Mercurial > repos > rhope
view runtime/object.c @ 62:b218af069da7
merge
author | Mike Pavone <pavone@retrodev.com> |
---|---|
date | Sat, 10 Oct 2009 16:43:37 -0400 |
parents | d2f9b0a9403d 1b86a1ee500a |
children | 04baa003de5a |
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(multi) + multi->size, manager); } blueprint * new_blueprint(uint32_t type, uint32_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, uint32_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]; }