Use combined byte_swap + read_unaligned for WebAssembly (#147)

The default read_unaligned causes CharLS to crash in WebAssembly builds. Use the original combined method to read bytes from the stream when building for the WebAssembly target.
This commit is contained in:
Victor Derks 2022-01-20 21:58:19 +01:00 committed by GitHub
parent c6075f3e82
commit cce893ef70
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
6 changed files with 49 additions and 8 deletions

View File

@ -58,8 +58,10 @@
<s:Boolean x:Key="/Default/UserDictionary/Words/=destructors/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/UserDictionary/Words/=Dicom/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/UserDictionary/Words/=Dtor/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/UserDictionary/Words/=emcc/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/UserDictionary/Words/=Endian/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/UserDictionary/Words/=errc/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/UserDictionary/Words/=Errval/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/UserDictionary/Words/=facto/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/UserDictionary/Words/=FFMPEG/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/UserDictionary/Words/=forceinline/@EntryIndexedValue">True</s:Boolean>

View File

@ -261,7 +261,7 @@ private:
// Easy & fast: if there is no 0xFF byte in sight, we can read without bit stuffing
if (position_ < position_ff_ - (sizeof(cache_t) - 1))
{
read_cache_ |= byte_swap(read_unaligned<cache_t>(position_)) >> valid_bits_;
read_cache_ |= read_big_endian_unaligned<cache_t>(position_) >> valid_bits_;
const int bytes_to_read{(cache_t_bit_count - valid_bits_) / 8};
position_ += bytes_to_read;
valid_bits_ += bytes_to_read * 8;

View File

@ -576,7 +576,7 @@ USE_DECL_ANNOTATIONS uint16_t jpeg_stream_reader::read_uint16() noexcept
{
ASSERT(position_ + sizeof(uint16_t) <= end_position_);
const auto value{byte_swap(read_unaligned<uint16_t>(position_))};
const auto value{read_big_endian_unaligned<uint16_t>(position_)};
advance_position(2);
return value;
}
@ -593,7 +593,7 @@ USE_DECL_ANNOTATIONS uint32_t jpeg_stream_reader::read_uint32() noexcept
{
ASSERT(position_ + sizeof(uint32_t) <= end_position_);
const auto value{byte_swap(read_unaligned<uint32_t>(position_))};
const auto value{read_big_endian_unaligned<uint32_t>(position_)};
advance_position(4);
return value;
}

View File

@ -68,13 +68,13 @@ unique_ptr<Strategy> make_codec(const Traits& traits, const frame_info& frame_in
// Functions to build tables used to decode short Golomb codes.
inline std::pair<int32_t, int32_t> create_encoded_value(const int32_t k, const int32_t mapped_error) noexcept
std::pair<int32_t, int32_t> create_encoded_value(const int32_t k, const int32_t mapped_error) noexcept
{
const int32_t high_bits{mapped_error >> k};
return std::make_pair(high_bits + k + 1, (1 << k) | (mapped_error & ((1 << k) - 1)));
}
inline golomb_code_table initialize_table(const int32_t k) noexcept
golomb_code_table initialize_table(const int32_t k) noexcept
{
golomb_code_table table;
for (int16_t error_value{};; ++error_value)

View File

@ -303,13 +303,52 @@ CHARLS_CHECK_RETURN inline uint64_t byte_swap(const uint64_t value) noexcept
template<typename T>
T read_unaligned(const void* buffer) noexcept
{
// Note: MSVC, GCC and clang will replace this with a direct register read if architecture allows it (x86, x64, ARM64
// allows it)
// Note: MSVC, GCC and clang will replace this with a direct register read if the CPU architecture allows it
// On x86, x64 and ARM64 this will just be 1 register load.
T value;
memcpy(&value, buffer, sizeof(T));
return value;
}
#ifdef __EMSCRIPTEN__
// Note: WebAssembly (emcc 3.1.1) will fail with the default read_unaligned.
template<typename T>
T read_big_endian_unaligned(const void* /*buffer*/) noexcept;
template<>
inline uint16_t read_big_endian_unaligned<uint16_t>(const void* buffer) noexcept
{
const uint8_t* p{static_cast<const uint8_t*>(buffer)};
return (static_cast<uint32_t>(p[0]) << 8U) + static_cast<uint32_t>(p[1]);
}
template<>
inline uint32_t read_big_endian_unaligned<uint32_t>(const void* buffer) noexcept
{
const uint8_t* p{static_cast<const uint8_t*>(buffer)};
return (static_cast<uint32_t>(p[0]) << 24U) + (static_cast<uint32_t>(p[1]) << 16U) +
(static_cast<uint32_t>(p[2]) << 8U) + static_cast<uint32_t>(p[3]);
}
template<>
inline size_t read_big_endian_unaligned<size_t>(const void* buffer) noexcept
{
static_assert(sizeof(size_t) == sizeof(uint32_t), "wasm32 only");
return read_big_endian_unaligned<uint32_t>(buffer);
}
#else
template<typename T>
T read_big_endian_unaligned(const void* buffer) noexcept
{
return byte_swap(read_unaligned<T>(buffer));
}
#endif
inline void skip_bytes(byte_span& stream_info, const size_t count) noexcept
{

View File

@ -17,7 +17,7 @@ TEST_CLASS(golomb_table_test)
public:
TEST_METHOD(golomb_table_create) // NOLINT
{
const golomb_code_table golomb_table;
constexpr golomb_code_table golomb_table;
for (uint32_t i{}; i != 256U; i++)
{