The actual first failure of the build on ARM is not in the Rakudo setting (which the previous message addresses), but on the very first thing that NQP tries to build, using a bootstrap .mvm file.
ie, the built MoarVM is bust. This turns out to be because P6Opaque was ignoring alignment constraints when mapping struct members. On x86_64 Win32 and Linux (and other) this didn't matter - all 3 types that P6Opaque deals with are all 64 bit. (Or possibly 2 - is anything using a MVMnum64 attribute?) On x86 Linux it also didn't matter, because the alignment of MVMint64 in structures is only 4 bytes, so no padding is ever needed. On ARM, MVMint64 needs to be 8 byte aligned in structures. Hence things blew up quite spectacularly, very early. With these 2 and the previous 2 patches, ARM almost builds. Curiously, this seems to fix known problems on 32 bit Win32. So I think that it's worth someone checking this on Windows (32 bit and 64 bit) and if it doesn't break anything that currently works, applying it. Nicholas Clark
>From d57ceba5b4064846980b944943cea4d2f4b54bbc Mon Sep 17 00:00:00 2001 From: Nicholas Clark <n...@ccl4.org> Date: Sun, 4 May 2014 14:45:41 +0200 Subject: [PATCH 3/5] Move the assignment to repr_data->attribute_offsets[cur_slot] later in compose() We need it later to deal better with alignment for platform portability. Splitting it into a distinct commit makes it easier to show that this part of the change introduces no regressions. --- src/6model/reprs/P6opaque.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/6model/reprs/P6opaque.c b/src/6model/reprs/P6opaque.c index bfff91a..bc7ffc6 100644 --- a/src/6model/reprs/P6opaque.c +++ b/src/6model/reprs/P6opaque.c @@ -689,8 +689,6 @@ static void compose(MVMThreadContext *tc, MVMSTable *st, MVMObject *info_hash) { if (MVM_is_null(tc, name_obj)) MVM_exception_throw_adhoc(tc, "P6opaque: missing attribute name"); - /* Attribute will live at the current position in the object. */ - repr_data->attribute_offsets[cur_slot] = cur_alloc_addr; if (REPR(name_obj)->ID == MVM_REPR_ID_MVMString) { MVM_ASSIGN_REF(tc, &(st->header), name_map->names[i], (MVMString *)name_obj); } @@ -765,6 +763,9 @@ static void compose(MVMThreadContext *tc, MVMSTable *st, MVMObject *info_hash) { } } + /* Attribute will live at the current position in the object. */ + repr_data->attribute_offsets[cur_slot] = cur_alloc_addr; + /* Handle object attributes, which need marking and may have auto-viv needs. */ if (!inlined) { repr_data->gc_obj_mark_offsets[cur_obj_attr] = cur_alloc_addr; -- 1.8.4.2
>From b54d708ea1ee49ad307c9f0455466cd7ff04e630 Mon Sep 17 00:00:00 2001 From: Nicholas Clark <n...@ccl4.org> Date: Sun, 4 May 2014 21:31:04 +0200 Subject: [PATCH 4/5] P6opaque must handle C structure member alignment, just like CStruct does. In particular, on some platforms MVMint64 has 8 byte alignment, which means padding may well be required to correctly map to how the C compiler lays out structs. --- src/6model/reprs/P6opaque.c | 33 +++++++++++++++++++++++++++------ 1 file changed, 27 insertions(+), 6 deletions(-) diff --git a/src/6model/reprs/P6opaque.c b/src/6model/reprs/P6opaque.c index bc7ffc6..64f08cc 100644 --- a/src/6model/reprs/P6opaque.c +++ b/src/6model/reprs/P6opaque.c @@ -576,7 +576,7 @@ static void compose(MVMThreadContext *tc, MVMSTable *st, MVMObject *info_hash) { MVMint64 mro_pos, mro_count, num_parents, total_attrs, num_attrs, cur_slot, cur_type, cur_alloc_addr, cur_obj_attr, cur_init_slot, cur_mark_slot, cur_cleanup_slot, cur_unbox_slot, - unboxed_type, bits, i; + unboxed_type, i; MVMObject *info; MVMStringConsts str_consts = tc->instance->str_consts; @@ -684,6 +684,8 @@ static void compose(MVMThreadContext *tc, MVMSTable *st, MVMObject *info_hash) { MVMint64 is_box_target = REPR(attr_info)->ass_funcs.exists_key(tc, STABLE(attr_info), attr_info, OBJECT_BODY(attr_info), (MVMObject *)str_box_target); MVMint8 inlined = 0; + MVMuint32 bits; + MVMuint32 align; /* Ensure we have a name. */ if (MVM_is_null(tc, name_obj)) @@ -700,6 +702,7 @@ static void compose(MVMThreadContext *tc, MVMSTable *st, MVMObject *info_hash) { /* Consider the type. */ unboxed_type = MVM_STORAGE_SPEC_BP_NONE; bits = sizeof(MVMObject *) * 8; + align = ALIGNOF(void *); if (!MVM_is_null(tc, type)) { /* Get the storage spec of the type and see what it wants. */ MVMStorageSpec spec = REPR(type)->get_storage_spec(tc, STABLE(type)); @@ -707,6 +710,7 @@ static void compose(MVMThreadContext *tc, MVMSTable *st, MVMObject *info_hash) { /* Yes, it's something we'll flatten. */ unboxed_type = spec.boxed_primitive; bits = spec.bits; + align = spec.align; MVM_ASSIGN_REF(tc, &(st->header), repr_data->flattened_stables[cur_slot], STABLE(type)); inlined = 1; @@ -763,6 +767,13 @@ static void compose(MVMThreadContext *tc, MVMSTable *st, MVMObject *info_hash) { } } + /* C structure needs careful alignment. If cur_alloc_addr is not + * aligned to align bytes (cur_alloc_addr % align), make sure it is + * before we add the next element. */ + if (cur_alloc_addr % align) { + cur_alloc_addr += align - cur_alloc_addr % align; + } + /* Attribute will live at the current position in the object. */ repr_data->attribute_offsets[cur_slot] = cur_alloc_addr; @@ -826,15 +837,19 @@ static void deserialize_stable_size(MVMThreadContext *tc, MVMSTable *st, MVMSeri /* To calculate size, we need number of attributes and to know about * anything flattend in. */ MVMint64 num_attributes = reader->read_varint(tc, reader); - MVMuint32 cur_offset = 0; + MVMuint32 cur_offset = sizeof(MVMP6opaque); MVMint64 i; for (i = 0; i < num_attributes; i++) { if (reader->read_varint(tc, reader)) { MVMSTable *st = reader->read_stable_ref(tc, reader); MVMStorageSpec ss = st->REPR->get_storage_spec(tc, st); - if (ss.inlineable) + if (ss.inlineable) { /* TODO: Review if/when we get sub-byte things. */ + if (cur_offset % ss.align) { + cur_offset += ss.align - cur_offset % ss.align; + } cur_offset += ss.bits / 8; + } else cur_offset += sizeof(MVMObject *); } @@ -843,7 +858,7 @@ static void deserialize_stable_size(MVMThreadContext *tc, MVMSTable *st, MVMSeri } } - st->size = sizeof(MVMP6opaque) + cur_offset; + st->size = cur_offset; } /* Serializes the REPR data. */ @@ -1017,7 +1032,7 @@ static void deserialize_repr_data(MVMThreadContext *tc, MVMSTable *st, MVMSerial else { /* Store position. */ MVMSTable *cur_st = repr_data->flattened_stables[i]; - repr_data->attribute_offsets[i] = cur_offset; + MVMStorageSpec spec = cur_st->REPR->get_storage_spec(tc, cur_st); /* Set up flags for initialization and GC. */ if (cur_st->REPR->initialize) @@ -1027,8 +1042,14 @@ static void deserialize_repr_data(MVMThreadContext *tc, MVMSTable *st, MVMSerial if (cur_st->REPR->gc_cleanup) repr_data->gc_cleanup_slots[cur_gc_cleanup_slot++] = i; + if (cur_offset % spec.align) { + cur_offset += spec.align - cur_offset % spec.align; + } + + repr_data->attribute_offsets[i] = cur_offset; + /* Increment by size reported by representation. */ - cur_offset += cur_st->REPR->get_storage_spec(tc, cur_st).bits / 8; + cur_offset += spec.bits / 8; } } repr_data->initialize_slots[cur_initialize_slot] = -1; -- 1.8.4.2