view runtime/object.c @ 75:0083b2f7b3c7

Partially working implementation of List. Modified build scripts to allow use of other compilers. Fixed some bugs involving method implementations on different types returning different numbers of outputs. Added Fold to the 'builtins' in the comipler.
author Mike Pavone <pavone@retrodev.com>
date Tue, 06 Jul 2010 07:52:59 -0400
parents 04baa003de5a
children a68e6828d896
line wrap: on
line source

#include "object.h"
#include "builtin.h"
#include <stdlib.h>
#include <string.h>
#include <stdio.h>
#include "fixed_alloc.h"

blueprint ** registered_types = NULL;
uint32_t max_registered_type = 0;
uint32_t type_storage = 0;

mem_manager * manager = NULL;
/*

returntype call_method(uint32_t methodid, calldata * params)
{
	int i;
	blueprint * bp = get_blueprint(params->params[0]);
	if(methodid >= bp->first_methodid && methodid < bp->last_methodid && bp->method_lookup[methodid - bp->first_methodid])
	{
		params->tail_func =  bp->method_lookup[methodid - bp->first_methodid];
		return TAIL_RETURN;
	} else {
		if(METHOD_MISSING >= bp->first_methodid && METHOD_MISSING < bp->last_methodid && bp->method_lookup[METHOD_MISSING - bp->first_methodid])
		{
			params->tail_func = bp->method_lookup[METHOD_MISSING - bp->first_methodid];
			return TAIL_RETURN;
		} else {
			//TODO: Add useful info to exception
			for(i = 0; i < params->num_params; ++i)
				release_ref(params->params[i]);
			params->params[0] = new_object(TYPE_METHODMISSINGEXCEPTION);
			return EXCEPTION_RETURN;
		}
	}
}

returntype set_field(uint32_t setfieldid, calldata * params)
{
	int i;
	blueprint * bp = get_blueprint(params->params[0]);
	if(setfieldid >= bp->first_setfieldid && setfieldid < bp->last_setfieldid && bp->setter_lookup[setfieldid - bp->first_setfieldid])
	{
		params->tail_func =  bp->setter_lookup[setfieldid - bp->first_setfieldid];
		return TAIL_RETURN;
	} else {
		if(METHOD_SETFIELDMISSING >= bp->first_setfieldid && METHOD_SETFIELDMISSING < bp->last_setfieldid && bp->method_lookup[METHOD_SETFIELDMISSING - bp->first_methodid])
		{
			params->tail_func = bp->method_lookup[METHOD_SETFIELDMISSING - bp->first_methodid];
			params->original_methodid = setfieldid;
			return TAIL_RETURN;
		} else {
			//TODO: Add useful info to exception
			for(i = 0; i < params->num_params; ++i)
				release_ref(params->params[i]);
			params->params[0] = new_object(TYPE_FIELDMISSINGEXCEPTION);
			return EXCEPTION_RETURN;
		}
	}
}


returntype get_field(uint32_t getfieldid, calldata * params)
{
	int i;
	blueprint * bp = get_blueprint(params->params[0]);
	if(getfieldid >= bp->first_getfieldid && getfieldid < bp->last_getfieldid && bp->getter_lookup[getfieldid - bp->first_getfieldid])
	{
		params->tail_func =  bp->getter_lookup[getfieldid - bp->first_getfieldid];
		return TAIL_RETURN;
	} else {
		if(METHOD_GETFIELDMISSING >= bp->first_getfieldid && METHOD_GETFIELDMISSING < bp->last_getfieldid && bp->method_lookup[METHOD_GETFIELDMISSING - bp->first_methodid])
		{
			params->tail_func = bp->method_lookup[METHOD_GETFIELDMISSING - bp->first_methodid];
			params->original_methodid = getfieldid;
			return TAIL_RETURN;
		} else {
			//TODO: Add useful info to exception
			for(i = 0; i < params->num_params; ++i)
				release_ref(params->params[i]);
			params->params[0] = new_object(TYPE_FIELDMISSINGEXCEPTION);
			return EXCEPTION_RETURN;
		}
	}
}

returntype convert_to(uint32_t convertto, calldata * params)
{
	int i;
	blueprint * bp = get_blueprint(params->params[0]);
	if(convertto >= bp->first_convertto && convertto < bp->last_convertto && bp->convert_to[convertto])
	{
		params->tail_func =  bp->convert_to[convertto - bp->first_convertto];
		return TAIL_RETURN;
	} else {
		return NO_CONVERSION;
	}
}

returntype convert_from(uint32_t convertfrom, calldata * params)
{
	int i;
	blueprint * bp = registered_types[convertfrom];
	if(convertfrom >= bp->first_convertfrom && convertfrom < bp->last_convertfrom && bp->convert_from[convertfrom])
	{
		params->tail_func =  bp->convert_from[convertfrom - bp->first_convertfrom];
		return TAIL_RETURN;
	} else {
		return NO_CONVERSION;
	}
}

returntype coerce_value(uint32_t type, calldata * params)
{
	int i;
	blueprint * bp = get_blueprint(params->params[0]);
	if(bp == registered_types[type])
		return NORMAL_RETURN;
	if(convert_to(type, params) == TAIL_RETURN)
		return TAIL_RETURN;
	if(convert_from(type, params) == TAIL_RETURN)
		return TAIL_RETURN;
	//TODO: Add useful info to exception
	for(i = 0; i < params->num_params; ++i)
		release_ref(params->params[i]);
	params->params[0] = new_object(TYPE_WRONGTYPEEXCEPTION);
	return EXCEPTION_RETURN;
}*/

object * alloc_object(blueprint * bp)
{
	return falloc(bp->boxed_size, manager);
	//return malloc(bp->boxed_size);
}

void dealloc_object(blueprint * bp, object * obj)
{
	ffree(obj, bp->boxed_size, manager);
}

object * new_object(uint32_t type)
{
	blueprint * bp;
	object * ret;
	if(type >= max_registered_type || !registered_types[type])
		return NULL;
	bp = registered_types[type];
	return new_object_bp(bp);
}

object * new_object_bp(blueprint * bp)
{
	object * ret;
	ret = alloc_object(bp);
	if(ret)
	{
		ret->bprint = bp;
		rh_atomic_set(ret, refcount, 1);
		memset(((char *)ret) + sizeof(object), '\0', bp->size);
		bp->init(ret);
	} else {
		fprintf(stderr, "Could not allocate new object with size %d\n", bp->boxed_size);
	}
	return ret;
}

multisize * new_multisize(uint32_t type, uint32_t size)
{
	blueprint *bp;
	multisize * ret;
	if(type >= max_registered_type || !registered_types[type])
		return NULL;
	ret = falloc(sizeof(multisize) + size, manager);
	if(ret)
	{
		bp = registered_types[type];
		ret->base.bprint = bp;
		ret->size = size;
		rh_atomic_set(&(ret->base), refcount, 1);
		memset(((char *)ret) + sizeof(multisize), '\0', size);
		bp->init((object *)ret);
	}
	return ret; 
}

object * copy_object(object * tocopy)
{
	object * copy;
	multisize * mcopy, *mtocopy;
	blueprint * bp;
	if(rh_atomic_get(tocopy, refcount) == 1)
		return tocopy;
	bp = get_blueprint(tocopy);
	if(bp->size < 0) {
		mtocopy = (multisize *)tocopy;
		mcopy = falloc(sizeof(multisize) + mtocopy->size, manager);
		mcopy->size = mtocopy->size;
		memcpy(((char *)mcopy)+sizeof(multisize), ((char *)mtocopy)+sizeof(multisize), mtocopy->size);
		copy = (object *)mcopy;
	} else {
		copy = alloc_object(bp);
		memcpy(((char *)copy) + sizeof(object), ((char *)tocopy)+sizeof(object), bp->size);
	}
	copy->bprint = bp;
	rh_atomic_set(copy, refcount, 1);
	bp->copy(copy);
	release_ref(tocopy);
	return copy;
}

object * naked_to_boxed(uint32_t type, void * rawdata)
{
	object * dest;
	blueprint * bp = get_blueprint_byid(type);
	if(!bp->boxed_size)
		return NULL; //We don't know how big a naked multi-size object is so we can't do anything with it
	dest = alloc_object(bp);
	memcpy(((char *)dest) + sizeof(object), rawdata, bp->size);
	dest->bprint = bp;
	rh_atomic_set(dest, refcount, 1);
	bp->copy(dest);
	return dest;
}

void boxed_to_naked(object * src, void * dest)
{
	blueprint * bp = get_blueprint(src);
	if(!bp->boxed_size)
		return; //We don't know how big a naked multi-size object is so we can't do anything with it
	memcpy(dest, ((char *)src) + sizeof(object), bp->size);
	bp->copy(src);
}

void release_ref(object * obj)
{
	if(rh_atomic_sub_testzero(obj, refcount, 1))
		get_blueprint(obj)->free(obj);
}

void check_type_storage(type)
{
	uint32_t type_storage_temp;
	blueprint ** temp;
	if(type >= type_storage)
		if(type_storage)
		{
			type_storage_temp = (type + (type_storage >> 1));
			temp = realloc(registered_types, type_storage_temp * sizeof(blueprint *));
			if(temp)
			{
				registered_types = temp;
				memset(registered_types + type_storage, '\0', (type_storage_temp - type_storage) * sizeof(blueprint *));
				type_storage = type_storage_temp;
			}
			else
			{
				free(registered_types);
				fprintf(stderr, "Couldn't allocate %d bytes for type storage array\n", type_storage_temp * sizeof(blueprint *));
				exit(-1);
			}
		} else {
			
			if(type < INITIAL_TYPE_STORAGE)
				type_storage =INITIAL_TYPE_STORAGE;
			else
				type_storage = type + 8;
			registered_types = malloc(type_storage * sizeof(blueprint *));
			if(registered_types)
				memset(registered_types, '\0', type_storage * sizeof(blueprint *));
			else
			{
				fprintf(stderr, "Couldn't allocate %d bytes for type storage array\n", type_storage * sizeof(blueprint *));
				exit(-1);
			}
				
		}
}

void default_action(object * obj)
{
}

void normal_free(object * obj)
{
	blueprint * bp = get_blueprint(obj);
	if(bp->cleanup)
		bp->cleanup(obj);
	ffree(obj, bp->boxed_size, manager);
}

void multi_free(object * obj)
{
	multisize * multi = (multisize *)obj;
	blueprint * bp = get_blueprint(obj);
	if(bp->cleanup)
		bp->cleanup(obj);
	ffree(multi, sizeof(multisize) + multi->size, manager);
}

blueprint * new_blueprint(uint32_t type, int32_t size, special_func init, special_func copy, special_func cleanup)
{
	blueprint * bp = malloc(sizeof(blueprint));
	//dirty hack!, move elsewhere
	if (!manager) {
		fixed_alloc_init();
		manager = new_mem_manager();
	}
	if(bp)
	{
		bp->size = size;
		bp->boxed_size = size >= 0 ? size + sizeof(object) : 0;
		bp->method_lookup = bp->getter_lookup = bp->setter_lookup = bp->convert_to = bp->convert_from = NULL;
		bp->type_id = type;
		bp->init = init ? init : default_action;
		bp->copy = copy ? copy : default_action;
		bp->cleanup = cleanup ? cleanup : default_action;
		bp->free = size >= 0 ? normal_free : multi_free;
		bp->first_methodid = bp->last_methodid = bp->first_getfieldid = bp->last_getfieldid = bp->first_setfieldid = bp->last_setfieldid = bp->first_convertto = bp->last_convertto = bp->first_convertfrom = bp->last_convertfrom = 0;
		//TODO: Handle names
		bp->name = NULL;
	}
	return bp;
}

blueprint * register_type_byid(uint32_t type, int32_t size, special_func init, special_func copy, special_func cleanup)
{
	check_type_storage(type);
	if(registered_types[type])
		return registered_types[type];
	registered_types[type] = new_blueprint(type, size, init, copy, cleanup);
	if(!registered_types[type])
	{
		fputs("Couldn't allocate new object blueprint\n", stderr);
		exit(-1);
	}
	if(type >= max_registered_type)
		max_registered_type = type + 1;
	return registered_types[type];
}

void add_method(blueprint * bp, uint32_t methodid, rhope_func impl)
{
	rhope_func * temp;
	if(methodid < 1) {
		fputs("Attempt to add a method with an ID < 1\n", stderr);
		exit(-1);
	}
	if (!bp->method_lookup)
	{
		bp->method_lookup = malloc(sizeof(rhope_func) * INITIAL_METHOD_LOOKUP);
		if(!bp->method_lookup) {
			fprintf(stderr, "Couldn't allocate %d bytes for method lookup table\n", sizeof(rhope_func) * INITIAL_METHOD_LOOKUP);
			exit(-1);
		}
		if(BELOW_INITIAL_METHOD > methodid) {
			bp->first_methodid = 1;
			bp->last_methodid = 1+INITIAL_METHOD_LOOKUP;
		} else {
			bp->first_methodid = methodid - BELOW_INITIAL_METHOD;
			bp->last_methodid = bp->first_methodid + INITIAL_METHOD_LOOKUP;
		}
		memset(bp->method_lookup, '\0', sizeof(rhope_func) * INITIAL_METHOD_LOOKUP);
	} else {
		if (methodid < bp->first_methodid) {
			temp = bp->method_lookup;
			//Note: if this gets changed to generating an exception on failure, we need to restore the original buffer
			bp->method_lookup = malloc(sizeof(rhope_func) * (bp->last_methodid-methodid));
			if(!bp->method_lookup) {
				fprintf(stderr, "Couldn't allocate %d bytes for method lookup table\n", sizeof(rhope_func) * (bp->last_methodid-methodid));
				exit(-1);
			}
			memset(bp->method_lookup, '\0', (bp->first_methodid-methodid) * sizeof(rhope_func));
			memcpy(bp->method_lookup + bp->first_methodid-methodid, temp, (bp->last_methodid-bp->first_methodid)*sizeof(rhope_func));
			free(temp);
			bp->first_methodid = methodid;
		} else if(methodid >= bp->last_methodid) {
			//Note: if this gets changed to generating an exception on failure, we need to restore the original buffer
			bp->method_lookup = realloc(bp->method_lookup, (methodid+1-bp->first_methodid) * sizeof(rhope_func));
			if(!bp->method_lookup) {
				fprintf(stderr, "Couldn't resize method lookup table to %d bytes\n", (methodid+1-bp->first_methodid) * sizeof(rhope_func));
				exit(-1);
			}
			memset(bp->method_lookup+bp->last_methodid, '\0', (methodid+1)-bp->last_methodid);
			bp->last_methodid = methodid+1;
		}
	}
	bp->method_lookup[methodid-bp->first_methodid] = impl;
}

void add_getter(blueprint * bp, uint32_t getfieldid, rhope_func impl)
{
	rhope_func * temp;
	if(getfieldid < 1) {
		fputs("Attempt to add a method with an ID < 1\n", stderr);
		exit(-1);
	}
	if (!bp->getter_lookup)
	{
		bp->getter_lookup = malloc(sizeof(rhope_func) * INITIAL_METHOD_LOOKUP);
		if(!bp->getter_lookup) {
			fprintf(stderr, "Couldn't allocate %d bytes for getter lookup table\n", sizeof(rhope_func) * INITIAL_METHOD_LOOKUP);
			exit(-1);
		}
		if(BELOW_INITIAL_METHOD > getfieldid) {
			bp->first_getfieldid = 1;
			bp->last_getfieldid = 1+INITIAL_METHOD_LOOKUP;
		} else {
			bp->first_getfieldid = getfieldid - BELOW_INITIAL_METHOD;
			bp->last_getfieldid = bp->first_getfieldid + INITIAL_METHOD_LOOKUP;
		}
		memset(bp->getter_lookup, '\0', sizeof(rhope_func) * INITIAL_METHOD_LOOKUP);
	} else {
		if (getfieldid < bp->first_getfieldid) {
			temp = bp->getter_lookup;
			//Note: if this gets changed to generating an exception on failure, we need to restore the original buffer
			bp->getter_lookup = malloc(sizeof(rhope_func) * (bp->last_getfieldid-getfieldid));
			if(!bp->getter_lookup) {
				fprintf(stderr, "Couldn't allocate %d bytes for getter lookup table\n", sizeof(rhope_func) * (bp->last_getfieldid-getfieldid));
				exit(-1);
			}
			memset(bp->getter_lookup, '\0', (bp->first_getfieldid-getfieldid) * sizeof(rhope_func));
			memcpy(bp->getter_lookup + bp->first_getfieldid-getfieldid, temp, (bp->last_getfieldid-bp->first_getfieldid)*sizeof(rhope_func));
			free(temp);
			bp->first_getfieldid = getfieldid;
		} else if(getfieldid >= bp->last_getfieldid) {
			//Note: if this gets changed to generating an exception on failure, we need to restore the original buffer
			bp->getter_lookup = realloc(bp->getter_lookup, (getfieldid+1-bp->first_getfieldid) * sizeof(rhope_func));
			if(!bp->getter_lookup) {
				fprintf(stderr, "Couldn't resize getter lookup table to %d bytes\n", (getfieldid+1-bp->first_getfieldid) * sizeof(rhope_func));
				exit(-1);
			}
			memset(bp->getter_lookup+bp->last_getfieldid, '\0', (getfieldid+1)-bp->last_getfieldid);
			bp->last_getfieldid = getfieldid+1;
		}
	}
	bp->getter_lookup[getfieldid-bp->first_getfieldid] = impl;
}

void add_setter(blueprint * bp, uint32_t setfieldid, rhope_func impl)
{
	rhope_func * temp;
	if(setfieldid < 1) {
		fputs("Attempt to add a method with an ID < 1\n", stderr);
		exit(-1);
	}
	if (!bp->setter_lookup)
	{
		bp->setter_lookup = malloc(sizeof(rhope_func) * INITIAL_METHOD_LOOKUP);
		if(!bp->setter_lookup) {
			fprintf(stderr, "Couldn't allocate %d bytes for setter lookup table\n", sizeof(rhope_func) * INITIAL_METHOD_LOOKUP);
			exit(-1);
		}
		if(BELOW_INITIAL_METHOD > setfieldid) {
			bp->first_setfieldid = 1;
			bp->last_setfieldid = 1+INITIAL_METHOD_LOOKUP;
		} else {
			bp->first_setfieldid = setfieldid - BELOW_INITIAL_METHOD;
			bp->last_setfieldid = bp->first_setfieldid + INITIAL_METHOD_LOOKUP;
		}
		memset(bp->setter_lookup, '\0', sizeof(rhope_func) * INITIAL_METHOD_LOOKUP);
	} else {
		if (setfieldid < bp->first_setfieldid) {
			temp = bp->setter_lookup;
			//Note: if this sets changed to generating an exception on failure, we need to restore the original buffer
			bp->setter_lookup = malloc(sizeof(rhope_func) * (bp->last_setfieldid-setfieldid));
			if(!bp->setter_lookup) {
				fprintf(stderr, "Couldn't allocate %d bytes for setter lookup table\n", sizeof(rhope_func) * (bp->last_setfieldid-setfieldid));
				exit(-1);
			}
			memset(bp->setter_lookup, '\0', (bp->first_setfieldid-setfieldid) * sizeof(rhope_func));
			memcpy(bp->setter_lookup + bp->first_setfieldid-setfieldid, temp, (bp->last_setfieldid-bp->first_setfieldid)*sizeof(rhope_func));
			free(temp);
			bp->first_setfieldid = setfieldid;
		} else if(setfieldid >= bp->last_setfieldid) {
			//Note: if this sets changed to generating an exception on failure, we need to restore the original buffer
			bp->setter_lookup = realloc(bp->setter_lookup, (setfieldid+1-bp->first_setfieldid) * sizeof(rhope_func));
			if(!bp->setter_lookup) {
				fprintf(stderr, "Couldn't resize setter lookup table to %d bytes\n", (setfieldid+1-bp->first_setfieldid) * sizeof(rhope_func));
				exit(-1);
			}
			memset(bp->setter_lookup+bp->last_setfieldid, '\0', (setfieldid+1)-bp->last_setfieldid);
			bp->last_setfieldid = setfieldid+1;
		}
	}
	bp->setter_lookup[setfieldid-bp->first_setfieldid] = impl;
}

blueprint * get_blueprint_byid(uint32_t type)
{
	if(type >= max_registered_type)
		return NULL;
	return registered_types[type];
}