Skip to content

Commit

Permalink
Merge pull request #1365 from MoarVM/big-endian-deserialisation
Browse files Browse the repository at this point in the history
Eliminate pointer mismatch warnings on big endian systems.

Avoid a call to `memcpy` everywhere, not just little endian systems that support unaligned reads.
  • Loading branch information
nwc10 committed Oct 26, 2020
2 parents 5c791a4 + dfbdcc9 commit d7a2c9f
Showing 1 changed file with 33 additions and 18 deletions.
51 changes: 33 additions & 18 deletions src/6model/serialization.c
Expand Up @@ -98,7 +98,7 @@
/* Endian translation (file format is little endian, so on big endian we need
* to twiddle. */
#ifdef MVM_BIGENDIAN
static void switch_endian(char *bytes, size_t size)
MVM_STATIC_INLINE void switch_endian(char *bytes, size_t size)
{
size_t low = 0;
size_t high = size - 1;
Expand Down Expand Up @@ -1479,7 +1479,7 @@ static MVMint64 read_int64(const char *buffer, size_t offset) {
MVMint64 value;
memcpy(&value, buffer + offset, 8);
#ifdef MVM_BIGENDIAN
switch_endian(&value, 8);
switch_endian((char *)&value, 8);
#endif
return value;
}
Expand All @@ -1489,7 +1489,7 @@ static MVMint32 read_int32(const char *buffer, size_t offset) {
MVMint32 value;
memcpy(&value, buffer + offset, 4);
#ifdef MVM_BIGENDIAN
switch_endian(&value, 4);
switch_endian((char *)&value, 4);
#endif
return value;
}
Expand All @@ -1498,7 +1498,7 @@ static MVMuint16 read_uint16(const char *buffer, size_t offset) {
MVMuint16 value;
memcpy(&value, buffer + offset, 2);
#ifdef MVM_BIGENDIAN
switch_endian(&value, 2);
switch_endian((char *)&value, 2);
#endif
return value;
}
Expand All @@ -1508,7 +1508,7 @@ static MVMnum64 read_double(const char *buffer, size_t offset) {
MVMnum64 value;
memcpy(&value, buffer + offset, 8);
#ifdef MVM_BIGENDIAN
switch_endian(&value, 8);
switch_endian((char *)&value, 8);
#endif
return value;
}
Expand Down Expand Up @@ -1636,7 +1636,7 @@ MVMint64 MVM_serialization_read_int(MVMThreadContext *tc, MVMSerializationReader
memcpy(&result, read_at, 8);
#endif
#ifdef MVM_BIGENDIAN
switch_endian(&result, 8);
switch_endian((char *)&result, 8);
#endif
*(reader->cur_read_offset) += 9;
return result;
Expand All @@ -1653,16 +1653,34 @@ MVMint64 MVM_serialization_read_int(MVMThreadContext *tc, MVMSerializationReader

/* The remaining 1 to 7 lower bytes follow next in the serialization stream.
*/
#ifdef MVM_BIGENDIAN
{
MVMuint8 *write_to = (MVMuint8 *)&result + 8 - need;
memcpy(write_to, read_at, need);
switch_endian(write_to, need);
}
#else
# ifdef MVM_CAN_UNALIGNED_INT64
/* Written out longhand to avoid the non-inlined function call:
* memcpy(&result, read_at, need);
* We can also inline the endian switch for big endian platforms. */
/* GCC and Clang both optimize this */
switch (MVM_EXPECT(need, 2)) {
#ifdef MVM_BIGENDIAN
case 7:
((MVMuint8*)&result)[1] = read_at[6];
MVM_FALLTHROUGH
case 6:
((MVMuint8*)&result)[2] = read_at[5];
MVM_FALLTHROUGH
case 5:
((MVMuint8*)&result)[3] = read_at[4];
MVM_FALLTHROUGH
case 4:
((MVMuint8*)&result)[4] = read_at[3];
MVM_FALLTHROUGH
case 3:
((MVMuint8*)&result)[5] = read_at[2];
MVM_FALLTHROUGH
case 2:
((MVMuint8*)&result)[6] = read_at[1];
MVM_FALLTHROUGH
case 1:
((MVMuint8*)&result)[7] = read_at[0];
break;
#else
case 7:
((MVMuint8*)&result)[6] = read_at[6];
MVM_FALLTHROUGH
Expand All @@ -1684,11 +1702,8 @@ MVMint64 MVM_serialization_read_int(MVMThreadContext *tc, MVMSerializationReader
case 1:
((MVMuint8*)&result)[0] = read_at[0];
break;
}
# else
memcpy(&result, read_at, need);
# endif
#endif
}

/* Having pieced the (unsigned) value back together, sign extend it: */
result = result << (64 - 4 - 8 * need);
Expand Down

0 comments on commit d7a2c9f

Please sign in to comment.