From 4096f549e7ae2dd5d5708d725fae019d4c89a01a Mon Sep 17 00:00:00 2001 From: Seonghyun Kim Date: Tue, 29 Aug 2023 15:01:28 +0900 Subject: [PATCH 1/3] When computing local position, use pre-computed value Signed-off-by: Seonghyun Kim --- src/parser/WASMParser.cpp | 88 +++++++++++---------------------------- 1 file changed, 24 insertions(+), 64 deletions(-) diff --git a/src/parser/WASMParser.cpp b/src/parser/WASMParser.cpp index 877e5ac99..550d41c20 100644 --- a/src/parser/WASMParser.cpp +++ b/src/parser/WASMParser.cpp @@ -485,8 +485,10 @@ class WASMBinaryReader : public wabt::WASMBinaryReaderDelegate { std::vector m_catchInfo; struct LocalInfo { Walrus::Value::Type m_valueType; - LocalInfo(Walrus::Value::Type type) + size_t m_position; + LocalInfo(Walrus::Value::Type type, size_t position) : m_valueType(type) + , m_position(position) { } }; @@ -586,8 +588,10 @@ class WASMBinaryReader : public wabt::WASMBinaryReaderDelegate { m_currentFunctionType = mf->functionType(); m_localInfo.clear(); m_localInfo.reserve(m_currentFunctionType->param().size()); + size_t pos = 0; for (size_t i = 0; i < m_currentFunctionType->param().size(); i++) { - m_localInfo.push_back(LocalInfo(m_currentFunctionType->param()[i])); + m_localInfo.push_back(LocalInfo(m_currentFunctionType->param()[i], pos)); + pos += Walrus::valueStackAllocatedSize(m_localInfo[i].m_valueType); } m_currentFunction->m_requiredStackSizeDueToParameterAndLocal = m_initialFunctionStackSize = m_functionStackSizeSoFar = m_currentFunctionType->paramStackSize(); m_currentFunction->m_requiredStackSize = std::max( @@ -969,7 +973,7 @@ class WASMBinaryReader : public wabt::WASMBinaryReaderDelegate { while (count) { auto wType = toValueKind(type); m_currentFunction->m_local.push_back(wType); - m_localInfo.push_back(LocalInfo(wType)); + m_localInfo.push_back(LocalInfo(wType, m_functionStackSizeSoFar)); auto sz = Walrus::valueStackAllocatedSize(wType); m_initialFunctionStackSize += sz; m_functionStackSizeSoFar += sz; @@ -1010,17 +1014,18 @@ class WASMBinaryReader : public wabt::WASMBinaryReaderDelegate { // init local if needs for (size_t i = m_currentFunctionType->param().size(); i < m_localInfo.size(); i++) { if (m_preprocessData.m_localVariableInfo[i].m_needsExplicitInitOnStartup) { - auto r = resolveLocalOffsetAndSize(i); - if (r.second == 4) { - pushByteCode(Walrus::Const32(r.first, 0), WASMOpcode::I32ConstOpcode); - } else if (r.second == 8) { - pushByteCode(Walrus::Const64(r.first, 0), WASMOpcode::I64ConstOpcode); + auto localPos = m_localInfo[i].m_position; + auto size = Walrus::valueSize(m_localInfo[i].m_valueType); + if (size == 4) { + pushByteCode(Walrus::Const32(localPos, 0), WASMOpcode::I32ConstOpcode); + } else if (size == 8) { + pushByteCode(Walrus::Const64(localPos, 0), WASMOpcode::I64ConstOpcode); } else { - ASSERT(r.second == 16); + ASSERT(size == 16); uint8_t empty[16] = { 0, }; - pushByteCode(Walrus::Const128(r.first, empty), WASMOpcode::V128ConstOpcode); + pushByteCode(Walrus::Const128(localPos, empty), WASMOpcode::V128ConstOpcode); } } } @@ -1050,8 +1055,7 @@ class WASMBinaryReader : public wabt::WASMBinaryReaderDelegate { } m_functionStackSizeSoFar = m_initialFunctionStackSize; - m_currentFunction->m_requiredStackSize = std::max( - m_currentFunction->m_requiredStackSize, m_functionStackSizeSoFar); + m_currentFunction->m_requiredStackSize = m_functionStackSizeSoFar; } virtual void OnOpcode(uint32_t opcode) override @@ -1186,24 +1190,6 @@ class WASMBinaryReader : public wabt::WASMBinaryReaderDelegate { pushByteCode(Walrus::Const128(computeExprResultPosition(Walrus::Value::Type::V128), value), WASMOpcode::V128ConstOpcode); } - std::pair resolveLocalOffsetAndSize(Index localIndex) - { - if (localIndex < m_currentFunctionType->param().size()) { - size_t offset = 0; - for (Index i = 0; i < localIndex; i++) { - offset += Walrus::valueStackAllocatedSize(m_currentFunctionType->param()[i]); - } - return std::make_pair(offset, Walrus::valueSize(m_currentFunctionType->param()[localIndex])); - } else { - localIndex -= m_currentFunctionType->param().size(); - size_t offset = m_currentFunctionType->paramStackSize(); - for (Index i = 0; i < localIndex; i++) { - offset += Walrus::valueStackAllocatedSize(m_currentFunction->m_local[i]); - } - return std::make_pair(offset, Walrus::valueSize(m_currentFunction->m_local[localIndex])); - } - } - size_t computeExprResultPosition(Walrus::Value::Type type) { if (!m_preprocessData.m_inPreprocess) { @@ -1211,7 +1197,7 @@ class WASMBinaryReader : public wabt::WASMBinaryReaderDelegate { // we can use local variable position as expr target position auto localSetInfo = readAheadLocalGetIfExists(); if (localSetInfo.first) { - auto pos = resolveLocalOffsetAndSize(localSetInfo.first.value()).first; + auto pos = m_localInfo[localSetInfo.first.value()].m_position; // skip local.set opcode *m_readerOffsetPointer += localSetInfo.second; return pos; @@ -1221,35 +1207,9 @@ class WASMBinaryReader : public wabt::WASMBinaryReaderDelegate { return pushVMStack(type); } - Index resolveLocalIndexFromStackPosition(size_t pos) - { - ASSERT(pos < m_initialFunctionStackSize); - if (pos <= m_currentFunctionType->paramStackSize()) { - Index idx = 0; - size_t offset = 0; - while (true) { - if (offset == pos) { - return idx; - } - offset += Walrus::valueStackAllocatedSize(m_currentFunctionType->param()[idx]); - idx++; - } - } - pos -= m_currentFunctionType->paramStackSize(); - Index idx = 0; - size_t offset = 0; - while (true) { - if (offset == pos) { - return idx + m_currentFunctionType->param().size(); - } - offset += Walrus::valueStackAllocatedSize(m_currentFunction->m_local[idx]); - idx++; - } - } - virtual void OnLocalGetExpr(Index localIndex) override { - auto r = resolveLocalOffsetAndSize(localIndex); + auto localPos = m_localInfo[localIndex].m_position; auto localValueType = m_localInfo[localIndex].m_valueType; bool canUseDirectReference = true; @@ -1264,31 +1224,31 @@ class WASMBinaryReader : public wabt::WASMBinaryReaderDelegate { } if (canUseDirectReference) { - pushVMStack(localValueType, r.first, localIndex); + pushVMStack(localValueType, localPos, localIndex); } else { auto pos = m_functionStackSizeSoFar; pushVMStack(localValueType, pos, localIndex); - generateMoveCodeIfNeeds(r.first, pos, localValueType); + generateMoveCodeIfNeeds(localPos, pos, localValueType); } } virtual void OnLocalSetExpr(Index localIndex) override { - auto r = resolveLocalOffsetAndSize(localIndex); + auto localPos = m_localInfo[localIndex].m_position; ASSERT(m_localInfo[localIndex].m_valueType == peekVMStackValueType()); auto src = popVMStackInfo(); - generateMoveCodeIfNeeds(src.position(), r.first, src.valueType()); + generateMoveCodeIfNeeds(src.position(), localPos, src.valueType()); m_preprocessData.addLocalVariableWrite(localIndex); } virtual void OnLocalTeeExpr(Index localIndex) override { auto valueType = m_localInfo[localIndex].m_valueType; - auto r = resolveLocalOffsetAndSize(localIndex); + auto localPos = m_localInfo[localIndex].m_position; ASSERT(valueType == peekVMStackValueType()); auto dstInfo = peekVMStackInfo(); - generateMoveCodeIfNeeds(dstInfo.position(), r.first, valueType); + generateMoveCodeIfNeeds(dstInfo.position(), localPos, valueType); m_preprocessData.addLocalVariableWrite(localIndex); } From 78a7a4607d56c778ccfc39f74dd085d31e4d777f Mon Sep 17 00:00:00 2001 From: Seonghyun Kim Date: Tue, 29 Aug 2023 16:09:27 +0900 Subject: [PATCH 2/3] Use value size instead of stack allocated size for global get, set Signed-off-by: Seonghyun Kim --- src/interpreter/ByteCode.h | 6 ++++++ src/parser/WASMParser.cpp | 4 ++-- src/runtime/Value.h | 2 +- 3 files changed, 9 insertions(+), 3 deletions(-) diff --git a/src/interpreter/ByteCode.h b/src/interpreter/ByteCode.h index ae59ad96d..023012536 100644 --- a/src/interpreter/ByteCode.h +++ b/src/interpreter/ByteCode.h @@ -2037,6 +2037,7 @@ class GlobalGet32 : public ByteCode { void dump(size_t pos) { printf("global.get32 "); + DUMP_BYTECODE_OFFSET(dstOffset); printf("index: %" PRId32, m_index); } @@ -2063,6 +2064,7 @@ class GlobalGet64 : public ByteCode { void dump(size_t pos) { printf("global.get64 "); + DUMP_BYTECODE_OFFSET(dstOffset); printf("index: %" PRId32, m_index); } @@ -2089,6 +2091,7 @@ class GlobalGet128 : public ByteCode { void dump(size_t pos) { printf("global.get128 "); + DUMP_BYTECODE_OFFSET(dstOffset); printf("index: %" PRId32, m_index); } @@ -2115,6 +2118,7 @@ class GlobalSet32 : public ByteCode { void dump(size_t pos) { printf("global.set32 "); + DUMP_BYTECODE_OFFSET(srcOffset); printf("index: %" PRId32, m_index); } @@ -2141,6 +2145,7 @@ class GlobalSet64 : public ByteCode { void dump(size_t pos) { printf("global.set64 "); + DUMP_BYTECODE_OFFSET(srcOffset); printf("index: %" PRId32, m_index); } @@ -2167,6 +2172,7 @@ class GlobalSet128 : public ByteCode { void dump(size_t pos) { printf("global.set128 "); + DUMP_BYTECODE_OFFSET(srcOffset); printf("index: %" PRId32, m_index); } diff --git a/src/parser/WASMParser.cpp b/src/parser/WASMParser.cpp index 550d41c20..6f06e896f 100644 --- a/src/parser/WASMParser.cpp +++ b/src/parser/WASMParser.cpp @@ -1255,7 +1255,7 @@ class WASMBinaryReader : public wabt::WASMBinaryReaderDelegate { virtual void OnGlobalGetExpr(Index index) override { auto valueType = m_result.m_globalTypes[index]->type(); - auto sz = Walrus::valueStackAllocatedSize(valueType); + auto sz = Walrus::valueSize(valueType); auto stackPos = computeExprResultPosition(valueType); if (sz == 4) { pushByteCode(Walrus::GlobalGet32(stackPos, index), WASMOpcode::GlobalGetOpcode); @@ -1273,7 +1273,7 @@ class WASMBinaryReader : public wabt::WASMBinaryReaderDelegate { auto stackPos = peekVMStack(); ASSERT(peekVMStackValueType() == valueType); - auto sz = Walrus::valueStackAllocatedSize(valueType); + auto sz = Walrus::valueSize(valueType); if (sz == 4) { pushByteCode(Walrus::GlobalSet32(stackPos, index), WASMOpcode::GlobalSetOpcode); } else if (sz == 8) { diff --git a/src/runtime/Value.h b/src/runtime/Value.h index dc3267e95..6b7a2aa52 100644 --- a/src/runtime/Value.h +++ b/src/runtime/Value.h @@ -434,7 +434,7 @@ inline size_t valueFunctionCopyCount(Value::Type type) template inline void Value::readFromStack(uint8_t* ptr) { - ASSERT(valueStackAllocatedSize(m_type) == size); + ASSERT(valueSize(m_type) == size); if (size == 4) { m_i32 = *reinterpret_cast(ptr); } else if (size == 8) { From 1056db8c6f6a018649c84cec2ca773735d27c951 Mon Sep 17 00:00:00 2001 From: Seonghyun Kim Date: Fri, 1 Sep 2023 19:26:33 +0900 Subject: [PATCH 3/3] Implement packing local variable and constant data on 64-bit if stack usage is high Signed-off-by: Seonghyun Kim --- src/Walrus.h | 2 +- src/parser/WASMParser.cpp | 79 ++++++++++++++++++++++++++++++++------- src/runtime/Module.cpp | 17 ++++----- src/runtime/Module.h | 6 +-- src/runtime/Value.h | 24 ++++++++++++ 5 files changed, 100 insertions(+), 28 deletions(-) diff --git a/src/Walrus.h b/src/Walrus.h index 6cbd03ff7..409f38858 100755 --- a/src/Walrus.h +++ b/src/Walrus.h @@ -347,7 +347,7 @@ if (f.type == Type::B) { puts("failed in msvc."); } std::unique_ptr Result##HolderWhenUsingMalloc; \ size_t bytes##Result = (Bytes); \ Type* Result; \ - if (LIKELY(bytes##Result < 512)) { \ + if (LIKELY(bytes##Result < 2048)) { \ Result = (Type*)alloca(bytes##Result); \ } else { \ Result##HolderWhenUsingMalloc = std::unique_ptr(new uint8_t[bytes##Result]); \ diff --git a/src/parser/WASMParser.cpp b/src/parser/WASMParser.cpp index 6f06e896f..ca85478ae 100644 --- a/src/parser/WASMParser.cpp +++ b/src/parser/WASMParser.cpp @@ -464,6 +464,7 @@ class WASMBinaryReader : public wabt::WASMBinaryReaderDelegate { bool m_inPreprocess; WASMBinaryReader& m_reader; std::vector m_localVariableInfo; + // std::vector> m_constantData; }; @@ -593,7 +594,7 @@ class WASMBinaryReader : public wabt::WASMBinaryReaderDelegate { m_localInfo.push_back(LocalInfo(m_currentFunctionType->param()[i], pos)); pos += Walrus::valueStackAllocatedSize(m_localInfo[i].m_valueType); } - m_currentFunction->m_requiredStackSizeDueToParameterAndLocal = m_initialFunctionStackSize = m_functionStackSizeSoFar = m_currentFunctionType->paramStackSize(); + m_initialFunctionStackSize = m_functionStackSizeSoFar = m_currentFunctionType->paramStackSize(); m_currentFunction->m_requiredStackSize = std::max( m_currentFunction->m_requiredStackSize, m_functionStackSizeSoFar); } @@ -977,7 +978,6 @@ class WASMBinaryReader : public wabt::WASMBinaryReaderDelegate { auto sz = Walrus::valueStackAllocatedSize(wType); m_initialFunctionStackSize += sz; m_functionStackSizeSoFar += sz; - m_currentFunction->m_requiredStackSizeDueToParameterAndLocal += sz; count--; } m_currentFunction->m_requiredStackSize = std::max( @@ -1011,7 +1011,64 @@ class WASMBinaryReader : public wabt::WASMBinaryReaderDelegate { m_vmStack.clear(); m_preprocessData.organizeData(); - // init local if needs + + // set const variables position + for (size_t i = 0; i < m_preprocessData.m_constantData.size(); i++) { + auto constType = m_preprocessData.m_constantData[i].first.type(); + m_preprocessData.m_constantData[i].second = m_initialFunctionStackSize; + m_initialFunctionStackSize += Walrus::valueStackAllocatedSize(constType); + } + +#if defined(WALRUS_64) +#ifndef WALRUS_ENABLE_LOCAL_VARIABLE_PACKING_MIN_SIZE +#define WALRUS_ENABLE_LOCAL_VARIABLE_PACKING_MIN_SIZE 64 +#endif + // pack local variables if needs + constexpr size_t enableLocalVaraiblePackingMinSize = WALRUS_ENABLE_LOCAL_VARIABLE_PACKING_MIN_SIZE; + if (m_initialFunctionStackSize >= enableLocalVaraiblePackingMinSize) { + m_initialFunctionStackSize = m_currentFunctionType->paramStackSize(); + // put already aligned variables first + for (size_t i = m_currentFunctionType->param().size(); i < m_localInfo.size(); i++) { + auto& info = m_localInfo[i]; + if (Walrus::hasCPUWordAlignedSize(info.m_valueType) || needsCPUWordAlignedAddress(info.m_valueType)) { + info.m_position = m_initialFunctionStackSize; + m_initialFunctionStackSize += Walrus::valueStackAllocatedSize(info.m_valueType); + } + } + for (size_t i = 0; i < m_preprocessData.m_constantData.size(); i++) { + auto constType = m_preprocessData.m_constantData[i].first.type(); + if (Walrus::hasCPUWordAlignedSize(constType) || needsCPUWordAlignedAddress(constType)) { + m_preprocessData.m_constantData[i].second = m_initialFunctionStackSize; + m_initialFunctionStackSize += Walrus::valueStackAllocatedSize(constType); + } + } + + // pack rest values + for (size_t i = m_currentFunctionType->param().size(); i < m_localInfo.size(); i++) { + auto& info = m_localInfo[i]; + if (!Walrus::hasCPUWordAlignedSize(info.m_valueType) && !needsCPUWordAlignedAddress(info.m_valueType)) { + info.m_position = m_initialFunctionStackSize; + m_initialFunctionStackSize += Walrus::valueSize(info.m_valueType); + } + } + for (size_t i = 0; i < m_preprocessData.m_constantData.size(); i++) { + auto constType = m_preprocessData.m_constantData[i].first.type(); + if (!Walrus::hasCPUWordAlignedSize(constType) && !needsCPUWordAlignedAddress(constType)) { + m_preprocessData.m_constantData[i].second = m_initialFunctionStackSize; + m_initialFunctionStackSize += Walrus::valueSize(constType); + } + } + + if (m_initialFunctionStackSize % sizeof(size_t)) { + m_initialFunctionStackSize += (sizeof(size_t) - m_initialFunctionStackSize % sizeof(size_t)); + } + } +#endif + + m_functionStackSizeSoFar = m_initialFunctionStackSize; + m_currentFunction->m_requiredStackSize = m_functionStackSizeSoFar; + + // Explicit init local variable if needs for (size_t i = m_currentFunctionType->param().size(); i < m_localInfo.size(); i++) { if (m_preprocessData.m_localVariableInfo[i].m_needsExplicitInitOnStartup) { auto localPos = m_localInfo[i].m_position; @@ -1028,13 +1085,16 @@ class WASMBinaryReader : public wabt::WASMBinaryReaderDelegate { pushByteCode(Walrus::Const128(localPos, empty), WASMOpcode::V128ConstOpcode); } } +#if !defined(NDEBUG) + m_currentFunction->m_localDebugData.push_back(m_localInfo[i].m_position); +#endif } // init constant space for (size_t i = 0; i < m_preprocessData.m_constantData.size(); i++) { const auto& constValue = m_preprocessData.m_constantData[i].first; auto constType = m_preprocessData.m_constantData[i].first.type(); - auto constPos = m_initialFunctionStackSize; + auto constPos = m_preprocessData.m_constantData[i].second; size_t constSize = Walrus::valueSize(constType); uint8_t constantBuffer[16]; @@ -1047,15 +1107,10 @@ class WASMBinaryReader : public wabt::WASMBinaryReaderDelegate { ASSERT(constSize == 16); pushByteCode(Walrus::Const128(constPos, constantBuffer), WASMOpcode::V128ConstOpcode); } - - m_initialFunctionStackSize += Walrus::valueStackAllocatedSize(constType); #if !defined(NDEBUG) - m_currentFunction->m_constantDebugData.pushBack(m_preprocessData.m_constantData[i].first); + m_currentFunction->m_constantDebugData.pushBack(m_preprocessData.m_constantData[i]); #endif } - - m_functionStackSizeSoFar = m_initialFunctionStackSize; - m_currentFunction->m_requiredStackSize = m_functionStackSizeSoFar; } virtual void OnOpcode(uint32_t opcode) override @@ -1136,13 +1191,11 @@ class WASMBinaryReader : public wabt::WASMBinaryReaderDelegate { if (!m_inInitExpr) { m_preprocessData.addConstantData(value); if (!m_preprocessData.m_inPreprocess) { - size_t pos = m_currentFunction->m_requiredStackSizeDueToParameterAndLocal; for (size_t i = 0; i < m_preprocessData.m_constantData.size(); i++) { if (m_preprocessData.m_constantData[i].first == value) { - pushVMStack(value.type(), pos); + pushVMStack(value.type(), m_preprocessData.m_constantData[i].second); return true; } - pos += Walrus::valueStackAllocatedSize(m_preprocessData.m_constantData[i].first.type()); } } } diff --git a/src/runtime/Module.cpp b/src/runtime/Module.cpp index 446f1fe59..6f252fc9e 100644 --- a/src/runtime/Module.cpp +++ b/src/runtime/Module.cpp @@ -33,7 +33,6 @@ namespace Walrus { ModuleFunction::ModuleFunction(FunctionType* functionType) : m_functionType(functionType) , m_requiredStackSize(std::max(m_functionType->paramStackSize(), m_functionType->resultStackSize())) - , m_requiredStackSizeDueToParameterAndLocal(0) { } @@ -420,24 +419,22 @@ void ModuleFunction::dumpByteCode() { printf("\n"); printf("required stack size: %u bytes\n", m_requiredStackSize); - printf("required stack size due to parameter and local: %u bytes\n", m_requiredStackSizeDueToParameterAndLocal); printf("stack: ["); size_t pos = 0; for (size_t i = 0; i < m_functionType->param().size(); i++) { - printf("%zu(parameter %zu, %s) ", pos, i, typeName(m_functionType->param()[i])); + printf("(parameter %zu, %s, pos %zu) ", i, typeName(m_functionType->param()[i]), pos); pos += valueStackAllocatedSize(m_functionType->param()[i]); } for (size_t i = 0; i < m_local.size(); i++) { - printf("%zu(local %zu, %s) ", pos, i, typeName(m_local[i])); - pos += valueStackAllocatedSize(m_local[i]); + printf("(local %zu, %s, pos %zu) ", i, typeName(m_local[i]), m_localDebugData[i]); } for (size_t i = 0; i < m_constantDebugData.size(); i++) { - printf("%zu(constant ", pos); - dumpValue(m_constantDebugData[i]); - printf(") "); - pos += valueStackAllocatedSize(m_constantDebugData[i].type()); + printf("(constant "); + dumpValue(m_constantDebugData[i].first); + printf(", pos %zu) ", m_constantDebugData[i].second); } - printf("%zu(%" PRIu32 " bytes for general operation)]\n", pos, (m_requiredStackSize - m_requiredStackSizeDueToParameterAndLocal)); + printf("....]\n"); + printf("bytecode size: %zu bytes\n", m_byteCode.size()); printf("\n"); diff --git a/src/runtime/Module.h b/src/runtime/Module.h index 0f7c8dd57..1e7d2866f 100644 --- a/src/runtime/Module.h +++ b/src/runtime/Module.h @@ -177,7 +177,6 @@ class ModuleFunction { FunctionType* functionType() const { return m_functionType; } uint32_t requiredStackSize() const { return m_requiredStackSize; } - uint32_t requiredStackSizeDueToParameterAndLocal() const { return m_requiredStackSizeDueToParameterAndLocal; } template void pushByteCode(const CodeType& code) @@ -220,13 +219,12 @@ class ModuleFunction { private: FunctionType* m_functionType; - // m_requiredStackSize = m_requiredStackSizeDueToParameterAndLocal + constant space + general purpose space uint32_t m_requiredStackSize; - uint32_t m_requiredStackSizeDueToParameterAndLocal; ValueTypeVector m_local; Vector> m_byteCode; #if !defined(NDEBUG) - Vector> m_constantDebugData; + Vector> m_localDebugData; + Vector, std::allocator>> m_constantDebugData; #endif Vector> m_catchInfo; }; diff --git a/src/runtime/Value.h b/src/runtime/Value.h index 6b7a2aa52..fda4b98e1 100644 --- a/src/runtime/Value.h +++ b/src/runtime/Value.h @@ -431,6 +431,30 @@ inline size_t valueFunctionCopyCount(Value::Type type) return s; } +inline bool hasCPUWordAlignedSize(Value::Type type) +{ +#if defined(WALRUS_32) + ASSERT(valueStackAllocatedSize(type) == valueSize(type)); +#endif + return valueStackAllocatedSize(type) == valueSize(type); +} + +inline bool needsCPUWordAlignedAddress(Value::Type type) +{ +#if defined(WALRUS_32) + // everything is already aligned! + return false; +#else + switch (type) { + case Value::FuncRef: + case Value::ExternRef: + return true; + default: + return false; + } +#endif +} + template inline void Value::readFromStack(uint8_t* ptr) {