Skip to content

Commit

Permalink
Implement CStruct
Browse files Browse the repository at this point in the history
  • Loading branch information
gerdr committed Sep 27, 2013
1 parent 763b768 commit f82e61a
Show file tree
Hide file tree
Showing 3 changed files with 286 additions and 15 deletions.
266 changes: 253 additions & 13 deletions src/native/CStruct.c
Original file line number Diff line number Diff line change
@@ -1,33 +1,273 @@
#include "moarvm.h"

static const MVMREPROps this_repr;

const MVMREPROps * MVMCStruct_initialize(MVMThreadContext *tc) {
return &this_repr;
}

static MVMObject * type_object_for(MVMThreadContext *tc, MVMObject *HOW) {
MVMSTable *st = MVM_gc_allocate_stable(tc, &this_repr, HOW);

MVMROOT(tc, st, {
MVMObject *obj = MVM_gc_allocate_type_object(tc, st);
MVM_ASSIGN_REF(tc, st, st->WHAT, obj);
st->size = sizeof(MVMPtr);
});

return st->WHAT;
}

static MVMObject * allocate(MVMThreadContext *tc, MVMSTable *st) {
return MVM_gc_allocate_object(tc, st);
}

static void initialize(MVMThreadContext *tc, MVMSTable *st, MVMObject *root,
void *data) {
MVMPtrBody *body = data;

if (!st->REPR_data)
MVM_exception_throw_adhoc(tc,
"cannot initialize C struct from uncomposed type object");

body->cobj = NULL;
body->blob = NULL;
}

static int find_name(const void *key, const void *value) {
return MVM_string_compare(NULL, (MVMString *)key, *(MVMString **)value);
}

static MVMint64 hint_for(MVMThreadContext *tc, MVMSTable *st,
MVMObject *class_handle, MVMString *name) {
MVMCStructSpec *spec = st->REPR_data;

MVMString **value = bsearch(name, spec->member_names, spec->member_count,
sizeof(MVMString *), find_name);

return value ? value - spec->member_names : MVM_NO_HINT;
}

static void get_attribute(MVMThreadContext *tc, MVMSTable *st,
MVMObject *root, void *data, MVMObject *class_handle, MVMString *name,
MVMint64 hint, MVMRegister *result, MVMuint16 kind) {
MVMPtrBody *body = data;
MVMCStructSpec *spec = st->REPR_data;
MVMObject *type;
MVMuint64 offset;

if (hint < 0) {
hint = hint_for(tc, st, class_handle, name);
if (hint < 0)
MVM_exception_throw_adhoc(tc, "unknown attribute");
}

type = spec->members[hint].type;
offset = spec->members[hint].offset;

switch (kind) {
case MVM_reg_obj:
MVMROOT(tc, root, {
MVMPtr *ptr = (MVMPtr *)MVM_repr_alloc_init(tc, type);
ptr->body.cobj = (char *)body->cobj + offset;
MVM_ASSIGN_REF(tc, ptr, ptr->body.blob, body->blob);
result->o = (MVMObject *)ptr;
});
return;

case MVM_reg_int64: {
MVMPtrBody dummy = { (char *)body->cobj + offset, NULL };

result->i64 = REPR(type)->box_funcs.get_int(tc, STABLE(type), root,
&dummy);
return;
}

case MVM_reg_num64: {
MVMPtrBody dummy = { (char *)body->cobj + offset, NULL };

result->n64 = REPR(type)->box_funcs.get_num(tc, STABLE(type), root,
&dummy);
return;
}

default:
MVM_exception_throw_adhoc(tc,
"unsupported result kind for C struct get_attribute");
}
}

static void bind_attribute(MVMThreadContext *tc, MVMSTable *st,
MVMObject *root, void *data, MVMObject *class_handle, MVMString *name,
MVMint64 hint, MVMRegister value, MVMuint16 kind) {
MVMPtrBody *body = data;
MVMCStructSpec *spec = st->REPR_data;
MVMObject *type;
MVMuint64 offset;

if (hint < 0) {
hint = hint_for(tc, st, class_handle, name);
if (hint < 0)
MVM_exception_throw_adhoc(tc, "unknown attribute");
}

type = spec->members[hint].type;
offset = spec->members[hint].offset;

switch (kind) {
case MVM_reg_obj:
MVM_exception_throw_adhoc(tc, "TODO [%s:%u]", __FILE__, __LINE__);

case MVM_reg_int64: {
MVMPtrBody dummy = { (char *)body->cobj + offset, NULL };

REPR(type)->box_funcs.set_int(tc, STABLE(type), root,
&dummy, value.i64);
return;
}

case MVM_reg_num64: {
MVMPtrBody dummy = { (char *)body->cobj + offset, NULL };

REPR(type)->box_funcs.set_num(tc, STABLE(type), root,
&dummy, value.n64);
return;
}

default: fail:
MVM_exception_throw_adhoc(tc,
"unsupported argument kind for C struct bind_attribute");
}
}

static MVMint64 is_attribute_initialized(MVMThreadContext *tc, MVMSTable *st,
void *data, MVMObject *class_handle, MVMString *name, MVMint64 hint) {
return 1;
}

static MVMStorageSpec get_storage_spec(MVMThreadContext *tc, MVMSTable *st) {
MVMStorageSpec spec;

spec.inlineable = MVM_STORAGE_SPEC_REFERENCE;
spec.boxed_primitive = MVM_STORAGE_SPEC_BP_NONE;
spec.can_box = 0;

return spec;
}

static void gc_mark(MVMThreadContext *tc, MVMSTable *st, void *data,
MVMGCWorklist *worklist) {
MVMPtrBody *body = data;

if (body->blob)
MVM_gc_worklist_add(tc, worklist, &body->blob);
}

static void gc_mark_repr_data(MVMThreadContext *tc, MVMSTable *st,
MVMGCWorklist *worklist) {
MVMCStructSpec *spec = st->REPR_data;

if (spec) {
MVMuint64 i;

for (i = 0; i < spec->member_count; i++) {
MVM_gc_worklist_add(tc, worklist, &spec->member_names[i]);
MVM_gc_worklist_add(tc, worklist, &spec->members[i]);
}
}

}

static void gc_free_repr_data(MVMThreadContext *tc, MVMSTable *st) {
MVMCStructSpec *spec = st->REPR_data;

if (spec) {
free(spec->member_names);
free(spec->members);
MVM_checked_free_null(st->REPR_data);
}
}

static void compose(MVMThreadContext *tc, MVMSTable *st, MVMObject *info) {
MVMCStructSpec *spec;
MVMuint64 count = MVM_repr_elems(tc, info);
MVMuint64 size = 0, align = 0;
MVMuint64 i;

if (count < 2)
MVM_exception_throw_adhoc(tc, "cannot create empty C struct");

spec = malloc(sizeof *spec);
spec->member_count = count / 2;
spec->member_names = malloc(count * sizeof(MVMString *));
spec->members = malloc(count * sizeof(MVMCMemberSpec));

for (i = 0; i < count; i += 2) {
MVMObject *type = MVM_repr_at_pos_o(tc, info, i);
MVMString *name = MVM_repr_get_str(tc,
MVM_repr_at_pos_o(tc, info, i + 1));
MVMuint64 member_size = MVM_native_csizeof(tc, type);
MVMuint64 member_align = MVM_native_calignof(tc, type);
MVMuint64 padding = size % member_align
? member_align - size % member_align
: 0;
MVMuint64 pos = i / 2;

if (member_align > align)
align = member_align;

size += padding;

/* insertion sort */
while (pos > 0 && MVM_string_compare(tc, name,
spec->member_names[pos - 1]) < 0) {
spec->member_names[pos] = spec->member_names[pos - 1];
spec->members[pos] = spec->members[pos - 1];
pos--;
}

spec->member_names[pos] = name;
spec->members[pos].type = type;
spec->members[pos].offset = size;

size += member_size;
}

spec->size = (size + align - 1) / align * align;
spec->align = align;

st->REPR_data = spec;
}

static const MVMREPROps this_repr = {
NULL, /* type_object_for */
NULL, /* allocate */
NULL, /* initialize */
type_object_for,
allocate,
initialize,
NULL, /* copy_to */
MVM_REPR_DEFAULT_ATTR_FUNCS,
{ /* attr_funcs */
get_attribute,
bind_attribute,
hint_for,
is_attribute_initialized
},
MVM_REPR_DEFAULT_BOX_FUNCS,
MVM_REPR_DEFAULT_POS_FUNCS,
MVM_REPR_DEFAULT_ASS_FUNCS,
MVM_REPR_DEFAULT_ELEMS,
NULL, /* get_storage_spec */
get_storage_spec,
NULL, /* change_type */
NULL, /* serialize */
NULL, /* deserialize */
NULL, /* serialize_repr_data */
NULL, /* deserialize_repr_data */
NULL, /* deserialize_stable_size */
NULL, /* gc_mark */
gc_mark,
NULL, /* gc_free */
NULL, /* gc_cleanup */
NULL, /* gc_mark_repr_data */
NULL, /* gc_free_repr_data */
NULL, /* compose */
gc_mark_repr_data,
gc_free_repr_data,
compose,
"CStruct",
MVM_REPR_ID_CStruct,
0, /* refs_frames */
};

const MVMREPROps * MVMCStruct_initialize(MVMThreadContext *tc) {
return &this_repr;
}
22 changes: 20 additions & 2 deletions src/native/ops.c
Original file line number Diff line number Diff line change
Expand Up @@ -145,7 +145,16 @@ MVMuint64 MVM_native_csizeof(MVMThreadContext *tc, MVMObject *obj) {
return spec->elem_count * spec->elem_size;
}

case MVM_REPR_ID_CStruct:
case MVM_REPR_ID_CStruct: {
MVMCStructSpec *spec = STABLE(obj)->REPR_data;

if (!spec)
MVM_exception_throw_adhoc(tc,
"cannot get size of uncomposed C struct");

return spec->size;
}

case MVM_REPR_ID_CUnion:
case MVM_REPR_ID_CFlexStruct:
MVM_exception_throw_adhoc(tc, "TODO [%s:%u]", __FILE__, __LINE__);
Expand Down Expand Up @@ -196,7 +205,16 @@ MVMuint64 MVM_native_calignof(MVMThreadContext *tc, MVMObject *obj) {
return MVM_native_calignof(tc, STABLE(obj)->REPR_data);
}

case MVM_REPR_ID_CStruct:
case MVM_REPR_ID_CStruct: {
MVMCStructSpec *spec = STABLE(obj)->REPR_data;

if (!spec)
MVM_exception_throw_adhoc(tc,
"cannot get alignment of uncomposed C struct");

return spec->align;
}

case MVM_REPR_ID_CUnion:
case MVM_REPR_ID_CFlexStruct:
MVM_exception_throw_adhoc(tc, "TODO [%s:%u]", __FILE__, __LINE__);
Expand Down
13 changes: 13 additions & 0 deletions src/native/reprs.h
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,19 @@ typedef struct {
MVMObject *elem_type;
} MVMCArraySpec;

typedef struct {
MVMObject *type;
MVMuint64 offset;
} MVMCMemberSpec;

typedef struct {
MVMuint64 size;
MVMuint64 align;
MVMuint64 member_count;
MVMString **member_names;
MVMCMemberSpec *members;
} MVMCStructSpec;

#if 0
typedef union {
MVMPtrBody PTR;
Expand Down

0 comments on commit f82e61a

Please sign in to comment.