forked from LeenkxTeam/LNXSDK
1318 lines
37 KiB
C
1318 lines
37 KiB
C
/*
|
|
* Copyright (C)2005-2016 Haxe Foundation
|
|
*
|
|
* Permission is hereby granted, free of charge, to any person obtaining a
|
|
* copy of this software and associated documentation files (the "Software"),
|
|
* to deal in the Software without restriction, including without limitation
|
|
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
|
* and/or sell copies of the Software, and to permit persons to whom the
|
|
* Software is furnished to do so, subject to the following conditions:
|
|
*
|
|
* The above copyright notice and this permission notice shall be included in
|
|
* all copies or substantial portions of the Software.
|
|
*
|
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
|
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
|
* DEALINGS IN THE SOFTWARE.
|
|
*/
|
|
#include "hl.h"
|
|
#include <string.h>
|
|
|
|
HL_PRIM hl_field_lookup *hl_lookup_insert( hl_field_lookup *l, int size, int hash, hl_type *t, int index ) {
|
|
int min = 0;
|
|
int max = size;
|
|
int pos;
|
|
while( min < max ) {
|
|
int mid = (min + max) >> 1;
|
|
int h = l[mid].hashed_name;
|
|
if( h < hash ) min = mid + 1; else max = mid;
|
|
}
|
|
pos = (min + max) >> 1;
|
|
memmove(l + pos + 1, l + pos, (size - pos) * sizeof(hl_field_lookup));
|
|
l[pos].field_index = index;
|
|
l[pos].hashed_name = hash;
|
|
l[pos].t = t;
|
|
return l + pos;
|
|
}
|
|
|
|
HL_PRIM hl_field_lookup *hl_lookup_find( hl_field_lookup *l, int size, int hash ) {
|
|
int min = 0;
|
|
int max = size;
|
|
while( min < max ) {
|
|
int mid = (min + max) >> 1;
|
|
int h = l[mid].hashed_name;
|
|
if( h < hash ) min = mid + 1; else if( h > hash ) max = mid; else return l + mid;
|
|
}
|
|
return NULL;
|
|
}
|
|
|
|
static int hl_lookup_find_index( hl_field_lookup *l, int size, int hash ) {
|
|
int min = 0;
|
|
int max = size;
|
|
while( min < max ) {
|
|
int mid = (min + max) >> 1;
|
|
int h = l[mid].hashed_name;
|
|
if( h < hash ) min = mid + 1; else if( h > hash ) max = mid; else return mid;
|
|
}
|
|
return (min + max) >> 1;
|
|
}
|
|
|
|
static hl_field_lookup *obj_resolve_field( hl_type_obj *o, int hfield ) {
|
|
hl_runtime_obj *rt = o->rt;
|
|
do {
|
|
hl_field_lookup *f = hl_lookup_find(rt->lookup,rt->nlookup,hfield);
|
|
if( f ) return f;
|
|
rt = rt->parent;
|
|
} while( rt );
|
|
return NULL;
|
|
}
|
|
|
|
static int hl_cache_count = 0;
|
|
static int hl_cache_size = 0;
|
|
static hl_mutex *hl_cache_lock = NULL;
|
|
static hl_field_lookup *hl_cache = NULL;
|
|
|
|
void hl_cache_init() {
|
|
# ifdef HL_THREADS
|
|
hl_add_root(&hl_cache_lock);
|
|
# endif
|
|
hl_cache_lock = hl_mutex_alloc(false);
|
|
}
|
|
|
|
HL_PRIM int hl_hash( vbyte *b ) {
|
|
return hl_hash_gen((uchar*)b,true);
|
|
}
|
|
|
|
HL_PRIM int hl_hash_utf8( const char *name ) {
|
|
int h = 0;
|
|
// ASCII should be enough
|
|
while( *name ) {
|
|
h = 223 * h + (unsigned)*name;
|
|
name++;
|
|
}
|
|
h %= 0x1FFFFF7B;
|
|
return h;
|
|
}
|
|
|
|
HL_PRIM int hl_hash_gen( const uchar *name, bool cache_name ) {
|
|
int h = 0;
|
|
const uchar *oname = name;
|
|
while( *name ) {
|
|
h = 223 * h + (unsigned)*name;
|
|
name++;
|
|
}
|
|
h %= 0x1FFFFF7B;
|
|
if( cache_name ) {
|
|
hl_field_lookup *l;
|
|
hl_mutex_acquire(hl_cache_lock);
|
|
l = hl_lookup_find(hl_cache, hl_cache_count, h);
|
|
// check for potential conflict (see haxe#5572)
|
|
while( l && ucmp((uchar*)l->t,oname) != 0 ) {
|
|
h++;
|
|
l = hl_lookup_find(hl_cache, hl_cache_count, h);
|
|
}
|
|
if( l == NULL ) {
|
|
if( hl_cache_size == hl_cache_count ) {
|
|
// resize
|
|
int newsize = hl_cache_size ? (hl_cache_size * 3) >> 1 : 16;
|
|
hl_field_lookup *cache = (hl_field_lookup*)malloc(sizeof(hl_field_lookup) * newsize);
|
|
memcpy(cache,hl_cache,sizeof(hl_field_lookup) * hl_cache_count);
|
|
free(hl_cache);
|
|
hl_cache = cache;
|
|
hl_cache_size = newsize;
|
|
}
|
|
hl_lookup_insert(hl_cache,hl_cache_count++,h,(hl_type*)ustrdup(oname),0);
|
|
}
|
|
hl_mutex_release(hl_cache_lock);
|
|
}
|
|
return h;
|
|
}
|
|
|
|
HL_PRIM vbyte *hl_field_name( int hash ) {
|
|
hl_field_lookup *l = hl_lookup_find(hl_cache, hl_cache_count, hash);
|
|
return l ? (vbyte*)l->t : (vbyte*)USTR("???");
|
|
}
|
|
|
|
HL_PRIM void hl_cache_free() {
|
|
int i;
|
|
for(i=0;i<hl_cache_count;i++)
|
|
free(hl_cache[i].t);
|
|
free(hl_cache);
|
|
hl_cache = NULL;
|
|
hl_cache_count = hl_cache_size = 0;
|
|
hl_mutex_free(hl_cache_lock);
|
|
hl_cache_lock = NULL;
|
|
hl_remove_root(&hl_cache_lock);
|
|
}
|
|
|
|
HL_PRIM hl_obj_field *hl_obj_field_fetch( hl_type *t, int fid ) {
|
|
hl_runtime_obj *rt;
|
|
if( t->kind != HOBJ && t->kind != HSTRUCT )
|
|
return NULL;
|
|
rt = hl_get_obj_rt(t);
|
|
if( fid < 0 || fid >= rt->nfields )
|
|
return NULL;
|
|
while( rt->parent && fid < rt->parent->nfields )
|
|
rt = rt->parent;
|
|
return rt->t->obj->fields + (fid - (rt->parent?rt->parent->nfields:0));
|
|
}
|
|
|
|
HL_PRIM int hl_mark_size( int data_size ) {
|
|
int ptr_count = (data_size + HL_WSIZE - 1) / HL_WSIZE;
|
|
return ((ptr_count + 31) >> 5) * sizeof(int);
|
|
}
|
|
|
|
/**
|
|
Builds class metadata (fields indexes, etc.)
|
|
Does not require the method table to be finalized.
|
|
**/
|
|
HL_PRIM hl_runtime_obj *hl_get_obj_rt( hl_type *ot ) {
|
|
hl_type_obj *o = ot->obj;
|
|
hl_module_context *m = o->m;
|
|
hl_alloc *alloc = &m->alloc;
|
|
hl_runtime_obj *p = NULL, *t;
|
|
int i, size, start, nlookup, compareHash;
|
|
if( o->rt ) return o->rt;
|
|
if( o->super ) p = hl_get_obj_rt(o->super);
|
|
|
|
hl_global_lock(true);
|
|
if( o->rt ) {
|
|
hl_global_lock(false);
|
|
return o->rt;
|
|
}
|
|
|
|
t = (hl_runtime_obj*)hl_malloc(alloc,sizeof(hl_runtime_obj));
|
|
t->t = ot;
|
|
t->nfields = o->nfields + (p ? p->nfields : 0);
|
|
t->nproto = p ? p->nproto : 0;
|
|
t->nlookup = o->nfields;
|
|
t->nbindings = p ? p->nbindings : 0;
|
|
t->hasPtr = p ? p->hasPtr : false;
|
|
|
|
if( !p ) {
|
|
t->nlookup += o->nproto;
|
|
t->nbindings += o->nbindings;
|
|
} else {
|
|
for(i=0;i<o->nproto;i++) {
|
|
hl_obj_proto *pr = o->proto + i;
|
|
if( pr->pindex >= 0 && pr->pindex < p->nproto )
|
|
continue;
|
|
t->nlookup++;
|
|
}
|
|
for(i=0;i<o->nbindings;i++) {
|
|
int j;
|
|
int fid = o->bindings[i<<1];
|
|
bool found = false;
|
|
hl_type_obj *pp = p ? p->t->obj : NULL;
|
|
while( pp && !found ) {
|
|
for(j=0;j<pp->nbindings;j++)
|
|
if( pp->bindings[j<<1] == fid ) {
|
|
found = true;
|
|
break;
|
|
}
|
|
pp = pp->super ? pp->super->obj : NULL;
|
|
}
|
|
if( !found )
|
|
t->nbindings++;
|
|
}
|
|
}
|
|
|
|
t->lookup = (hl_field_lookup*)hl_malloc(alloc,sizeof(hl_field_lookup) * t->nlookup);
|
|
t->fields_indexes = (int*)hl_malloc(alloc,sizeof(int)*t->nfields);
|
|
t->bindings = (hl_runtime_binding*)hl_malloc(alloc,sizeof(hl_runtime_binding)*t->nbindings);
|
|
t->toStringFun = NULL;
|
|
t->compareFun = NULL;
|
|
t->castFun = NULL;
|
|
t->getFieldFun = NULL;
|
|
t->parent = p;
|
|
|
|
// fields indexes
|
|
start = 0;
|
|
if( p ) {
|
|
start = p->nfields;
|
|
memcpy(t->fields_indexes, p->fields_indexes, sizeof(int)*p->nfields);
|
|
}
|
|
size = p ? p->size : (ot->kind == HSTRUCT ? 0 : HL_WSIZE); // hl_type*
|
|
nlookup = 0;
|
|
for(i=0;i<o->nfields;i++) {
|
|
hl_type *ft = o->fields[i].t;
|
|
hl_type *pad = ft;
|
|
while( pad->kind == HPACKED ) {
|
|
// align on first field
|
|
pad = pad->tparam;
|
|
while( pad->obj->super && hl_get_obj_rt(pad->obj->super)->nfields ) pad = pad->obj->super;
|
|
pad = pad->obj->fields[0].t;
|
|
}
|
|
size += hl_pad_struct(size,pad);
|
|
t->fields_indexes[i+start] = size;
|
|
if( *o->fields[i].name )
|
|
hl_lookup_insert(t->lookup,nlookup++,o->fields[i].hashed_name,o->fields[i].t,size);
|
|
else
|
|
t->nlookup--;
|
|
if( ft->kind == HPACKED ) {
|
|
hl_runtime_obj *rts = hl_get_obj_rt(ft->tparam);
|
|
size += rts->size;
|
|
if( rts->hasPtr ) t->hasPtr = true;
|
|
continue;
|
|
}
|
|
size += hl_type_size(ft);
|
|
if( !t->hasPtr && hl_is_ptr(ft) ) t->hasPtr = true;
|
|
}
|
|
t->size = size;
|
|
t->nmethods = p ? p->nmethods : o->nproto;
|
|
t->methods = NULL;
|
|
o->rt = t;
|
|
ot->vobj_proto = NULL;
|
|
|
|
// fields lookup
|
|
compareHash = hl_hash_gen(USTR("__compare"),false);
|
|
for(i=0;i<o->nproto;i++) {
|
|
hl_obj_proto *pr = o->proto + i;
|
|
hl_type *mt;
|
|
int method_index;
|
|
if( p ) {
|
|
if( pr->pindex >= 0 && pr->pindex < p->nproto )
|
|
continue;
|
|
method_index = t->nmethods++;
|
|
} else
|
|
method_index = i;
|
|
if( pr->pindex >= t->nproto ) t->nproto = pr->pindex + 1;
|
|
mt = m->functions_types[pr->findex];
|
|
hl_lookup_insert(t->lookup,nlookup++,pr->hashed_name,mt,-(method_index+1));
|
|
// tell if we have a compare fun (req for JIT)
|
|
if( pr->hashed_name == compareHash && mt->fun->nargs == 2 && mt->fun->args[1]->kind == HDYN && mt->fun->ret->kind == HI32 )
|
|
t->compareFun = (void*)(int_val)pr->findex;
|
|
}
|
|
|
|
// mark bits
|
|
if( t->hasPtr ) {
|
|
unsigned int *mark = (unsigned int*)hl_zalloc(alloc,hl_mark_size(t->size));
|
|
ot->mark_bits = mark;
|
|
if( p && p->t->mark_bits ) memcpy(mark, p->t->mark_bits, hl_mark_size(p->size));
|
|
for(i=0;i<o->nfields;i++) {
|
|
hl_type *ft = o->fields[i].t;
|
|
if( hl_is_ptr(ft) ) {
|
|
int pos = t->fields_indexes[i + start] / HL_WSIZE;
|
|
if( ft->kind == HPACKED ) {
|
|
hl_runtime_obj *rts = hl_get_obj_rt(ft->tparam);
|
|
if( rts->t->mark_bits )
|
|
memcpy(mark + (pos>>5), rts->t->mark_bits, hl_mark_size(rts->size));
|
|
continue;
|
|
}
|
|
mark[pos >> 5] |= 1 << (pos & 31);
|
|
}
|
|
}
|
|
}
|
|
|
|
hl_global_lock(false);
|
|
return t;
|
|
}
|
|
|
|
/**
|
|
Fill class prototype with method pointers.
|
|
Requires method table to be finalized
|
|
**/
|
|
HL_API hl_runtime_obj *hl_get_obj_proto( hl_type *ot ) {
|
|
hl_type_obj *o = ot->obj;
|
|
hl_module_context *m = o->m;
|
|
hl_alloc *alloc = &m->alloc;
|
|
hl_runtime_obj *p = NULL, *t = hl_get_obj_rt(ot);
|
|
hl_field_lookup *strField, *cmpField, *castField, *getField;
|
|
int i;
|
|
int nmethods, nbindings;
|
|
if( ot->vobj_proto ) return t;
|
|
if( o->super ) p = hl_get_obj_proto(o->super);
|
|
|
|
hl_global_lock(true);
|
|
|
|
if( ot->vobj_proto ) {
|
|
hl_global_lock(false);
|
|
return t;
|
|
}
|
|
|
|
if( t->nproto ) {
|
|
void **fptr = (void**)hl_malloc(alloc, sizeof(void*) * t->nproto);
|
|
ot->vobj_proto = fptr;
|
|
if( p )
|
|
memcpy(fptr, p->t->vobj_proto, p->nproto * sizeof(void*));
|
|
for(i=0;i<o->nproto;i++) {
|
|
hl_obj_proto *p = o->proto + i;
|
|
if( p->pindex >= 0 ) fptr[p->pindex] = m->functions_ptrs[p->findex];
|
|
}
|
|
} else
|
|
ot->vobj_proto = (void*)1;
|
|
|
|
t->methods = (void**)hl_malloc(alloc, sizeof(void*) * t->nmethods);
|
|
if( p ) memcpy(t->methods,p->methods,p->nmethods * sizeof(void*));
|
|
|
|
nmethods = p ? p->nmethods : 0;
|
|
for(i=0;i<o->nproto;i++) {
|
|
hl_obj_proto *pr = o->proto + i;
|
|
int method_index;
|
|
if( p ) {
|
|
if( pr->pindex >= 0 && pr->pindex < p->nproto )
|
|
method_index = -obj_resolve_field(o->super->obj,pr->hashed_name)->field_index-1;
|
|
else
|
|
method_index = nmethods++;
|
|
} else
|
|
method_index = i;
|
|
t->methods[method_index] = m->functions_ptrs[pr->findex];
|
|
}
|
|
|
|
// interfaces
|
|
t->ninterfaces = 0;
|
|
for(i=0;i<o->nfields;i++) {
|
|
if( o->fields[i].hashed_name == 0 )
|
|
t->ninterfaces++;
|
|
}
|
|
t->interfaces = (int*)hl_malloc(alloc,sizeof(int) * t->ninterfaces);
|
|
t->ninterfaces = 0;
|
|
for(i=0;i<o->nfields;i++) {
|
|
if( o->fields[i].hashed_name == 0 )
|
|
t->interfaces[t->ninterfaces++] = i;
|
|
}
|
|
|
|
// bindings
|
|
if( p ) {
|
|
nbindings = p->nbindings;
|
|
memcpy(t->bindings,p->bindings,p->nbindings*sizeof(hl_runtime_binding));
|
|
} else
|
|
nbindings = 0;
|
|
for(i=0;i<o->nbindings;i++) {
|
|
int fid = o->bindings[i<<1];
|
|
int mid = o->bindings[(i<<1)|1];
|
|
hl_runtime_binding *b = NULL;
|
|
hl_type *ft;
|
|
if( p ) {
|
|
int j;
|
|
for(j=0;j<p->nbindings;j++)
|
|
if( p->bindings[j].fid == fid ) {
|
|
b = t->bindings + j;
|
|
break;
|
|
}
|
|
}
|
|
if( b == NULL )
|
|
b = t->bindings + nbindings++;
|
|
b->fid = fid;
|
|
ft = hl_obj_field_fetch(t->t, fid)->t;
|
|
switch( ft->kind ) {
|
|
case HFUN:
|
|
if( ft->fun->nargs == m->functions_types[mid]->fun->nargs ) {
|
|
// static fun
|
|
vclosure *c = (vclosure*)hl_malloc(alloc,sizeof(vclosure));
|
|
c->fun = m->functions_ptrs[mid];
|
|
c->t = m->functions_types[mid];
|
|
c->hasValue = false;
|
|
c->value = NULL;
|
|
b->closure = NULL;
|
|
b->ptr = c;
|
|
break;
|
|
}
|
|
// fallthrough
|
|
case HDYN: // __constructor__ is defined as dynamic in Class
|
|
b->closure = m->functions_types[mid];
|
|
b->ptr = m->functions_ptrs[mid];
|
|
break;
|
|
default:
|
|
hl_fatal("invalid bind field");
|
|
break;
|
|
}
|
|
}
|
|
|
|
strField = obj_resolve_field(o,hl_hash_gen(USTR("__string"),false));
|
|
cmpField = obj_resolve_field(o,hl_hash_gen(USTR("__compare"),false));
|
|
castField = obj_resolve_field(o,hl_hash_gen(USTR("__cast"),false));
|
|
getField = obj_resolve_field(o,hl_hash_gen(USTR("__get_field"),false));
|
|
t->toStringFun = strField ? t->methods[-(strField->field_index+1)] : NULL;
|
|
t->compareFun = cmpField && t->compareFun ? t->methods[-(cmpField->field_index+1)] : NULL;
|
|
t->castFun = castField ? t->methods[-(castField->field_index+1)] : NULL;
|
|
t->getFieldFun = getField ? t->methods[-(getField->field_index+1)] : NULL;
|
|
if( p && !t->getFieldFun ) t->getFieldFun = p->getFieldFun;
|
|
|
|
hl_global_lock(false);
|
|
|
|
return t;
|
|
}
|
|
|
|
HL_API void hl_flush_proto( hl_type *ot ) {
|
|
int i;
|
|
hl_type_obj *o = ot->obj;
|
|
hl_runtime_obj *rt = ot->obj->rt;
|
|
hl_module_context *m = o->m;
|
|
if( !rt || !ot->vobj_proto ) return;
|
|
for(i=0;i<o->nbindings;i++) {
|
|
int fid = o->bindings[i<<1];
|
|
int mid = o->bindings[(i<<1)|1];
|
|
hl_runtime_binding *b = NULL;
|
|
int j;
|
|
for(j=0;j<rt->nbindings;j++)
|
|
if( rt->bindings[j].fid == fid ) {
|
|
b = rt->bindings + j;
|
|
break;
|
|
}
|
|
void *ptr = m->functions_ptrs[mid];
|
|
if( b->closure ) {
|
|
if( b->ptr != ptr )
|
|
b->ptr = ptr;
|
|
} else {
|
|
vclosure *c = (vclosure*)b->ptr;
|
|
if( c->fun != ptr )
|
|
c->fun = ptr;
|
|
}
|
|
}
|
|
}
|
|
|
|
HL_API 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);
|
|
unsigned int *mark;
|
|
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_struct(size, f->t);
|
|
indexes[i] = size;
|
|
size += hl_type_size(f->t);
|
|
}
|
|
vt->virt->lookup = l;
|
|
vt->virt->indexes = indexes;
|
|
vt->virt->dataSize = size - vsize;
|
|
mark = (unsigned int*)hl_zalloc(&ctx->alloc, hl_mark_size(size));
|
|
vt->mark_bits = mark;
|
|
mark[0] = 2 | 4; // value | next
|
|
for(i=0;i<vt->virt->nfields;i++) {
|
|
hl_obj_field *f = vt->virt->fields + i;
|
|
if( hl_is_ptr(f->t) ) {
|
|
int pos = indexes[i] / HL_WSIZE;
|
|
mark[pos >> 5] |= 1 << (pos & 31);
|
|
}
|
|
}
|
|
}
|
|
|
|
#define hl_dynobj_field(o,f) (hl_is_ptr((f)->t) ? (void*)((o)->values + (f)->field_index) : (void*) ((o)->raw_data + (f)->field_index))
|
|
|
|
vdynamic *hl_virtual_make_value( vvirtual *v ) {
|
|
vdynobj *o;
|
|
int i, nfields;
|
|
int raw_size = 0, nvalues = 0;
|
|
if( v->value )
|
|
return v->value;
|
|
nfields = v->t->virt->nfields;
|
|
o = hl_alloc_dynobj();
|
|
// copy the lookup table
|
|
o->lookup = (hl_field_lookup*)hl_gc_alloc_noptr(sizeof(hl_field_lookup) * nfields);
|
|
o->nfields = nfields;
|
|
memcpy(o->lookup,v->t->virt->lookup,nfields * sizeof(hl_field_lookup));
|
|
for(i=0;i<nfields;i++) {
|
|
hl_field_lookup *f = o->lookup + i;
|
|
if( hl_is_ptr(f->t) )
|
|
f->field_index = nvalues++;
|
|
else {
|
|
raw_size += hl_pad_size(raw_size, f->t);
|
|
f->field_index = raw_size;
|
|
raw_size += hl_type_size(f->t);
|
|
}
|
|
}
|
|
// copy the data & rebind virtual addresses
|
|
o->raw_data = hl_gc_alloc_noptr(raw_size);
|
|
o->raw_size = raw_size;
|
|
o->values = hl_gc_alloc_raw(nvalues*sizeof(void*));
|
|
o->nvalues = nvalues;
|
|
for(i=0;i<nfields;i++) {
|
|
hl_field_lookup *f = o->lookup + i;
|
|
hl_field_lookup *vf = v->t->virt->lookup + i;
|
|
void **vaddr = hl_vfields(v) + vf->field_index;
|
|
memcpy(hl_dynobj_field(o,f),*vaddr, hl_type_size(f->t));
|
|
*vaddr = hl_dynobj_field(o,f);
|
|
}
|
|
// erase virtual data
|
|
memset(hl_vfields(v) + nfields, 0, v->t->virt->dataSize);
|
|
o->virtuals = v;
|
|
v->value = (vdynamic*)o;
|
|
return v->value;
|
|
}
|
|
|
|
static bool should_recast( hl_type *t, hl_type *vt ) {
|
|
if( vt->kind == HF64 && t->kind == HI32 )
|
|
return true;
|
|
if( vt->kind == HNULL && vt->tparam->kind == t->kind )
|
|
return true;
|
|
if( vt->kind == HNULL && vt->tparam->kind == HF64 && t->kind == HI32 )
|
|
return true;
|
|
if( vt->kind == HVIRTUAL && t->kind == HDYNOBJ )
|
|
return true;
|
|
if( vt->kind == HOBJ && t->kind == HOBJ && vt->obj->rt->castFun )
|
|
return true;
|
|
return false;
|
|
}
|
|
|
|
/**
|
|
Allocate a virtual fields mapping to a given value.
|
|
**/
|
|
vvirtual *hl_to_virtual( hl_type *vt, vdynamic *obj ) {
|
|
vvirtual *v = NULL;
|
|
if( obj == NULL ) return NULL;
|
|
#ifdef _DEBUG
|
|
if( vt->virt->nfields && vt->virt->lookup == NULL ) hl_fatal("virtual not initialized");
|
|
#endif
|
|
switch( obj->t->kind ) {
|
|
case HOBJ:
|
|
{
|
|
int i;
|
|
void **interface_address = NULL;
|
|
{
|
|
hl_runtime_obj *rt = obj->t->obj->rt;
|
|
while( rt ) {
|
|
for(i=0;i<rt->ninterfaces;i++) {
|
|
if( rt->t->obj->fields[rt->interfaces[i]].t == vt ) {
|
|
int start = rt->parent ? rt->parent->nfields : 0;
|
|
interface_address = (void**)((char*)obj + rt->fields_indexes[rt->interfaces[i]+start]);
|
|
break;
|
|
}
|
|
}
|
|
rt = rt->parent;
|
|
}
|
|
}
|
|
if( interface_address ) {
|
|
v = (vvirtual*)*interface_address;
|
|
if( v ) return v;
|
|
}
|
|
v = (vvirtual*)hl_gc_alloc(vt, sizeof(vvirtual) + sizeof(void*)*vt->virt->nfields);
|
|
v->t = vt;
|
|
v->value = obj;
|
|
v->next = NULL;
|
|
for(i=0;i<vt->virt->nfields;i++) {
|
|
hl_field_lookup *f = obj_resolve_field(obj->t->obj,vt->virt->fields[i].hashed_name);
|
|
if( f && f->field_index < 0 ) {
|
|
hl_type *ft = vt->virt->fields[i].t;
|
|
hl_type tmp;
|
|
hl_type_fun tf;
|
|
tmp.kind = HMETHOD;
|
|
tmp.fun = &tf;
|
|
tf.args = f->t->fun->args + 1;
|
|
tf.nargs = f->t->fun->nargs - 1;
|
|
tf.ret = f->t->fun->ret;
|
|
if( hl_safe_cast(&tmp,ft) )
|
|
hl_vfields(v)[i] = obj->t->obj->rt->methods[-f->field_index-1];
|
|
else
|
|
hl_vfields(v)[i] = NULL;
|
|
} else
|
|
hl_vfields(v)[i] = f == NULL || !hl_same_type(f->t,vt->virt->fields[i].t) ? NULL : (char*)obj + f->field_index;
|
|
}
|
|
if( interface_address )
|
|
*interface_address = v;
|
|
}
|
|
break;
|
|
case HDYNOBJ:
|
|
{
|
|
int i;
|
|
int64 need_recast = 0;
|
|
vdynobj *o = (vdynobj*)obj;
|
|
v = o->virtuals;
|
|
while( v ) {
|
|
if( v->t->virt == vt->virt )
|
|
return v;
|
|
v = v->next;
|
|
}
|
|
// allocate a new virtual mapping
|
|
v = (vvirtual*)hl_gc_alloc(vt, sizeof(vvirtual) + sizeof(void*) * vt->virt->nfields);
|
|
v->t = vt;
|
|
v->value = obj;
|
|
for(i=0;i<vt->virt->nfields;i++) {
|
|
hl_field_lookup *f = hl_lookup_find(o->lookup,o->nfields,vt->virt->fields[i].hashed_name);
|
|
hl_type *vft = vt->virt->fields[i].t;
|
|
void *addr = f == NULL || !hl_same_type(f->t,vft) ? NULL : hl_dynobj_field(o,f);
|
|
// check if we will perform recast of some fields to match the virtual definition
|
|
// recast will not work for >64 fields, but this should be pretty rare
|
|
if( addr == NULL && f && !o->virtuals && should_recast(f->t,vft) )
|
|
need_recast |= ((int64)1) << ((int64)i);
|
|
hl_vfields(v)[i] = addr;
|
|
}
|
|
// add it to the list
|
|
v->next = o->virtuals;
|
|
o->virtuals = v;
|
|
// recast
|
|
if( need_recast ) {
|
|
bool extra_check = vt->virt->nfields > 63;
|
|
for(i=0;i<vt->virt->nfields;i++)
|
|
if( need_recast & (((int64)1) << ((int64)i)) ) {
|
|
hl_obj_field *f = vt->virt->fields + i;
|
|
if( extra_check && hl_lookup_find(o->lookup,o->nfields,f->hashed_name) == NULL )
|
|
continue;
|
|
if( hl_is_ptr(f->t) )
|
|
hl_dyn_setp(obj,f->hashed_name,f->t,hl_dyn_getp(obj,f->hashed_name,f->t));
|
|
else if( f->t->kind == HF64 )
|
|
hl_dyn_setd(obj,f->hashed_name,hl_dyn_getd(obj,f->hashed_name));
|
|
}
|
|
}
|
|
}
|
|
break;
|
|
case HVIRTUAL:
|
|
if( hl_safe_cast(obj->t, vt) ) return (vvirtual*)obj;
|
|
return hl_to_virtual(vt,hl_virtual_make_value((vvirtual*)obj));
|
|
default:
|
|
hl_error("Can't cast %s to %s", hl_type_str(obj->t), hl_type_str(vt));
|
|
break;
|
|
}
|
|
return v;
|
|
}
|
|
|
|
static void hl_dynobj_remap_virtuals( vdynobj *o, hl_field_lookup *f, int_val address_offset ) {
|
|
vvirtual *v = o->virtuals;
|
|
bool is_ptr = hl_is_ptr(f->t);
|
|
while( v ) {
|
|
hl_field_lookup *vf = hl_lookup_find(v->t->virt->lookup,v->t->virt->nfields,f->hashed_name);
|
|
int i;
|
|
if( address_offset )
|
|
for(i=0;i<v->t->virt->nfields;i++)
|
|
if( hl_vfields(v)[i] && hl_is_ptr(v->t->virt->fields[i].t) == is_ptr )
|
|
((char**)hl_vfields(v))[i] += address_offset;
|
|
if( vf )
|
|
hl_vfields(v)[vf->field_index] = hl_same_type(vf->t,f->t) ? hl_dynobj_field(o, f) : NULL;
|
|
v = v->next;
|
|
}
|
|
}
|
|
|
|
static void hl_dynobj_delete_field( vdynobj *o, hl_field_lookup *f ) {
|
|
int i;
|
|
int index = f->field_index;
|
|
bool is_ptr = hl_is_ptr(f->t);
|
|
// erase data
|
|
if( is_ptr ) {
|
|
memmove(o->values + index, o->values + index + 1, (o->nvalues - (index + 1)) * sizeof(void*));
|
|
o->nvalues--;
|
|
o->values[o->nvalues] = NULL;
|
|
for(i=0;i<o->nfields;i++) {
|
|
hl_field_lookup *f = o->lookup + i;
|
|
if( hl_is_ptr(f->t) && f->field_index > index )
|
|
f->field_index--;
|
|
}
|
|
} else {
|
|
// no erase needed, compaction will be performed on next add
|
|
}
|
|
|
|
// remove from virtuals
|
|
vvirtual *v = o->virtuals;
|
|
while( v ) {
|
|
hl_field_lookup *vf = hl_lookup_find(v->t->virt->lookup,v->t->virt->nfields,f->hashed_name);
|
|
if( vf ) hl_vfields(v)[vf->field_index] = NULL;
|
|
// remap pointers that were moved
|
|
if( is_ptr ) {
|
|
for(i=0;i<v->t->virt->nfields;i++) {
|
|
vf = v->t->virt->lookup + i;
|
|
if( hl_is_ptr(vf->t) ) {
|
|
void ***pf = (void***)hl_vfields(v) + vf->field_index;
|
|
if( *pf && *pf > (void**)(o->values + index) )
|
|
*pf = (*pf) - 1;
|
|
}
|
|
}
|
|
}
|
|
v = v->next;
|
|
}
|
|
|
|
// remove from lookup
|
|
int field = (int)(f - o->lookup);
|
|
memmove(o->lookup + field, o->lookup + field + 1, (o->nfields - (field + 1)) * sizeof(hl_field_lookup));
|
|
o->nfields--;
|
|
}
|
|
|
|
static hl_field_lookup *hl_dynobj_add_field( vdynobj *o, int hfield, hl_type *t ) {
|
|
int index;
|
|
int_val address_offset;
|
|
|
|
// expand data
|
|
if( hl_is_ptr(t) ) {
|
|
void **nvalues = hl_gc_alloc_raw( (o->nvalues + 1) * sizeof(void*) );
|
|
memcpy(nvalues,o->values,o->nvalues * sizeof(void*));
|
|
index = o->nvalues;
|
|
nvalues[index] = NULL;
|
|
address_offset = (char*)nvalues - (char*)o->values;
|
|
o->values = nvalues;
|
|
o->nvalues++;
|
|
} else {
|
|
int raw_size = 0;
|
|
int i;
|
|
for(i=0;i<o->nfields;i++) {
|
|
hl_field_lookup *f = o->lookup + i;
|
|
if( hl_is_ptr(f->t) ) continue;
|
|
raw_size += hl_pad_size(raw_size, f->t);
|
|
raw_size += hl_type_size(f->t);
|
|
}
|
|
if( raw_size > o->raw_size ) // our current mapping is better
|
|
raw_size = o->raw_size;
|
|
int pad = hl_pad_size(raw_size, t);
|
|
int size = hl_type_size(t);
|
|
char *newData = (char*)hl_gc_alloc_noptr(raw_size + pad + size);
|
|
if( raw_size == o->raw_size )
|
|
memcpy(newData,o->raw_data,o->raw_size);
|
|
else {
|
|
raw_size = 0;
|
|
for(i=0;i<o->nfields;i++) {
|
|
hl_field_lookup *f = o->lookup + i;
|
|
int index = f->field_index;
|
|
if( hl_is_ptr(f->t) ) continue;
|
|
raw_size += hl_pad_size(raw_size, f->t);
|
|
memcpy(newData + raw_size, o->raw_data + index, hl_type_size(f->t));
|
|
f->field_index = raw_size;
|
|
if( index != raw_size )
|
|
hl_dynobj_remap_virtuals(o, f, 0);
|
|
raw_size += hl_type_size(f->t);
|
|
}
|
|
o->raw_size = raw_size;
|
|
}
|
|
address_offset = newData - o->raw_data;
|
|
o->raw_data = newData;
|
|
o->raw_size += pad;
|
|
index = o->raw_size;
|
|
o->raw_size += size;
|
|
}
|
|
|
|
// update field table
|
|
hl_field_lookup *new_lookup = (hl_field_lookup*)hl_gc_alloc_noptr(sizeof(hl_field_lookup) * (o->nfields + 1));
|
|
int field_pos = hl_lookup_find_index(o->lookup, o->nfields, hfield);
|
|
memcpy(new_lookup,o->lookup,field_pos * sizeof(hl_field_lookup));
|
|
hl_field_lookup *f = new_lookup + field_pos;
|
|
f->t = t;
|
|
f->hashed_name = hfield;
|
|
f->field_index = index;
|
|
memcpy(new_lookup + (field_pos + 1),o->lookup + field_pos, (o->nfields - field_pos) * sizeof(hl_field_lookup));
|
|
o->nfields++;
|
|
o->lookup = new_lookup;
|
|
|
|
hl_dynobj_remap_virtuals(o, f, address_offset);
|
|
return f;
|
|
}
|
|
|
|
// -------------------- DYNAMIC GET ------------------------------------
|
|
|
|
static void *hl_obj_lookup( vdynamic *d, int hfield, hl_type **t ) {
|
|
switch( d->t->kind ) {
|
|
case HDYNOBJ:
|
|
{
|
|
vdynobj *o = (vdynobj*)d;
|
|
hl_field_lookup *f = hl_lookup_find(o->lookup,o->nfields,hfield);
|
|
if( f == NULL ) return NULL;
|
|
*t = f->t;
|
|
return hl_dynobj_field(o,f);
|
|
}
|
|
break;
|
|
case HOBJ:
|
|
{
|
|
hl_field_lookup *f = obj_resolve_field(d->t->obj,hfield);
|
|
if( f == NULL || f->field_index < 0 ) return NULL;
|
|
*t = f->t;
|
|
return (char*)d + f->field_index;
|
|
}
|
|
break;
|
|
case HSTRUCT:
|
|
{
|
|
hl_field_lookup *f = obj_resolve_field(d->t->obj,hfield);
|
|
if( f == NULL || f->field_index < 0 ) return NULL;
|
|
*t = f->t;
|
|
return (char*)d->v.ptr + f->field_index;
|
|
}
|
|
break;
|
|
case HVIRTUAL:
|
|
{
|
|
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;
|
|
}
|
|
return NULL;
|
|
}
|
|
|
|
// fetch method or dynamic field (getField)
|
|
static vdynamic *hl_obj_lookup_extra( vdynamic *d, int hfield ) {
|
|
switch( d->t->kind ) {
|
|
case HOBJ:
|
|
case HSTRUCT:
|
|
{
|
|
hl_field_lookup *f = obj_resolve_field(d->t->obj,hfield);
|
|
if( f && f->field_index < 0 )
|
|
return (vdynamic*)hl_alloc_closure_ptr(f->t,d->t->obj->rt->methods[-f->field_index-1],d);
|
|
if( f == NULL ) {
|
|
hl_runtime_obj *rt = d->t->obj->rt;
|
|
if( rt->getFieldFun )
|
|
return rt->getFieldFun(d,hfield);
|
|
}
|
|
return NULL;
|
|
}
|
|
break;
|
|
case HVIRTUAL:
|
|
{
|
|
vdynamic *v = ((vvirtual*)d)->value;
|
|
if( v ) return hl_obj_lookup_extra(v, hfield);
|
|
}
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
return NULL;
|
|
}
|
|
|
|
HL_PRIM int hl_dyn_geti( vdynamic *d, int hfield, hl_type *t ) {
|
|
hl_type *ft;
|
|
hl_track_call(HL_TRACK_DYNFIELD, on_dynfield(d,hfield));
|
|
void *addr = hl_obj_lookup(d,hfield,&ft);
|
|
if( !addr ) {
|
|
d = hl_obj_lookup_extra(d,hfield);
|
|
return d == NULL ? 0 : hl_dyn_casti(&d,&hlt_dyn,t);
|
|
}
|
|
switch( ft->kind ) {
|
|
case HUI8:
|
|
return *(unsigned char*)addr;
|
|
case HUI16:
|
|
return *(unsigned short*)addr;
|
|
case HI32:
|
|
return *(int*)addr;
|
|
case HI64:
|
|
return (int)*(int64*)addr;
|
|
case HF32:
|
|
return (int)*(float*)addr;
|
|
case HF64:
|
|
return (int)*(double*)addr;
|
|
case HBOOL:
|
|
return *(bool*)addr;
|
|
default:
|
|
return hl_dyn_casti(addr,ft,t);
|
|
}
|
|
}
|
|
|
|
HL_PRIM int64 hl_dyn_geti64( vdynamic *d, int hfield ) {
|
|
hl_type *ft;
|
|
hl_track_call(HL_TRACK_DYNFIELD, on_dynfield(d,hfield));
|
|
void *addr = hl_obj_lookup(d,hfield,&ft);
|
|
if( !addr ) {
|
|
d = hl_obj_lookup_extra(d,hfield);
|
|
return d == NULL ? 0 : hl_dyn_casti64(&d,&hlt_dyn);
|
|
}
|
|
switch( ft->kind ) {
|
|
case HUI8:
|
|
return *(unsigned char*)addr;
|
|
case HUI16:
|
|
return *(unsigned short*)addr;
|
|
case HI32:
|
|
return *(int*)addr;
|
|
case HI64:
|
|
return *(int64*)addr;
|
|
case HF32:
|
|
return (int64)*(float*)addr;
|
|
case HF64:
|
|
return (int64)*(double*)addr;
|
|
case HBOOL:
|
|
return *(bool*)addr;
|
|
default:
|
|
return hl_dyn_casti64(addr,ft);
|
|
}
|
|
}
|
|
|
|
HL_PRIM float hl_dyn_getf( vdynamic *d, int hfield ) {
|
|
hl_type *ft;
|
|
hl_track_call(HL_TRACK_DYNFIELD, on_dynfield(d,hfield));
|
|
void *addr = hl_obj_lookup(d,hfield,&ft);
|
|
if( !addr ) {
|
|
d = hl_obj_lookup_extra(d,hfield);
|
|
return d == NULL ? 0.f : hl_dyn_castf(&d,&hlt_dyn);
|
|
}
|
|
return ft->kind == HF32 ? *(float*)addr : hl_dyn_castf(addr,ft);
|
|
}
|
|
|
|
HL_PRIM double hl_dyn_getd( vdynamic *d, int hfield ) {
|
|
hl_type *ft;
|
|
hl_track_call(HL_TRACK_DYNFIELD, on_dynfield(d,hfield));
|
|
void *addr = hl_obj_lookup(d,hfield,&ft);
|
|
if( !addr ) {
|
|
d = hl_obj_lookup_extra(d,hfield);
|
|
return d == NULL ? 0. : hl_dyn_castd(&d,&hlt_dyn);
|
|
}
|
|
return ft->kind == HF64 ? *(double*)addr : hl_dyn_castd(addr,ft);
|
|
}
|
|
|
|
HL_PRIM void *hl_dyn_getp( vdynamic *d, int hfield, hl_type *t ) {
|
|
hl_type *ft;
|
|
hl_track_call(HL_TRACK_DYNFIELD, on_dynfield(d,hfield));
|
|
void *addr = hl_obj_lookup(d,hfield,&ft);
|
|
if( !addr ) {
|
|
d = hl_obj_lookup_extra(d,hfield);
|
|
return d == NULL ? NULL : hl_dyn_castp(&d,&hlt_dyn,t);
|
|
}
|
|
return hl_same_type(t,ft) ? *(void**)addr : hl_dyn_castp(addr,ft,t);
|
|
}
|
|
|
|
// -------------------- DYNAMIC SET ------------------------------------
|
|
|
|
static void *hl_obj_lookup_set( vdynamic *d, int hfield, hl_type *t, hl_type **ft ) {
|
|
switch( d->t->kind ) {
|
|
case HDYNOBJ:
|
|
{
|
|
vdynobj *o = (vdynobj*)d;
|
|
hl_field_lookup *f = hl_lookup_find(o->lookup,o->nfields,hfield);
|
|
if( f == NULL )
|
|
f = hl_dynobj_add_field(o,hfield,t);
|
|
else if( !hl_same_type(t,f->t) ) {
|
|
if( hl_is_ptr(t) != hl_is_ptr(f->t) || hl_type_size(t) != hl_type_size(f->t) ) {
|
|
hl_dynobj_delete_field(o, f);
|
|
f = hl_dynobj_add_field(o,hfield,t);
|
|
} else {
|
|
f->t = t;
|
|
hl_dynobj_remap_virtuals(o,f,0);
|
|
}
|
|
}
|
|
*ft = f->t;
|
|
return hl_dynobj_field(o,f);
|
|
}
|
|
break;
|
|
case HOBJ:
|
|
{
|
|
hl_field_lookup *f = obj_resolve_field(d->t->obj,hfield);
|
|
if( f == NULL || f->field_index < 0 ) hl_error("%s does not have field %s",d->t->obj->name,hl_field_name(hfield));
|
|
*ft = f->t;
|
|
return (char*)d + f->field_index;
|
|
}
|
|
break;
|
|
case HSTRUCT:
|
|
{
|
|
hl_field_lookup *f = obj_resolve_field(d->t->obj,hfield);
|
|
if( f == NULL || f->field_index < 0 ) hl_error("%s does not have field %s",d->t->obj->name,hl_field_name(hfield));
|
|
*ft = f->t;
|
|
return (char*)d->v.ptr + f->field_index;
|
|
}
|
|
break;
|
|
case HVIRTUAL:
|
|
{
|
|
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;
|
|
}
|
|
return NULL;
|
|
}
|
|
|
|
HL_PRIM void hl_dyn_seti( vdynamic *d, int hfield, hl_type *t, int value ) {
|
|
hl_type *ft = NULL;
|
|
hl_track_call(HL_TRACK_DYNFIELD, on_dynfield(d,hfield));
|
|
void *addr = hl_obj_lookup_set(d,hfield,t,&ft);
|
|
switch( ft->kind ) {
|
|
case HUI8:
|
|
*(unsigned char*)addr = (unsigned char)value;
|
|
break;
|
|
case HUI16:
|
|
*(unsigned short*)addr = (unsigned short)value;
|
|
break;
|
|
case HI32:
|
|
*(int*)addr = value;
|
|
break;
|
|
case HI64:
|
|
*(int64*)addr = value;
|
|
break;
|
|
case HBOOL:
|
|
*(bool*)addr = value != 0;
|
|
break;
|
|
case HF32:
|
|
*(float*)addr = (float)value;
|
|
break;
|
|
case HF64:
|
|
*(double*)addr = value;
|
|
break;
|
|
default:
|
|
{
|
|
vdynamic tmp;
|
|
tmp.t = t;
|
|
tmp.v.i = value;
|
|
hl_write_dyn(addr,ft,&tmp,true);
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
|
|
HL_PRIM void hl_dyn_seti64( vdynamic *d, int hfield, int64 value ) {
|
|
hl_type *ft = NULL;
|
|
hl_track_call(HL_TRACK_DYNFIELD, on_dynfield(d,hfield));
|
|
void *addr = hl_obj_lookup_set(d,hfield,&hlt_i64,&ft);
|
|
switch( ft->kind ) {
|
|
case HUI8:
|
|
*(unsigned char*)addr = (unsigned char)value;
|
|
break;
|
|
case HUI16:
|
|
*(unsigned short*)addr = (unsigned short)value;
|
|
break;
|
|
case HI32:
|
|
*(int*)addr = (int)value;
|
|
break;
|
|
case HI64:
|
|
*(int64*)addr = value;
|
|
break;
|
|
case HBOOL:
|
|
*(bool*)addr = value != 0;
|
|
break;
|
|
case HF32:
|
|
*(float*)addr = (float)value;
|
|
break;
|
|
case HF64:
|
|
*(double*)addr = (double)value;
|
|
break;
|
|
default:
|
|
{
|
|
vdynamic tmp;
|
|
tmp.t = &hlt_i64;
|
|
tmp.v.i64 = value;
|
|
hl_write_dyn(addr,ft,&tmp,true);
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
|
|
HL_PRIM void hl_dyn_setf( vdynamic *d, int hfield, float value ) {
|
|
hl_type *t = NULL;
|
|
hl_track_call(HL_TRACK_DYNFIELD, on_dynfield(d,hfield));
|
|
void *addr = hl_obj_lookup_set(d,hfield,&hlt_f32,&t);
|
|
if( t->kind == HF32 )
|
|
*(float*)addr = value;
|
|
else {
|
|
vdynamic tmp;
|
|
tmp.t = &hlt_f32;
|
|
tmp.v.f = value;
|
|
hl_write_dyn(addr,t,&tmp,true);
|
|
}
|
|
}
|
|
|
|
HL_PRIM void hl_dyn_setd( vdynamic *d, int hfield, double value ) {
|
|
hl_type *t = NULL;
|
|
hl_track_call(HL_TRACK_DYNFIELD, on_dynfield(d,hfield));
|
|
void *addr = hl_obj_lookup_set(d,hfield,&hlt_f64,&t);
|
|
if( t->kind == HF64 )
|
|
*(double*)addr = value;
|
|
else {
|
|
vdynamic tmp;
|
|
tmp.t = &hlt_f64;
|
|
tmp.v.d = value;
|
|
hl_write_dyn(addr,t,&tmp,true);
|
|
}
|
|
}
|
|
|
|
HL_PRIM void hl_dyn_setp( vdynamic *d, int hfield, hl_type *t, void *value ) {
|
|
hl_type *ft = NULL;
|
|
hl_track_call(HL_TRACK_DYNFIELD, on_dynfield(d,hfield));
|
|
void *addr = hl_obj_lookup_set(d,hfield,t,&ft);
|
|
if( hl_same_type(t,ft) || (hl_is_ptr(ft) && value == NULL) )
|
|
*(void**)addr = value;
|
|
else if( hl_is_dynamic(t) )
|
|
hl_write_dyn(addr,ft,(vdynamic*)value,false);
|
|
else {
|
|
vdynamic tmp;
|
|
tmp.t = t;
|
|
tmp.v.ptr = value;
|
|
hl_write_dyn(addr,ft,&tmp, true);
|
|
}
|
|
}
|
|
|
|
// -------------------- HAXE API ------------------------------------
|
|
|
|
HL_PRIM vdynamic *hl_obj_get_field( vdynamic *obj, int hfield ) {
|
|
if( obj == NULL )
|
|
return NULL;
|
|
switch( obj->t->kind ) {
|
|
case HOBJ:
|
|
case HVIRTUAL:
|
|
case HDYNOBJ:
|
|
case HSTRUCT:
|
|
return (vdynamic*)hl_dyn_getp(obj,hfield,&hlt_dyn);
|
|
default:
|
|
return NULL;
|
|
}
|
|
}
|
|
|
|
HL_PRIM void hl_obj_set_field( vdynamic *obj, int hfield, vdynamic *v ) {
|
|
if( obj == NULL )
|
|
hl_error("Null access");
|
|
if( v == NULL ) {
|
|
hl_dyn_setp(obj,hfield,&hlt_dyn,NULL);
|
|
return;
|
|
}
|
|
hl_track_call(HL_TRACK_DYNFIELD, on_dynfield(obj,hfield));
|
|
hl_type *ft = NULL;
|
|
void *addr = hl_obj_lookup_set(obj,hfield,v->t,&ft);
|
|
hl_write_dyn(addr,ft,v,false);
|
|
}
|
|
|
|
HL_PRIM bool hl_obj_has_field( vdynamic *obj, int hfield ) {
|
|
if( obj == NULL ) return false;
|
|
switch( obj->t->kind ) {
|
|
case HOBJ:
|
|
case HSTRUCT:
|
|
{
|
|
hl_field_lookup *l = obj_resolve_field(obj->t->obj, hfield);
|
|
return l && l->field_index >= 0;
|
|
}
|
|
break;
|
|
case HDYNOBJ:
|
|
{
|
|
vdynobj *d = (vdynobj*)obj;
|
|
hl_field_lookup *f = hl_lookup_find(d->lookup,d->nfields,hfield);
|
|
return f != NULL;
|
|
}
|
|
break;
|
|
case HVIRTUAL:
|
|
{
|
|
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;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
HL_PRIM bool hl_obj_delete_field( vdynamic *obj, int hfield ) {
|
|
if( obj == NULL ) return false;
|
|
switch( obj->t->kind ) {
|
|
case HDYNOBJ:
|
|
{
|
|
vdynobj *d = (vdynobj*)obj;
|
|
hl_field_lookup *f = hl_lookup_find(d->lookup,d->nfields,hfield);
|
|
if( f == NULL ) return false;
|
|
hl_dynobj_delete_field(d, f);
|
|
return true;
|
|
}
|
|
break;
|
|
case HVIRTUAL:
|
|
{
|
|
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;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
HL_PRIM varray *hl_obj_fields( vdynamic *obj ) {
|
|
varray *a = NULL;
|
|
if( obj == NULL ) return NULL;
|
|
switch( obj->t->kind ) {
|
|
case HDYNOBJ:
|
|
{
|
|
vdynobj *o = (vdynobj*)obj;
|
|
int i;
|
|
a = hl_alloc_array(&hlt_bytes,o->nfields);
|
|
for(i=0;i<o->nfields;i++)
|
|
hl_aptr(a,vbyte*)[i] = (vbyte*)hl_field_name((o->lookup + i)->hashed_name);
|
|
}
|
|
break;
|
|
case HOBJ:
|
|
case HSTRUCT:
|
|
{
|
|
hl_type_obj *tobj = obj->t->obj;
|
|
hl_runtime_obj *o = tobj->rt;
|
|
int i, p = 0;
|
|
a = hl_alloc_array(&hlt_bytes,o->nfields);
|
|
while( true ) {
|
|
for(i=0;i<tobj->nfields;i++) {
|
|
hl_obj_field *f = tobj->fields + i;
|
|
if( !*f->name ) {
|
|
a->size--;
|
|
continue;
|
|
}
|
|
hl_aptr(a,vbyte*)[p++] = (vbyte*)f->name;
|
|
}
|
|
if( tobj->super == NULL ) break;
|
|
tobj = tobj->super->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;
|
|
}
|
|
return a;
|
|
}
|
|
|
|
HL_PRIM vdynamic *hl_obj_copy( vdynamic *obj ) {
|
|
if( obj == NULL )
|
|
return NULL;
|
|
switch( obj->t->kind ) {
|
|
case HDYNOBJ:
|
|
{
|
|
vdynobj *o = (vdynobj*)obj;
|
|
vdynobj *c = hl_alloc_dynobj();
|
|
int lsize = sizeof(hl_field_lookup) * o->nfields;
|
|
c->raw_size = o->raw_size;
|
|
c->nfields = o->nfields;
|
|
c->nvalues = o->nvalues;
|
|
c->virtuals = NULL;
|
|
c->lookup = (hl_field_lookup*)hl_gc_alloc_noptr(lsize);
|
|
memcpy(c->lookup,o->lookup,lsize);
|
|
c->raw_data = (char*)hl_gc_alloc_noptr(o->raw_size);
|
|
c->values = (void**)hl_gc_alloc_raw(o->nvalues * sizeof(void*));
|
|
memcpy(c->raw_data,o->raw_data,o->raw_size);
|
|
memcpy(c->values,o->values,o->nvalues * sizeof(void*));
|
|
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(hl_vfields(v2) + v->t->virt->nfields, hl_vfields(v) + v->t->virt->nfields, v->t->virt->dataSize);
|
|
return (vdynamic*)v2;
|
|
}
|
|
default:
|
|
break;
|
|
}
|
|
return NULL;
|
|
}
|
|
|
|
HL_PRIM vdynamic *hl_get_virtual_value( vdynamic *v ) {
|
|
return ((vvirtual*)v)->value;
|
|
}
|
|
|
|
DEFINE_PRIM(_DYN, alloc_obj, _TYPE);
|
|
DEFINE_PRIM(_DYN, obj_get_field, _DYN _I32);
|
|
DEFINE_PRIM(_VOID, obj_set_field, _DYN _I32 _DYN);
|
|
DEFINE_PRIM(_BOOL, obj_has_field, _DYN _I32);
|
|
DEFINE_PRIM(_BOOL, obj_delete_field, _DYN _I32);
|
|
DEFINE_PRIM(_ARR, obj_fields, _DYN);
|
|
DEFINE_PRIM(_DYN, obj_copy, _DYN);
|
|
DEFINE_PRIM(_DYN, get_virtual_value, _DYN);
|
|
DEFINE_PRIM(_I32, hash, _BYTES);
|
|
DEFINE_PRIM(_BYTES, field_name, _I32);
|
|
|