浏览代码

optimized virtual using only underlying dynobj when necessary

Nicolas Cannasse 9 年之前
父节点
当前提交
484c0b72dd
共有 10 个文件被更改,包括 177 次插入37 次删除
  1. 16 2
      src/alloc.c
  2. 17 9
      src/hl.h
  3. 0 4
      src/hlc.h
  4. 2 2
      src/std/array.c
  5. 29 1
      src/std/buffer.c
  6. 1 1
      src/std/bytes.c
  7. 1 0
      src/std/cast.c
  8. 9 4
      src/std/maps.c
  9. 100 12
      src/std/obj.c
  10. 2 2
      src/std/types.c

+ 16 - 2
src/alloc.c

@@ -126,7 +126,7 @@ vdynamic *hl_alloc_dynamic( hl_type *t ) {
 	return d;
 }
 
-vobj *hl_alloc_obj( hl_type *t ) {
+vdynamic *hl_alloc_obj( hl_type *t ) {
 	vobj *o;
 	int size;
 	hl_runtime_obj *rt = t->obj->rt;
@@ -136,7 +136,7 @@ vobj *hl_alloc_obj( hl_type *t ) {
 	o = (vobj*)hl_gc_alloc(size);
 	memset(o,0,size);
 	o->t = t;
-	return o;
+	return (vdynamic*)o;
 }
 
 vdynobj *hl_alloc_dynobj() {
@@ -148,3 +148,17 @@ vdynobj *hl_alloc_dynobj() {
 	o->virtuals = NULL;
 	return o;
 }
+
+vvirtual *hl_alloc_virtual( hl_type *t ) {
+	vvirtual *v = (vvirtual*)hl_gc_alloc(t->virt->dataSize + sizeof(vvirtual) + sizeof(void*) * t->virt->nfields);
+	void **fields = (void**)(v + 1);
+	char *vdata = (char*)(fields + t->virt->nfields);
+	int i;
+	v->t = t;
+	v->value = NULL;
+	v->next = NULL;
+	for(i=0;i<t->virt->nfields;i++)
+		fields[i] = (char*)v + t->virt->indexes[i];
+	memset(vdata,0,t->virt->dataSize);
+	return v;
+}

+ 17 - 9
src/hl.h

@@ -54,7 +54,11 @@
 #	define HL_CYGWIN
 #endif
 
-#if defined(_MSC_VER)
+#if defined(__llvm__)
+#	define HL_LLVM
+#endif
+
+#if defined(_MSC_VER) && !defined(HL_LLVM)
 #	define HL_VCC
 #	pragma warning(disable:4996) // remove deprecated C API usage warnings
 #	pragma warning(disable:4055) // void* - to - function cast
@@ -127,7 +131,7 @@ typedef long long int64;
 
 // -------------- UNICODE -----------------------------------
 
-#ifdef HL_WIN
+#if defined(HL_WIN) && !defined(HL_LLVM)
 #	include <windows.h>
 #	include <wchar.h>
 typedef wchar_t	uchar;
@@ -191,6 +195,7 @@ typedef struct hl_type hl_type;
 typedef struct hl_runtime_obj hl_runtime_obj;
 typedef struct hl_alloc_block hl_alloc_block;
 typedef struct { hl_alloc_block *cur; } hl_alloc;
+typedef struct _hl_field_lookup hl_field_lookup;
 
 typedef struct {
 	hl_alloc alloc;
@@ -242,11 +247,12 @@ typedef struct {
 } hl_type_obj;
 
 typedef struct {
-	int nfields;
-#	ifdef HL_64
-	int __pad;
-#	endif
 	hl_obj_field *fields;
+	int nfields;
+	// runtime
+	int dataSize;
+	int *indexes;
+	hl_field_lookup *lookup;
 } hl_type_virtual;
 
 typedef struct {
@@ -337,11 +343,11 @@ typedef struct {
 	vclosure *wrappedFun;
 } vclosure_wrapper;
 
-typedef struct {
+struct _hl_field_lookup {
 	hl_type *t;
 	int hashed_name;
 	int field_index; // negative or zero : index in methods
-} hl_field_lookup;
+};
 
 struct hl_runtime_obj {
 	hl_type *t;
@@ -398,10 +404,12 @@ bool hl_safe_cast( hl_type *t, hl_type *to );
 
 varray *hl_alloc_array( hl_type *t, int size );
 vdynamic *hl_alloc_dynamic( hl_type *t );
-vobj *hl_alloc_obj( hl_type *t );
+vdynamic *hl_alloc_obj( hl_type *t );
+vvirtual *hl_alloc_virtual( hl_type *t );
 vdynobj *hl_alloc_dynobj();
 vbyte *hl_alloc_bytes( int size );
 vbyte *hl_copy_bytes( vbyte *byte, int size );
+vdynamic *hl_virtual_make_value( vvirtual *v );
 
 int hl_hash( vbyte *name );
 int hl_hash_gen( const uchar *name, bool cache_name );

+ 0 - 4
src/hlc.h

@@ -58,10 +58,6 @@ static void hl_null_access() {
 	hl_error_msg(USTR("Null access"));
 }
 
-static vdynamic *hl_oalloc( hl_type *t ) {
-	return (vdynamic*)hl_alloc_obj(t);
-}
-
 extern vdynamic *hl_call_method( vdynamic *c, varray *args );
 
 #define HLC_DYN_MAX_ARGS 9

+ 2 - 2
src/std/array.c

@@ -31,11 +31,11 @@ HL_PRIM varray *hl_alloc_array( hl_type *at, int size ) {
 	return a;
 }
 
-HL_PRIM void hl_ablit( varray *dst, int dpos, varray *src, int spos, int len ) {
+HL_PRIM void hl_array_blit( varray *dst, int dpos, varray *src, int spos, int len ) {
 	memcpy( hl_aptr(dst,void*) + dpos, hl_aptr(src,void*) + spos, len * sizeof(void*)); 
 }
 
-HL_PRIM hl_type *hl_atype( varray *a ) {
+HL_PRIM hl_type *hl_array_type( varray *a ) {
 	return a->at;
 }
 

+ 29 - 1
src/std/buffer.c

@@ -257,7 +257,35 @@ static void hl_buffer_rec( hl_buffer *b, vdynamic *v, vlist *stack ) {
 		hl_buffer_str_sub(b, USTR("ref"), 3);
 		break;
 	case HVIRTUAL:
-		hl_buffer_rec(b, ((vvirtual*)v)->value, stack);
+		{
+			vvirtual *vv = (vvirtual*)v;
+			int i;
+			vlist l;
+			vlist *vtmp = stack;
+			hl_field_lookup *f;
+			if( vv->value ) {
+				hl_buffer_rec(b, vv->value, stack);
+				return;
+			}
+			while( vtmp != NULL ) {
+				if( vtmp->v == v ) {
+					hl_buffer_str_sub(b,USTR("..."),3);
+					return;
+				}
+				vtmp = vtmp->next;
+			}
+			l.v = v;
+			l.next = stack;
+			hl_buffer_char(b, '{');
+			for(i=0;i<vv->t->virt->nfields;i++) {
+				hl_field_lookup *f = vv->t->virt->lookup + i;
+				if( i ) hl_buffer_str_sub(b,USTR(", "),2);
+				hl_buffer_str(b,hl_field_name(f->hashed_name));
+				hl_buffer_str_sub(b,USTR(" : "),3);
+				hl_buffer_addr(b, (char*)v + vv->t->virt->indexes[f->field_index], f->t, &l);
+			}
+			hl_buffer_char(b, '}');
+		}
 		break;
 	case HDYNOBJ:
 		{

+ 1 - 1
src/std/bytes.c

@@ -31,7 +31,7 @@ HL_PRIM vbyte *hl_copy_bytes( vbyte *ptr, int size ) {
 	return b;
 }
 
-HL_PRIM void hl_bblit( char *dst, int dpos, char *src, int spos, int len ) {
+HL_PRIM void hl_bytes_blit( char *dst, int dpos, char *src, int spos, int len ) {
 	memcpy(dst + dpos,src+spos,len);
 }
 

+ 1 - 0
src/std/cast.c

@@ -154,6 +154,7 @@ void *hl_dyn_castp( void *data, hl_type *t, hl_type *to ) {
 	case TK2(HVIRTUAL,HOBJ):
 		{
 			vvirtual *v = *(vvirtual**)data;
+			if( v->value == NULL ) break;
 			return hl_dyn_castp( &v->value, v->value->t, to);
 		}
 	case TK2(HOBJ,HDYN):

+ 9 - 4
src/std/maps.c

@@ -558,22 +558,27 @@ static void hl_hogrow( hl_obj_map *m ) {
 	}
 }
 
+static vdynamic *no_virtual( vdynamic *k ) {
+	return k && k->t->kind == HVIRTUAL ? hl_virtual_make_value((vvirtual*)k) : k;
+}
+
 HL_PRIM void hl_hoset( hl_obj_map *m, vdynamic *key, vdynamic *value ) {
-	if( hl_hoadd(m,key,value) && m->nentries > m->ncells * H_CELL_SIZE * 2 )
+	if( hl_hoadd(m,no_virtual(key),value) && m->nentries > m->ncells * H_CELL_SIZE * 2 )
 		hl_hogrow(m);
 }
 
 HL_PRIM bool hl_hoexists( hl_obj_map *m, vdynamic *key ) {
-	return hl_hofind(m,key) != NULL;
+	return hl_hofind(m,no_virtual(key)) != NULL;
 }
 
 HL_PRIM vdynamic* hl_hoget( hl_obj_map *m, vdynamic *key ) {
-	vdynamic **v = hl_hofind(m,key);
+	vdynamic **v = hl_hofind(m,no_virtual(key));
 	if( v == NULL ) return NULL;
 	return *v;
 }
 
-HL_PRIM bool hl_horemove( hl_obj_map *m, vdynamic *key ) {
+HL_PRIM bool hl_horemove( hl_obj_map *m, vdynamic *_key ) {
+	vdynamic *key = no_virtual(_key);
 	int hash = (int)(int_val)key;
 	int ckey = ((unsigned)hash) % ((unsigned)m->ncells);
 	hl_obj_cell *c = m->cells[ckey];

+ 100 - 12
src/std/obj.c

@@ -249,12 +249,44 @@ hl_runtime_obj *hl_get_obj_proto( hl_type *ot ) {
 
 void hl_init_virtual( hl_type *vt, hl_module_context *ctx ) {
 	int i;
+	int vsize = sizeof(vvirtual) + sizeof(void*) * vt->virt->nfields;
+	int size = vsize;
 	hl_field_lookup *l = (hl_field_lookup*)hl_malloc(&ctx->alloc,sizeof(hl_field_lookup)*vt->virt->nfields);
+	int *indexes = (int*)hl_malloc(&ctx->alloc,sizeof(int)*vt->virt->nfields);
 	for(i=0;i<vt->virt->nfields;i++) {
 		hl_obj_field *f = vt->virt->fields + i;
 		hl_lookup_insert(l,i,f->hashed_name,f->t,i);
+		size += hl_pad_size(size, f->t);
+		indexes[i] = size;
+		size += hl_type_size(f->t);
 	}
-	vt->vobj_proto = (void**)l;
+	vt->virt->lookup = l;
+	vt->virt->indexes = indexes;
+	vt->virt->dataSize = size - vsize;
+}
+
+vdynamic *hl_virtual_make_value( vvirtual *v ) {
+	vdynobj *o;
+	int i, nfields;
+	int hsize;
+	if( v->value )
+		return v->value;
+	nfields = v->t->virt->nfields;
+	hsize = sizeof(vvirtual) + nfields * sizeof(void*);
+	o = hl_alloc_dynobj();
+	o->fields_data = (char*)v + hsize;
+	o->nfields = nfields;
+	o->dataSize = v->t->virt->dataSize;
+	o->dproto = (vdynobj_proto*)hl_gc_alloc(sizeof(vdynobj_proto) + sizeof(hl_field_lookup) * (nfields - 1));
+	o->dproto->t = hlt_dynobj;
+	memcpy(&o->dproto->fields,v->t->virt->lookup,nfields * sizeof(hl_field_lookup));
+	for(i=0;i<nfields;i++) {
+		hl_field_lookup *f = (&o->dproto->fields) + i;
+		f->field_index = v->t->virt->indexes[f->field_index] - hsize;
+	}
+	o->virtuals = v;
+	v->value = (vdynamic*)o;
+	return v->value;
 }
 
 /**
@@ -264,7 +296,7 @@ vvirtual *hl_to_virtual( hl_type *vt, vdynamic *obj ) {
 	vvirtual *v = NULL;
 	if( obj == NULL ) return NULL;
 #ifdef _DEBUG
-	if( vt->vobj_proto == NULL ) hl_fatal("virtual not initialized");
+	if( vt->virt->lookup == NULL ) hl_fatal("virtual not initialized");
 #endif
 	switch( obj->t->kind ) {
 	case HOBJ:
@@ -314,7 +346,8 @@ vvirtual *hl_to_virtual( hl_type *vt, vdynamic *obj ) {
 		}
 		break;
 	case HVIRTUAL:
-		return hl_to_virtual(vt,((vvirtual*)obj)->value);
+		if( hl_safe_cast(obj->t, vt) ) return (vvirtual*)obj;
+		return hl_to_virtual(vt,hl_virtual_make_value((vvirtual*)obj));
 	default:
 		hl_fatal_fmt("Don't know how to virtual %d",obj->t->kind);
 	}
@@ -350,7 +383,7 @@ static hl_field_lookup *hl_dyn_alloc_field( vdynobj *o, int hfield, hl_type *t )
 	{
 		vvirtual *v = o->virtuals;
 		while( v ) {
-			hl_field_lookup *vf = hl_lookup_find((hl_field_lookup*)v->t->vobj_proto,v->t->virt->nfields,hfield);
+			hl_field_lookup *vf = hl_lookup_find(v->t->virt->lookup,v->t->virt->nfields,hfield);
 			int i;
 			for(i=0;i<v->t->virt->nfields;i++)
 				if( hl_vfields(v)[i] )
@@ -400,7 +433,7 @@ static void hl_dyn_change_field( vdynobj *o, hl_field_lookup *f, hl_type *t ) {
 	{
 		vvirtual *v = o->virtuals;
 		while( v ) {
-			hl_field_lookup *vf = hl_lookup_find((hl_field_lookup*)v->t->vobj_proto,v->t->virt->nfields,f->hashed_name);
+			hl_field_lookup *vf = hl_lookup_find(v->t->virt->lookup,v->t->virt->nfields,f->hashed_name);
 			int i;
 			if( newData != oldData )
 				for(i=0;i<v->t->virt->nfields;i++)
@@ -435,7 +468,16 @@ static void *hl_obj_lookup( vdynamic *d, int hfield, hl_type **t ) {
 		}
 		break;
 	case HVIRTUAL:
-		return hl_obj_lookup(((vvirtual*)d)->value, hfield, t);
+		{
+			vdynamic *v = ((vvirtual*)d)->value;
+			hl_field_lookup *f;
+			if( v )
+				return hl_obj_lookup(v, hfield, t);
+			f = hl_lookup_find(d->t->virt->lookup,d->t->virt->nfields,hfield);
+			if( f == NULL ) return NULL;
+			*t = f->t;
+			return (char*)d + d->t->virt->indexes[f->field_index];
+		}
 	default:
 		hl_error("Invalid field access");
 		break;
@@ -460,7 +502,11 @@ static vdynamic *hl_obj_lookup_extra( vdynamic *d, int hfield ) {
 		}
 		break;
 	case HVIRTUAL:
-		return hl_obj_lookup_extra(((vvirtual*)d)->value, hfield);
+		{
+			vdynamic *v = ((vvirtual*)d)->value;
+			if( v ) return hl_obj_lookup_extra(v, hfield);
+		}
+		break;
 	default:
 		break;
 	}
@@ -534,11 +580,20 @@ static void *hl_obj_lookup_set( vdynamic *d, int hfield, hl_type *t, hl_type **f
 			hl_field_lookup *f = obj_resolve_field(d->t->obj,hfield);
 			if( f == NULL || f->field_index < 0 ) hl_error_msg(USTR("%s does not have field %s"),d->t->obj->name,hl_field_name(hfield));
 			*ft = f->t;
-			return (char*)d+f->field_index;
+			return (char*)d + f->field_index;
 		}
 		break;
 	case HVIRTUAL:
-		return hl_obj_lookup_set(((vvirtual*)d)->value, hfield, t, ft);
+		{
+			vvirtual *v = (vvirtual*)d;
+			hl_field_lookup *f;
+			if( v->value ) return hl_obj_lookup_set(v->value, hfield, t, ft);
+			f = hl_lookup_find(v->t->virt->lookup,v->t->virt->nfields,hfield);
+			if( f == NULL || !hl_safe_cast(t,f->t) )
+				return hl_obj_lookup_set(hl_virtual_make_value(v), hfield, t, ft);
+			*ft = f->t;
+			return (char*)v + v->t->virt->indexes[f->field_index];
+		}
 	default:
 		hl_error("Invalid field access");
 		break;
@@ -682,7 +737,11 @@ HL_PRIM bool hl_obj_has_field( vdynamic *obj, int hfield ) {
 		}
 		break;
 	case HVIRTUAL:
-		return hl_obj_has_field(((vvirtual*)obj)->value,hfield);
+		{
+			vvirtual *v = (vvirtual*)obj;
+			if( v->value ) return hl_obj_has_field(v->value,hfield);
+			return hl_lookup_find(v->t->virt->lookup,v->t->virt->nfields,hfield) != NULL;
+		}
 	default:
 		break;
 	}
@@ -702,7 +761,7 @@ HL_PRIM bool hl_obj_delete_field( vdynamic *obj, int hfield ) {
 			{
 				vvirtual *v = d->virtuals;
 				while( v ) {
-					hl_field_lookup *vf = hl_lookup_find((hl_field_lookup*)v->t->vobj_proto,v->t->virt->nfields,hfield);
+					hl_field_lookup *vf = hl_lookup_find(v->t->virt->lookup,v->t->virt->nfields,hfield);
 					if( vf )
 						hl_vfields(v)[vf->field_index] = NULL;
 					v = v->next;
@@ -712,7 +771,12 @@ HL_PRIM bool hl_obj_delete_field( vdynamic *obj, int hfield ) {
 		}
 		break;
 	case HVIRTUAL:
-		return hl_obj_delete_field(((vvirtual*)obj)->value,hfield);
+		{
+			vvirtual *v = (vvirtual*)obj;
+			if( v->value ) return hl_obj_delete_field(v->value,hfield);
+			if( hl_lookup_find(v->t->virt->lookup,v->t->virt->nfields,hfield) == NULL ) return false;
+			return hl_obj_delete_field(hl_virtual_make_value(v),hfield);
+		}
 	default:
 		break;
 	}
@@ -747,6 +811,16 @@ HL_PRIM varray *hl_obj_fields( vdynamic *obj ) {
 			}
 		}
 		break;
+	case HVIRTUAL:
+		{
+			vvirtual *v = (vvirtual*)obj;
+			int i;
+			if( v->value ) return hl_obj_fields(v->value);
+			a = hl_alloc_array(&hlt_bytes,v->t->virt->nfields);
+			for(i=0;i<v->t->virt->nfields;i++)
+				hl_aptr(a,vbyte*)[i] = (vbyte*)v->t->virt->fields[i].name;
+		}
+		break;
 	default:
 		break;
 	}
@@ -772,8 +846,22 @@ HL_PRIM vdynamic *hl_obj_copy( vdynamic *obj ) {
 			return (vdynamic*)c;
 		}
 		break;
+	case HVIRTUAL:
+		{
+			vvirtual *v = (vvirtual*)obj;
+			vvirtual *v2;
+			if( v->value )
+				return hl_obj_copy(v->value);
+			v2 = hl_alloc_virtual(v->t);
+			memcpy((void**)(v2 + 1) + v->t->virt->nfields * sizeof(void*), (void**)(v + 1) + v->t->virt->nfields * sizeof(void*), v->t->virt->dataSize);
+			return (vdynamic*)v2;
+		}
 	default:
 		break;
 	}
 	return NULL;
 }
+
+HL_PRIM vdynamic *hl_get_virtual_value( vdynamic *v ) {
+	return ((vvirtual*)v)->value;
+}

+ 2 - 2
src/std/types.c

@@ -146,7 +146,7 @@ bool hl_is_dynamic( hl_type *t ) {
 bool hl_safe_cast( hl_type *t, hl_type *to ) {
 	if( t == to )
 		return true;
-	if( to->kind == HDYN && t->kind != HVIRTUAL )
+	if( to->kind == HDYN )
 		return hl_is_dynamic(t);
 	if( t->kind != to->kind )
 		return false;
@@ -389,7 +389,7 @@ bool hl_type_enum_eq( vdynamic *a, vdynamic *b ) {
 	return true;
 }
 
-HL_PRIM vdynamic *hl_ealloc( hl_type *t, int index, varray *args ) {
+HL_PRIM vdynamic *hl_alloc_enum( hl_type *t, int index, varray *args ) {
 	hl_enum_construct *c = t->tenum->constructs + index;
 	venum *e;
 	vdynamic *v;