فهرست منبع

added mem_compact

Nicolas Cannasse 3 سال پیش
والد
کامیت
5f0633b053
1فایلهای تغییر یافته به همراه385 افزوده شده و 0 حذف شده
  1. 385 0
      src/std/types.c

+ 385 - 0
src/std/types.c

@@ -576,3 +576,388 @@ DEFINE_PRIM(_BOOL, type_enum_eq, _DYN _DYN);
 DEFINE_PRIM(_DYN, alloc_enum_dyn, _TYPE _I32 _ARR _I32);
 DEFINE_PRIM(_ARR, enum_parameters, _DYN);
 DEFINE_PRIM(_BOOL, type_set_global, _TYPE _DYN);
+
+
+typedef struct {
+	char *buf;
+	int buf_pos;
+	int buf_size;
+	int *offsets;
+	int offsets_pos;
+	int offsets_size;
+	void **lookup;
+	int *lookup_index;
+	int lookup_pos;
+	int lookup_size;
+	int *remap_target;
+	int remap_pos;
+	int remap_size;
+	void **todos;
+	int todos_pos;
+	int todos_size;
+	int flags;
+} mem_context;
+
+#define compact_grow(buf,pos,size,req,type) \
+	if( ctx->pos + req > ctx->size ) { \
+		int nsize = ctx->size; \
+		if( nsize == 0 ) nsize = 256 /sizeof(type); \
+		while( nsize < ctx->pos + req ) nsize = (nsize * 3) / 2; \
+		type *nbuf = (type*)malloc(nsize * sizeof(type)); \
+		memcpy(nbuf,ctx->buf,ctx->pos * sizeof(type)); \
+		free(ctx->buf); \
+		ctx->buf = nbuf; \
+		ctx->size = nsize; \
+	}
+
+
+static void compact_write_mem( mem_context *ctx, void *mem, int size ) {
+	compact_grow(buf,buf_pos,buf_size,size,char);
+	memcpy(ctx->buf + ctx->buf_pos, mem, size);
+	ctx->buf_pos += size;
+}
+
+static void compact_write_ptr( mem_context *ctx, void *ptr ) {
+	compact_write_mem(ctx,&ptr,sizeof(void*));
+}
+
+static void compact_write_int( mem_context *ctx, int v ) {
+	compact_write_mem(ctx,&v,4);
+}
+
+static void compact_write_offset( mem_context *ctx, int position ) {
+	compact_grow(offsets,offsets_pos,offsets_size,1,int);
+	ctx->offsets[ctx->offsets_pos++] = ctx->buf_pos;
+	compact_write_ptr(ctx,(void*)(int_val)position);
+}
+
+static int compact_lookup_index( mem_context *ctx, void *addr ) {
+	int min = 0;
+	int max = ctx->lookup_pos;
+	while( min < max ) {
+		int mid = (min + max) >> 1;
+		void *a = ctx->lookup[mid];
+		if( a < addr ) min = mid + 1; else if( a > addr ) max = mid; else return mid;
+	}
+	return -1;
+}
+
+#define BYTE_MARK 0x40000000
+
+static int compact_lookup_ref( mem_context *ctx, void *addr, bool is_bytes ) {
+	int min = 0;
+	int max = ctx->lookup_pos;
+	while( min < max ) {
+		int mid = (min + max) >> 1;
+		void *a = ctx->lookup[mid];
+		if( a < addr ) min = mid + 1; else if( a > addr ) max = mid; else return ctx->remap_target[ctx->lookup_index[mid]&~BYTE_MARK];
+	}
+	if( ctx->lookup_pos == ctx->lookup_size ) {
+		int nsize = ctx->lookup_size == 0 ? 128 : (ctx->lookup_size * 3) / 2;
+		void **nlookup = (void**)malloc(nsize * sizeof(void*));
+		int *nindex = (int*)malloc(nsize * sizeof(int));
+		memcpy(nlookup,ctx->lookup,ctx->lookup_pos * sizeof(void*));
+		memcpy(nindex,ctx->lookup_index,ctx->lookup_pos * sizeof(int));
+		free(ctx->lookup);
+		free(ctx->lookup_index);
+		ctx->lookup = nlookup;
+		ctx->lookup_index = nindex;
+		ctx->lookup_size = nsize;
+	}
+	int pos = (min + max) >> 1;
+	memmove(ctx->lookup + pos + 1, ctx->lookup + pos, (ctx->lookup_pos - pos) * sizeof(void*));
+	memmove(ctx->lookup_index + pos + 1, ctx->lookup_index + pos, (ctx->lookup_pos - pos) * sizeof(int));
+	int id = ctx->lookup_pos++;
+	ctx->lookup[pos] = addr;
+	ctx->lookup_index[pos] = id | (is_bytes ? BYTE_MARK : 0);
+	compact_grow(todos,todos_pos,todos_size,1,void*);
+	ctx->todos[ctx->todos_pos++] = addr;
+	compact_grow(remap_target,remap_pos,remap_size,1,int);
+	int target = -id-1;
+	ctx->remap_target[ctx->remap_pos++] = target;
+	return target;
+}
+
+static void compact_write_ref( mem_context *ctx, void *ptr, bool is_bytes ) {
+	if( !ptr ) {
+		compact_write_ptr(ctx, NULL);
+		return;
+	}
+	int ref = compact_lookup_ref(ctx,ptr,is_bytes);
+	compact_write_offset(ctx, ref);
+}
+
+static void compact_write_data( mem_context *ctx, hl_type *t, void *addr ) {
+	if( hl_is_dynamic(t) ) {
+		vdynamic *v = *(vdynamic**)addr;
+		if( v == NULL || (v->t->kind == HENUM && v->t->tenum->constructs[((venum*)v)->index].nparams == 0) ) {
+			compact_write_ptr(ctx,v);
+			return;
+		}
+		compact_write_ref(ctx,v,false);
+		return;
+	}
+	switch( t->kind ) {
+	case HUI8:
+		compact_write_mem(ctx, addr, 1);
+		break;
+	case HUI16:
+		compact_write_mem(ctx, addr, 2);
+		break;
+	case HI32:
+	case HF32:
+		compact_write_mem(ctx, addr, 4);
+		break;
+	case HF64:
+	case HI64:
+		compact_write_mem(ctx, addr, 8);
+		break;
+	case HBOOL:
+		compact_write_mem(ctx, addr, sizeof(bool));
+		break;
+	case HBYTES:
+		{
+			void *bytes = *(void**)addr;
+			if( bytes == NULL || !hl_is_gc_ptr(bytes) ) {
+				compact_write_ptr(ctx, bytes);
+				break;
+			}
+			compact_write_ref(ctx, bytes, true);
+		}
+		break;
+	case HABSTRACT:
+		hl_error("Unsupported abstract %s", t->abs_name);
+		break;
+	default:
+		hl_error("Unsupported type %d", t->kind);
+		break;
+	}
+}
+
+static void compact_pad( mem_context *ctx, hl_type *t ) {
+	int sz = hl_pad_size(ctx->buf_pos,t);
+	ctx->buf_pos += sz;
+}
+
+static void compact_write_content( mem_context *ctx, vdynamic *d ) {
+	int i;
+	hl_type *t = d->t;
+	if( !hl_is_ptr(t) ) {
+		compact_write_ptr(ctx, t);
+		compact_write_mem(ctx,&d->v,hl_type_size(t));
+		return;
+	}
+	switch( t->kind ) {
+	case HOBJ: {
+		char *obj_data = (char*)d;
+		hl_runtime_obj *rt = hl_get_obj_rt(t);
+		compact_grow(buf,buf_pos,buf_size,rt->size,char);
+		memset(ctx->buf + ctx->buf_pos, 0xCD, rt->size);
+		int buf_start = ctx->buf_pos;
+		int fstart = rt->nfields;
+		compact_write_ptr(ctx,t);
+		while( t ) {
+			fstart -= t->obj->nfields;
+			for(i=0;i<t->obj->nfields;i++) {
+				int fid = i + fstart;
+				ctx->buf_pos = buf_start + rt->fields_indexes[fid];
+				compact_write_data(ctx, t->obj->fields[i].t, obj_data + rt->fields_indexes[fid]);
+			}
+			t = t->obj->super;
+		}
+		ctx->buf_pos = buf_start + rt->size;
+		break;
+	}
+	case HVIRTUAL: {
+		vvirtual *v = (vvirtual*)d;
+		int start = ctx->buf_pos;
+		compact_write_ptr(ctx, t);
+		if( ctx->flags & 4 )
+			compact_write_offset(ctx, start); // virtual self value
+		else if( ctx->flags & 2 )
+			compact_write_ptr(ctx, NULL); // optimize virtuals
+		else
+			compact_write_data(ctx, &hlt_dyn, &v->value);
+		compact_write_data(ctx, &hlt_dyn, &v->next);
+		if( !v->value || (ctx->flags&6) ) {
+			int target = ctx->buf_pos + t->virt->nfields * sizeof(void*);
+			for(i=0;i<t->virt->nfields;i++) {
+				hl_type *ft = t->virt->fields[i].t;
+				target += hl_pad_size(target, ft);
+				compact_write_offset(ctx, target);
+				target += hl_type_size(ft);
+			}
+			for(i=0;i<t->virt->nfields;i++) {
+				void *addr = ((void**)(v + 1))[i];
+				hl_type *ft = t->virt->fields[i].t;
+				compact_pad(ctx,ft);
+				if( !addr ) {
+					if( !hl_is_ptr(ft) ) hl_error("assert");
+					compact_write_ptr(ctx,NULL);
+				} else
+					compact_write_data(ctx,ft,addr);
+			}
+		} else {
+			vdynobj *obj = (vdynobj*)v->value;
+			if( obj->t->kind != HDYNOBJ ) hl_error("assert");
+			int todo_save = ctx->todos_pos;
+			for(i=0;i<t->virt->nfields;i++) {
+				void *addr = ((void**)(v + 1))[i];
+				compact_write_ref(ctx, addr, false);
+			}
+			ctx->todos_pos = todo_save;
+		}
+		break;
+	}
+	case HDYNOBJ: {
+		vdynobj *obj = (vdynobj*)d;
+		int lookup_data = ctx->buf_pos + sizeof(vdynobj);
+		int raw_data = lookup_data + obj->nfields * sizeof(hl_field_lookup);
+		int values_data = raw_data + obj->raw_size;
+		values_data += hl_pad_size(values_data,&hlt_dyn);
+
+		compact_write_ptr(ctx, t);
+		if( obj->lookup )
+			compact_write_offset(ctx, lookup_data);
+		else
+			compact_write_ptr(ctx, NULL);
+		if( obj->raw_data )
+			compact_write_offset(ctx, raw_data);
+		else
+			compact_write_ptr(ctx, NULL);
+		if( obj->values )
+			compact_write_offset(ctx, values_data);
+		else
+			compact_write_ptr(ctx, NULL);
+		compact_write_int(ctx,obj->nfields);
+		compact_write_int(ctx,obj->raw_size);
+		compact_write_int(ctx,obj->nvalues);
+#		ifdef HL_64
+		compact_write_int(ctx,0);
+#		endif
+		compact_write_ref(ctx,obj->virtuals,false);
+		if( obj->lookup )
+			compact_write_mem(ctx,obj->lookup,sizeof(hl_field_lookup) * obj->nfields);
+		if( obj->raw_data )
+			compact_write_mem(ctx,obj->raw_data,obj->raw_size);
+		if( obj->values ) {
+			compact_pad(ctx,&hlt_dyn);
+			for(i=0;i<obj->nvalues;i++) {
+				int j;
+				for(j=0;i<obj->nfields;j++) {
+					if( obj->lookup[j].field_index == i && hl_is_ptr(obj->lookup[j].t) ) {
+						compact_write_data(ctx, obj->lookup[j].t, obj->values + i);
+						break;
+					}
+				}
+			}
+		}
+		int save_pos = ctx->todos_pos;
+		for(i=0;i<obj->nfields;i++) {
+			hl_field_lookup *f = obj->lookup + i;
+			int idx = compact_lookup_ref(ctx, hl_is_ptr(f->t) ? (char*)(obj->values + f->field_index) : (char*)(obj->raw_data + f->field_index), false);
+			idx = -idx-1;
+			ctx->remap_target[idx] = hl_is_ptr(f->t) ? values_data + sizeof(void*)*f->field_index : raw_data + f->field_index;
+		}
+		ctx->todos_pos = save_pos;
+		break;
+	}
+	case HARRAY: {
+		varray *a = (varray*)d;
+		compact_write_ptr(ctx, a->t);
+		compact_write_ptr(ctx, a->at);
+		compact_write_int(ctx, a->size);
+		compact_write_int(ctx, 0);
+		char *array_data = (char*)(a + 1);
+		int stride = hl_type_size(a->at);
+		for(i=0;i<a->size;i++) {
+			compact_write_data(ctx,a->at, array_data + stride * i);
+		}
+		break;
+	}
+	case HENUM: {
+		venum *e = (venum*)d;
+		hl_enum_construct *c = &t->tenum->constructs[e->index];
+		int buf_start = ctx->buf_pos;
+		compact_write_ptr(ctx, e->t);
+		compact_write_int(ctx, e->index);
+		for(i=0;i<c->nparams;i++) {
+			compact_pad(ctx,c->params[i]);
+			compact_write_data(ctx,c->params[i],(char*)e+(ctx->buf_pos-buf_start));
+		}
+		break;
+	}
+	default:
+		hl_error("Unsupported type %d", t->kind);
+	}
+}
+
+HL_PRIM vdynamic *hl_mem_compact( vdynamic *d, varray *exclude, int flags, int *outCount ) {
+	mem_context _ctx;
+	mem_context *ctx = &_ctx;
+	int i;
+	int object_count = 0;
+	memset(ctx,0,sizeof(mem_context));
+	ctx->flags = flags;
+	compact_lookup_ref(ctx,d,false);
+	if( exclude ) {
+		for(i=0;i<exclude->size;i++) {
+			vdynamic *ptr = (vdynamic*)hl_aptr(exclude,void*)[i];
+			compact_lookup_ref(ctx,ptr,false);
+			ctx->todos_pos--;
+		}
+	}
+	while( ctx->todos_pos > 0 ) {
+		void *addr = ctx->todos[--ctx->todos_pos];
+		int pos = compact_lookup_index(ctx, addr);
+		int index = ctx->lookup_index[pos];
+		compact_pad(ctx, &hlt_dyn);
+		ctx->remap_target[index&~BYTE_MARK] = ctx->buf_pos;
+		if( index & BYTE_MARK ) {
+			int size = hl_gc_get_memsize(addr);
+			if( size < 0 ) hl_error("assert");
+			compact_write_mem(ctx, addr, size);
+		} else
+			compact_write_content(ctx, (vdynamic*)addr);
+		object_count++;
+	}
+	vbyte *data = NULL;
+#	ifdef HL_WIN
+	if( flags & 1 )
+		data = (vbyte*)VirtualAlloc(NULL,ctx->buf_pos,MEM_COMMIT|MEM_RESERVE,PAGE_READWRITE);
+#	endif
+	if( data == NULL )
+		data = hl_gc_alloc_noptr(ctx->buf_pos);
+	memcpy(data,ctx->buf,ctx->buf_pos);
+	int exclude_count = exclude ? exclude->size : 0;
+	for(i=0;i<ctx->offsets_pos;i++) {
+		int pos = ctx->offsets[i];
+		int target = *(int*)(data + pos);
+		if( target < 0 ) {
+			int eid = -target-1;
+			if( eid > 0 && eid <= exclude_count ) {
+				*(void**)(data+pos) = hl_aptr(exclude,void*)[eid-1];
+				continue;
+			}
+			target = ctx->remap_target[eid];
+		}
+		*(void**)(data+pos) = data + target;
+	}
+	free(ctx->buf);
+	free(ctx->offsets);
+	free(ctx->lookup);
+	free(ctx->lookup_index);
+	free(ctx->remap_target);
+	free(ctx->todos);
+#	ifdef HL_WIN
+	if( flags & 1 ) {
+		DWORD old = 0;
+		VirtualProtect(data,ctx->buf_pos,PAGE_READONLY,&old);
+	}
+#	endif
+	if( outCount )
+		*outCount = object_count;
+	return (vdynamic*)data;
+}
+
+DEFINE_PRIM(_DYN, mem_compact, _DYN _ARR _I32 _REF(_I32));