From 4fd19f8f15282699626b7436d5755d2b0546eec8 Mon Sep 17 00:00:00 2001 From: Seonghyun Kim Date: Wed, 16 Aug 2023 16:07:49 +0900 Subject: [PATCH 1/2] Assign frequently used constant value in code on stack Signed-off-by: Seonghyun Kim --- src/interpreter/ByteCode.h | 1 - src/parser/WASMParser.cpp | 265 ++++++++++++++++++++++++++++--------- src/runtime/Function.cpp | 7 +- src/runtime/Module.cpp | 63 ++++++++- src/runtime/Module.h | 13 +- src/runtime/Value.h | 7 + 6 files changed, 284 insertions(+), 72 deletions(-) diff --git a/src/interpreter/ByteCode.h b/src/interpreter/ByteCode.h index b7080d72c..c82913c93 100644 --- a/src/interpreter/ByteCode.h +++ b/src/interpreter/ByteCode.h @@ -637,7 +637,6 @@ class Const128 : public ByteCode { { printf("const128 "); DUMP_BYTECODE_OFFSET(dstOffset); - //printf("value: %" PRIu64, m_value); } #endif diff --git a/src/parser/WASMParser.cpp b/src/parser/WASMParser.cpp index a5394cf70..0443408ad 100644 --- a/src/parser/WASMParser.cpp +++ b/src/parser/WASMParser.cpp @@ -267,7 +267,8 @@ class WASMBinaryReader : public wabt::WASMBinaryReaderDelegate { , m_returnValueType(returnValueType) , m_position(0) , m_functionStackSizeSoFar(binaryReader.m_functionStackSizeSoFar) - , m_shouldRestoreVMStackAtEnd(false) + , m_shouldRestoreVMStackAtEnd((m_returnValueType.IsIndex() && binaryReader.m_result.m_functionTypes[m_returnValueType]->result().size()) + || m_returnValueType != Type::Void) , m_byteCodeGenerationStopped(false) { if (returnValueType.IsIndex() && binaryReader.m_result.m_functionTypes[returnValueType]->param().size()) { @@ -276,14 +277,14 @@ class WASMBinaryReader : public wabt::WASMBinaryReaderDelegate { auto endIter = binaryReader.m_vmStack.rbegin() + param.size(); auto iter = binaryReader.m_vmStack.rbegin(); while (iter != endIter) { - if (iter->hasValidLocalIndex()) { + if (iter->position() != iter->nonOptimizedPosition()) { binaryReader.generateMoveCodeIfNeeds(iter->position(), iter->nonOptimizedPosition(), iter->valueType()); iter->setPosition(iter->nonOptimizedPosition()); - if (binaryReader.m_inPreprocess) { + if (binaryReader.m_preprocessData.m_inPreprocess && iter->hasValidLocalIndex()) { size_t pos = *binaryReader.m_readerOffsetPointer; - auto localVariableIter = binaryReader.m_localVariableUsage.rbegin(); + auto localVariableIter = binaryReader.m_preprocessData.m_localVariableUsage.rbegin(); while (true) { - ASSERT(localVariableIter != binaryReader.m_localVariableUsage.rend()); + ASSERT(localVariableIter != binaryReader.m_preprocessData.m_localVariableUsage.rend()); if (localVariableIter->m_localIndex == iter->localIndex() && localVariableIter->m_endPosition == std::numeric_limits::max()) { localVariableIter->m_endPosition = *binaryReader.m_readerOffsetPointer; @@ -328,9 +329,9 @@ class WASMBinaryReader : public wabt::WASMBinaryReaderDelegate { LocalVariableUsage& findNearestUsage(size_t localIndex) { size_t pos = *m_readerOffsetPointer; - auto iter = m_localVariableUsage.rbegin(); + auto iter = m_preprocessData.m_localVariableUsage.rbegin(); while (true) { - ASSERT(iter != m_localVariableUsage.rend()); + ASSERT(iter != m_preprocessData.m_localVariableUsage.rend()); if (iter->m_localIndex == localIndex) { if (iter->m_startPosition <= pos) { return *iter; @@ -341,9 +342,62 @@ class WASMBinaryReader : public wabt::WASMBinaryReaderDelegate { ASSERT_NOT_REACHED(); } - bool m_inPreprocess; - std::vector m_localVariableUsage; + struct ProprocessData { + bool m_inPreprocess; + std::vector m_localVariableUsage; + std::vector> m_constantData; + ProprocessData() + : m_inPreprocess(false) + { + } + + void clear() + { + m_localVariableUsage.clear(); + m_constantData.clear(); + } + + void addConstantData(const Walrus::Value& v) + { + ASSERT(m_inPreprocess); + bool found = false; + for (size_t i = 0; i < m_constantData.size(); i++) { + if (m_constantData[i].first == v) { + m_constantData[i].second++; + found = true; + break; + } + } + if (!found) { + m_constantData.push_back(std::make_pair(v, 1)); + } + +#ifndef WALRUS_ASSIGN_CONSTANT_ON_STACK_MAX_COUNT +#define WALRUS_ASSIGN_CONSTANT_ON_STACK_MAX_COUNT 6 +#endif + constexpr size_t maxConstantData = WALRUS_ASSIGN_CONSTANT_ON_STACK_MAX_COUNT; + if (m_constantData.size() > maxConstantData) { + organizeConstantData(); + m_constantData.erase(m_constantData.end() - maxConstantData / 4, m_constantData.end()); + } + } + + void organizeConstantData() + { + std::sort(m_constantData.begin(), m_constantData.end(), + [](const std::pair& a, const std::pair& b) -> bool { + return a.second > b.second; + }); + } + void organizeData() + { + organizeConstantData(); + } + + } m_preprocessData; + + bool m_inInitExpr; Walrus::ModuleFunction* m_currentFunction; Walrus::FunctionType* m_currentFunctionType; uint32_t m_initialFunctionStackSize; @@ -397,7 +451,7 @@ class WASMBinaryReader : public wabt::WASMBinaryReaderDelegate { void pushVMStack(Walrus::Value::Type type, size_t pos, size_t localIndex = std::numeric_limits::max()) { - if (m_inPreprocess) { + if (m_preprocessData.m_inPreprocess) { if (localIndex != std::numeric_limits::max()) { size_t pushCount = 0; for (const auto& stack : m_vmStack) { @@ -405,7 +459,7 @@ class WASMBinaryReader : public wabt::WASMBinaryReaderDelegate { pushCount++; } } - m_localVariableUsage.push_back(LocalVariableUsage(localIndex, *m_readerOffsetPointer, pushCount)); + m_preprocessData.m_localVariableUsage.push_back(LocalVariableUsage(localIndex, *m_readerOffsetPointer, pushCount)); } } @@ -424,12 +478,12 @@ class WASMBinaryReader : public wabt::WASMBinaryReaderDelegate { m_functionStackSizeSoFar -= Walrus::valueStackAllocatedSize(info.valueType()); m_vmStack.pop_back(); - if (m_inPreprocess) { + if (m_preprocessData.m_inPreprocess) { if (info.hasValidLocalIndex()) { size_t pos = *m_readerOffsetPointer; - auto iter = m_localVariableUsage.rbegin(); + auto iter = m_preprocessData.m_localVariableUsage.rbegin(); while (true) { - ASSERT(iter != m_localVariableUsage.rend()); + ASSERT(iter != m_preprocessData.m_localVariableUsage.rend()); if (iter->m_localIndex == info.localIndex() && iter->m_endPosition == std::numeric_limits::max()) { iter->m_endPosition = *m_readerOffsetPointer; @@ -453,7 +507,7 @@ class WASMBinaryReader : public wabt::WASMBinaryReaderDelegate { return m_vmStack.back().position(); } - const VMStackInfo& peekVMStackInfo() + VMStackInfo& peekVMStackInfo() { return m_vmStack.back(); } @@ -463,8 +517,9 @@ class WASMBinaryReader : public wabt::WASMBinaryReaderDelegate { return m_vmStack.back().valueType(); } - void beginFunction(Walrus::ModuleFunction* mf) + void beginFunction(Walrus::ModuleFunction* mf, bool inInitExpr) { + m_inInitExpr = inInitExpr; m_currentFunction = mf; m_currentFunctionType = mf->functionType(); m_localInfo.clear(); @@ -472,7 +527,7 @@ class WASMBinaryReader : public wabt::WASMBinaryReaderDelegate { for (size_t i = 0; i < m_currentFunctionType->param().size(); i++) { m_localInfo.push_back(LocalInfo(m_currentFunctionType->param()[i])); } - m_initialFunctionStackSize = m_functionStackSizeSoFar = m_currentFunctionType->paramStackSize(); + m_currentFunction->m_requiredStackSizeDueToParameterAndLocal = m_initialFunctionStackSize = m_functionStackSizeSoFar = m_currentFunctionType->paramStackSize(); m_lastByteCodePosition = 0; m_currentFunction->m_requiredStackSize = std::max( m_currentFunction->m_requiredStackSize, m_functionStackSizeSoFar); @@ -531,7 +586,7 @@ class WASMBinaryReader : public wabt::WASMBinaryReaderDelegate { , m_readerDataPointer(nullptr) , m_codeStartOffset(0) , m_codeEndOffset(0) - , m_inPreprocess(false) + , m_inInitExpr(false) , m_currentFunction(nullptr) , m_currentFunctionType(nullptr) , m_initialFunctionStackSize(0) @@ -687,7 +742,7 @@ class WASMBinaryReader : public wabt::WASMBinaryReaderDelegate { virtual void BeginElemSegmentInitExpr(Index index) override { - beginFunction(new Walrus::ModuleFunction(Walrus::Store::getDefaultFunctionType(Walrus::Value::I32))); + beginFunction(new Walrus::ModuleFunction(Walrus::Store::getDefaultFunctionType(Walrus::Value::I32)), true); } virtual void EndElemSegmentInitExpr(Index index) override @@ -750,7 +805,7 @@ class WASMBinaryReader : public wabt::WASMBinaryReaderDelegate { virtual void BeginDataSegment(Index index, Index memoryIndex, uint8_t flags) override { ASSERT(index == m_result.m_datas.size()); - beginFunction(new Walrus::ModuleFunction(Walrus::Store::getDefaultFunctionType(Walrus::Value::I32))); + beginFunction(new Walrus::ModuleFunction(Walrus::Store::getDefaultFunctionType(Walrus::Value::I32)), true); } virtual void BeginDataSegmentInitExpr(Index index) override @@ -804,7 +859,7 @@ class WASMBinaryReader : public wabt::WASMBinaryReaderDelegate { auto ft = Walrus::Store::getDefaultFunctionType(m_result.m_globalTypes[index]->type()); Walrus::ModuleFunction* mf = new Walrus::ModuleFunction(ft); m_result.m_globalTypes[index]->setFunction(mf); - beginFunction(mf); + beginFunction(mf, true); } virtual void EndGlobalInitExpr(Index index) override @@ -840,7 +895,7 @@ class WASMBinaryReader : public wabt::WASMBinaryReaderDelegate { virtual void BeginFunctionBody(Index index, Offset size) override { ASSERT(m_currentFunction == nullptr); - beginFunction(m_result.m_functions[index]); + beginFunction(m_result.m_functions[index], false); } virtual void OnLocalDeclCount(Index count) override @@ -858,7 +913,7 @@ class WASMBinaryReader : public wabt::WASMBinaryReaderDelegate { auto sz = Walrus::valueStackAllocatedSize(wType); m_initialFunctionStackSize += sz; m_functionStackSizeSoFar += sz; - m_currentFunction->m_requiredStackSizeDueToLocal += sz; + m_currentFunction->m_requiredStackSizeDueToParameterAndLocal += sz; count--; } m_currentFunction->m_requiredStackSize = std::max( @@ -874,13 +929,29 @@ class WASMBinaryReader : public wabt::WASMBinaryReaderDelegate { virtual void OnStartPreprocess() override { - m_inPreprocess = true; - m_localVariableUsage.clear(); + m_preprocessData.m_inPreprocess = true; + m_preprocessData.clear(); } virtual void OnEndPreprocess() override { - m_inPreprocess = false; + m_preprocessData.m_inPreprocess = false; + m_preprocessData.organizeData(); + + uint8_t constantBuffer[16]; + for (size_t i = 0; i < m_preprocessData.m_constantData.size(); i++) { + size_t siz = Walrus::valueStackAllocatedSize(m_preprocessData.m_constantData[i].first.type()); + m_initialFunctionStackSize += siz; + memset(constantBuffer, 0, sizeof(constantBuffer)); + m_preprocessData.m_constantData[i].first.writeToMemory(constantBuffer); + for (size_t i = 0; i < siz; i++) { + m_currentFunction->m_constantData.pushBack(constantBuffer[i]); + } +#if !defined(NDEBUG) + m_currentFunction->m_constantDebugData.pushBack(m_preprocessData.m_constantData[i].first); +#endif + } + m_skipValidationUntil = *m_readerOffsetPointer - 1; m_shouldContinueToGenerateByteCode = true; @@ -890,6 +961,8 @@ class WASMBinaryReader : public wabt::WASMBinaryReaderDelegate { m_catchInfo.clear(); m_functionStackSizeSoFar = m_initialFunctionStackSize; + m_currentFunction->m_requiredStackSize = std::max( + m_currentFunction->m_requiredStackSize, m_functionStackSizeSoFar); m_lastByteCodePosition = 0; m_vmStack.clear(); } @@ -947,28 +1020,63 @@ class WASMBinaryReader : public wabt::WASMBinaryReaderDelegate { } } + bool processConstValue(const Walrus::Value& value) + { + if (!m_inInitExpr) { + if (m_preprocessData.m_inPreprocess) { + m_preprocessData.addConstantData(value); + } else { + 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); + return true; + } + pos += Walrus::valueStackAllocatedSize(m_preprocessData.m_constantData[i].first.type()); + } + } + } + return false; + } + + virtual void OnI32ConstExpr(uint32_t value) override { + if (processConstValue(Walrus::Value(Walrus::Value::Type::I32, reinterpret_cast(&value)))) { + return; + } pushByteCode(Walrus::Const32(computeExprResultPosition(Walrus::Value::Type::I32), value), WASMOpcode::I32ConstOpcode); } virtual void OnI64ConstExpr(uint64_t value) override { + if (processConstValue(Walrus::Value(Walrus::Value::Type::I64, reinterpret_cast(&value)))) { + return; + } pushByteCode(Walrus::Const64(computeExprResultPosition(Walrus::Value::Type::I64), value), WASMOpcode::I64ConstOpcode); } virtual void OnF32ConstExpr(uint32_t value) override { + if (processConstValue(Walrus::Value(Walrus::Value::Type::F32, reinterpret_cast(&value)))) { + return; + } pushByteCode(Walrus::Const32(computeExprResultPosition(Walrus::Value::Type::F32), value), WASMOpcode::F32ConstOpcode); } virtual void OnF64ConstExpr(uint64_t value) override { + if (processConstValue(Walrus::Value(Walrus::Value::Type::F64, reinterpret_cast(&value)))) { + return; + } pushByteCode(Walrus::Const64(computeExprResultPosition(Walrus::Value::Type::F64), value), WASMOpcode::F64ConstOpcode); } virtual void OnV128ConstExpr(uint8_t* value) override { + if (processConstValue(Walrus::Value(Walrus::Value::Type::V128, value))) { + return; + } pushByteCode(Walrus::Const128(computeExprResultPosition(Walrus::Value::Type::V128), value), WASMOpcode::V128ConstOpcode); } @@ -992,7 +1100,7 @@ class WASMBinaryReader : public wabt::WASMBinaryReaderDelegate { size_t computeExprResultPosition(Walrus::Value::Type type) { - if (!m_inPreprocess) { + if (!m_preprocessData.m_inPreprocess) { // if there is local.set code ahead, // we can use local variable position as expr target position auto localSetInfo = readAheadLocalGetIfExists(); @@ -1040,7 +1148,7 @@ class WASMBinaryReader : public wabt::WASMBinaryReaderDelegate { bool canUseDirectReference = true; size_t pos = *m_readerOffsetPointer; - for (const auto& r : m_localVariableUsage) { + for (const auto& r : m_preprocessData.m_localVariableUsage) { if (r.m_localIndex == localIndex && r.m_startPosition <= pos && pos <= r.m_endPosition) { if (r.m_hasWriteUsage) { canUseDirectReference = false; @@ -1060,10 +1168,10 @@ class WASMBinaryReader : public wabt::WASMBinaryReaderDelegate { void updateWriteUsageOfLocalIfNeeds(Index localIndex) { - if (m_inPreprocess) { + if (m_preprocessData.m_inPreprocess) { size_t pos = *m_readerOffsetPointer; - auto iter = m_localVariableUsage.begin(); - while (iter != m_localVariableUsage.end()) { + auto iter = m_preprocessData.m_localVariableUsage.begin(); + while (iter != m_preprocessData.m_localVariableUsage.end()) { if (localIndex == iter->m_localIndex && iter->m_startPosition <= pos && pos <= iter->m_endPosition) { iter->m_hasWriteUsage = true; @@ -1204,44 +1312,45 @@ class WASMBinaryReader : public wabt::WASMBinaryReaderDelegate { m_functionStackSizeSoFar = blockInfo.m_functionStackSizeSoFar; } - void restoreVMStackRegardToPartOfBlockEnd(const BlockInfo& blockInfo) + void keepBlockResultsIfNeeds(BlockInfo& blockInfo) { - if (blockInfo.m_shouldRestoreVMStackAtEnd) { - restoreVMStackBy(blockInfo); - } else if (blockInfo.m_returnValueType.IsIndex()) { - auto ft = m_result.m_functionTypes[blockInfo.m_returnValueType]; - if (ft->param().size()) { - restoreVMStackBy(blockInfo); - } else { - const auto& result = ft->result(); - for (size_t i = 0; i < result.size(); i++) { - ASSERT(peekVMStackValueType() == result[result.size() - i - 1]); - popVMStack(); - } - } - } else if (blockInfo.m_returnValueType != Type::Void) { - ASSERT(peekVMStackValueType() == toValueKind(blockInfo.m_returnValueType)); - popVMStack(); - } + auto dropSize = dropStackValuesBeforeBrIfNeeds(0); + keepBlockResultsIfNeeds(blockInfo, dropSize); } - void keepSubResultsIfNeeds() + void keepBlockResultsIfNeeds(BlockInfo& blockInfo, const std::pair& dropSize) { - BlockInfo& blockInfo = m_blockInfo.back(); - if ((blockInfo.m_returnValueType.IsIndex() && m_result.m_functionTypes[blockInfo.m_returnValueType]->result().size()) - || blockInfo.m_returnValueType != Type::Void) { - blockInfo.m_shouldRestoreVMStackAtEnd = true; - auto dropSize = dropStackValuesBeforeBrIfNeeds(0); + if (blockInfo.m_shouldRestoreVMStackAtEnd) { if (dropSize.second) { generateMoveValuesCodeRegardToDrop(dropSize); } + + if (!blockInfo.m_byteCodeGenerationStopped) { + if (blockInfo.m_returnValueType.IsIndex()) { + auto ft = m_result.m_functionTypes[blockInfo.m_returnValueType]; + const auto& result = ft->result(); + for (size_t i = 0; i < result.size(); i++) { + ASSERT(peekVMStackValueType() == result[result.size() - i - 1]); + auto info = peekVMStackInfo(); + generateMoveCodeIfNeeds(info.position(), info.nonOptimizedPosition(), info.valueType()); + info.setPosition(info.nonOptimizedPosition()); + popVMStack(); + } + } else if (blockInfo.m_returnValueType != Type::Void) { + ASSERT(peekVMStackValueType() == toValueKind(blockInfo.m_returnValueType)); + auto info = peekVMStackInfo(); + generateMoveCodeIfNeeds(info.position(), info.nonOptimizedPosition(), info.valueType()); + info.setPosition(info.nonOptimizedPosition()); + popVMStack(); + } + } } } virtual void OnElseExpr() override { - keepSubResultsIfNeeds(); BlockInfo& blockInfo = m_blockInfo.back(); + keepBlockResultsIfNeeds(blockInfo); ASSERT(blockInfo.m_blockType == BlockInfo::IfElse); blockInfo.m_jumpToEndBrInfo.erase(blockInfo.m_jumpToEndBrInfo.begin()); @@ -1252,7 +1361,7 @@ class WASMBinaryReader : public wabt::WASMBinaryReaderDelegate { } blockInfo.m_byteCodeGenerationStopped = false; - restoreVMStackRegardToPartOfBlockEnd(blockInfo); + restoreVMStackBy(blockInfo); m_currentFunction->peekByteCode(blockInfo.m_position) ->setOffset(m_currentFunction->currentByteCodeSize() - blockInfo.m_position); } @@ -1460,6 +1569,17 @@ class WASMBinaryReader : public wabt::WASMBinaryReaderDelegate { auto dropSize = dropStackValuesBeforeBrIfNeeds(depth); if (dropSize.second) { generateMoveValuesCodeRegardToDrop(dropSize); + } else if (blockInfo.m_blockType == BlockInfo::Loop && blockInfo.m_returnValueType.IsIndex() && m_result.m_functionTypes[blockInfo.m_returnValueType]->param().size()) { + size_t pos = m_currentFunction->currentByteCodeSize(); + + auto ft = m_result.m_functionTypes[blockInfo.m_returnValueType]; + const auto& param = ft->param(); + for (size_t i = 0; i < param.size(); i++) { + ASSERT((m_vmStack.rbegin() + i)->valueType() == param[param.size() - i - 1]); + auto info = m_vmStack.rbegin() + i; + generateMoveCodeIfNeeds(info->position(), info->nonOptimizedPosition(), info->valueType()); + info->setPosition(info->nonOptimizedPosition()); + } } if (blockInfo.m_blockType != BlockInfo::Loop) { ASSERT(blockInfo.m_blockType == BlockInfo::Block || blockInfo.m_blockType == BlockInfo::IfElse || blockInfo.m_blockType == BlockInfo::TryCatch); @@ -1494,6 +1614,28 @@ class WASMBinaryReader : public wabt::WASMBinaryReaderDelegate { size_t pos = m_currentFunction->currentByteCodeSize(); pushByteCode(Walrus::JumpIfFalse(stackPos), WASMOpcode::BrIfOpcode); generateMoveValuesCodeRegardToDrop(dropSize); + + auto offset = (int32_t)blockInfo.m_position - (int32_t)m_currentFunction->currentByteCodeSize(); + if (blockInfo.m_blockType != BlockInfo::Loop) { + ASSERT(blockInfo.m_blockType == BlockInfo::Block || blockInfo.m_blockType == BlockInfo::IfElse || blockInfo.m_blockType == BlockInfo::TryCatch); + blockInfo.m_jumpToEndBrInfo.push_back({ BlockInfo::JumpToEndBrInfo::IsJump, m_currentFunction->currentByteCodeSize() }); + } + pushByteCode(Walrus::Jump(offset), WASMOpcode::BrIfOpcode); + m_currentFunction->peekByteCode(pos) + ->setOffset(m_currentFunction->currentByteCodeSize() - pos); + } else if (blockInfo.m_blockType == BlockInfo::Loop && blockInfo.m_returnValueType.IsIndex() && m_result.m_functionTypes[blockInfo.m_returnValueType]->param().size()) { + size_t pos = m_currentFunction->currentByteCodeSize(); + pushByteCode(Walrus::JumpIfFalse(stackPos), WASMOpcode::BrIfOpcode); + + auto ft = m_result.m_functionTypes[blockInfo.m_returnValueType]; + const auto& param = ft->param(); + for (size_t i = 0; i < param.size(); i++) { + ASSERT((m_vmStack.rbegin() + i)->valueType() == param[param.size() - i - 1]); + auto info = m_vmStack.rbegin() + i; + generateMoveCodeIfNeeds(info->position(), info->nonOptimizedPosition(), info->valueType()); + info->setPosition(info->nonOptimizedPosition()); + } + auto offset = (int32_t)blockInfo.m_position - (int32_t)m_currentFunction->currentByteCodeSize(); if (blockInfo.m_blockType != BlockInfo::Loop) { ASSERT(blockInfo.m_blockType == BlockInfo::Block || blockInfo.m_blockType == BlockInfo::IfElse || blockInfo.m_blockType == BlockInfo::TryCatch); @@ -1620,10 +1762,10 @@ class WASMBinaryReader : public wabt::WASMBinaryReaderDelegate { void processCatchExpr(Index tagIndex) { ASSERT(m_blockInfo.back().m_blockType == BlockInfo::TryCatch); - keepSubResultsIfNeeds(); auto& blockInfo = m_blockInfo.back(); - restoreVMStackRegardToPartOfBlockEnd(blockInfo); + keepBlockResultsIfNeeds(blockInfo); + restoreVMStackBy(blockInfo); size_t tryEnd = m_currentFunction->currentByteCodeSize(); if (m_catchInfo.size() && m_catchInfo.back().m_tryCatchBlockDepth == m_blockInfo.size()) { @@ -1887,10 +2029,9 @@ class WASMBinaryReader : public wabt::WASMBinaryReaderDelegate { return; } + keepBlockResultsIfNeeds(blockInfo, dropSize); + if (blockInfo.m_shouldRestoreVMStackAtEnd) { - if (dropSize.second) { - generateMoveValuesCodeRegardToDrop(dropSize); - } restoreVMStackBy(blockInfo); if (blockInfo.m_returnValueType.IsIndex()) { auto ft = m_result.m_functionTypes[blockInfo.m_returnValueType]; diff --git a/src/runtime/Function.cpp b/src/runtime/Function.cpp index 9dfa3c157..a7c21c35b 100644 --- a/src/runtime/Function.cpp +++ b/src/runtime/Function.cpp @@ -85,8 +85,13 @@ void DefinedFunction::call(ExecutionState& state, const uint32_t argc, Value* ar } // init local space - auto localSize = m_moduleFunction->requiredStackSizeDueToLocal(); + auto localSize = m_moduleFunction->requiredStackSizeDueToParameterAndLocal() + - m_moduleFunction->functionType()->paramStackSize(); memset(functionStackPointer, 0, localSize); + functionStackPointer += localSize; + + // init constant space + memcpy(functionStackPointer, m_moduleFunction->constantData(), m_moduleFunction->constantDataSize()); auto resultOffsets = Interpreter::interpret(newState, functionStackBase); diff --git a/src/runtime/Module.cpp b/src/runtime/Module.cpp index 8bd839ef2..6146267cc 100644 --- a/src/runtime/Module.cpp +++ b/src/runtime/Module.cpp @@ -33,7 +33,7 @@ namespace Walrus { ModuleFunction::ModuleFunction(FunctionType* functionType) : m_functionType(functionType) , m_requiredStackSize(std::max(m_functionType->paramStackSize(), m_functionType->resultStackSize())) - , m_requiredStackSizeDueToLocal(0) + , m_requiredStackSizeDueToParameterAndLocal(0) { } @@ -363,7 +363,7 @@ Instance* Module::instantiate(ExecutionState& state, const ExternVector& imports #if !defined(NDEBUG) -static const char* localTypeName(Value::Type v) +static const char* typeName(Value::Type v) { switch (v) { case Value::I32: @@ -385,18 +385,71 @@ static const char* localTypeName(Value::Type v) } } +static void dumpValue(Value v) +{ + switch (v.type()) { + case Value::I32: + printf("%" PRId32, v.asI32()); + break; + case Value::I64: + printf("%" PRId64, v.asI64()); + break; + case Value::F32: + printf("%f", v.asF32()); + break; + case Value::F64: + printf("%lf", v.asF64()); + break; + case Value::V128: + printf("%" PRIu8, v.asV128().m_data[0]); + printf(" %" PRIu8, v.asV128().m_data[1]); + printf(" %" PRIu8, v.asV128().m_data[2]); + printf(" %" PRIu8, v.asV128().m_data[3]); + printf(" %" PRIu8, v.asV128().m_data[4]); + printf(" %" PRIu8, v.asV128().m_data[5]); + printf(" %" PRIu8, v.asV128().m_data[6]); + printf(" %" PRIu8, v.asV128().m_data[7]); + printf(" %" PRIu8, v.asV128().m_data[8]); + printf(" %" PRIu8, v.asV128().m_data[9]); + printf(" %" PRIu8, v.asV128().m_data[10]); + printf(" %" PRIu8, v.asV128().m_data[11]); + printf(" %" PRIu8, v.asV128().m_data[12]); + printf(" %" PRIu8, v.asV128().m_data[13]); + printf(" %" PRIu8, v.asV128().m_data[14]); + printf(" %" PRIu8, v.asV128().m_data[15]); + break; + case Value::FuncRef: + break; + case Value::ExternRef: + break; + default: + RELEASE_ASSERT_NOT_REACHED(); + } + printf(", %s", typeName(v.type())); +} + void ModuleFunction::dumpByteCode() { printf("\n"); printf("required stack size: %u bytes\n", m_requiredStackSize); - printf("required stack size due to local: %u bytes\n", m_requiredStackSizeDueToLocal); + 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])); + pos += valueStackAllocatedSize(m_functionType->param()[i]); + } for (size_t i = 0; i < m_local.size(); i++) { - printf("%zu(local %zu, %s) ", pos, i, localTypeName(m_local[i])); + printf("%zu(local %zu, %s) ", pos, i, typeName(m_local[i])); pos += valueStackAllocatedSize(m_local[i]); } - printf("%zu(%" PRIu32 " bytes for general operation)]\n", pos, (m_requiredStackSize - m_requiredStackSizeDueToLocal)); + 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("%zu(%" PRIu32 " bytes for general operation)]\n", pos, (m_requiredStackSize - m_requiredStackSizeDueToParameterAndLocal)); printf("bytecode size: %zu bytes\n", m_byteCode.size()); printf("\n"); diff --git a/src/runtime/Module.h b/src/runtime/Module.h index d586bd97f..e0d1b87cf 100644 --- a/src/runtime/Module.h +++ b/src/runtime/Module.h @@ -177,7 +177,7 @@ class ModuleFunction { FunctionType* functionType() const { return m_functionType; } uint32_t requiredStackSize() const { return m_requiredStackSize; } - uint32_t requiredStackSizeDueToLocal() const { return m_requiredStackSizeDueToLocal; } + uint32_t requiredStackSizeDueToParameterAndLocal() const { return m_requiredStackSizeDueToParameterAndLocal; } template void pushByteCode(const CodeType& code) @@ -208,7 +208,9 @@ class ModuleFunction { return m_byteCode.size(); } - uint8_t* byteCode() { return m_byteCode.data(); } + const uint8_t* byteCode() const { return m_byteCode.data(); } + const uint8_t* constantData() const { return m_constantData.data(); } + size_t constantDataSize() const { return m_constantData.size(); } #if !defined(NDEBUG) void dumpByteCode(); #endif @@ -220,10 +222,15 @@ class ModuleFunction { private: FunctionType* m_functionType; + // m_requiredStackSize = m_requiredStackSizeDueToParameterAndLocal + constant space + general purpose space uint32_t m_requiredStackSize; - uint32_t m_requiredStackSizeDueToLocal; + uint32_t m_requiredStackSizeDueToParameterAndLocal; ValueTypeVector m_local; Vector> m_byteCode; + Vector> m_constantData; +#if !defined(NDEBUG) + Vector> m_constantDebugData; +#endif Vector> m_catchInfo; }; diff --git a/src/runtime/Value.h b/src/runtime/Value.h index eeacb451d..cc0a3ed3d 100644 --- a/src/runtime/Value.h +++ b/src/runtime/Value.h @@ -48,6 +48,11 @@ struct Vec128 { { } + bool operator==(const Vec128& src) const + { + return memcmp(m_data, src.m_data, 16) == 0; + } + float asF32(int lane) const { return to(lane); } uint32_t asF32Bits(int lane) const { return to(lane); } double asF64(int lane) const { return to(lane); } @@ -348,6 +353,8 @@ class Value { case FuncRef: case ExternRef: return m_ref == v.m_ref; + case V128: + return m_v128 == v.m_v128; default: ASSERT_NOT_REACHED(); break; From ec2b77b9353306592efd0b6e3ba09551aef2ddc4 Mon Sep 17 00:00:00 2001 From: Seonghyun Kim Date: Thu, 17 Aug 2023 11:25:56 +0900 Subject: [PATCH 2/2] Update benchmark.py to support various case of benchmark Signed-off-by: Seonghyun Kim --- test/wasmBenchmarker/benchmark.py | 52 ++++++++++++------------------- 1 file changed, 20 insertions(+), 32 deletions(-) diff --git a/test/wasmBenchmarker/benchmark.py b/test/wasmBenchmarker/benchmark.py index 58500a44b..818b835ab 100644 --- a/test/wasmBenchmarker/benchmark.py +++ b/test/wasmBenchmarker/benchmark.py @@ -50,8 +50,7 @@ def prepare_arg_pars(): const='./ctests', default='./ctests') parser.add_argument('--only-game', help='only run The Benchmarks Game tests', action='store_true') parser.add_argument('--run', metavar='TEST', help='only run one benchmark') - parser.add_argument('--walrus', metavar='PATH', help='path to the engine', nargs='?', const='./engines/walrus', - type=str) + parser.add_argument('--walrus', metavar='PATH', help='path to the engine', nargs='+', default=['walrus']) parser.add_argument('--report', metavar='PATH', help='path to the report', nargs='?', const='./report.md') parser.add_argument('--iterations', metavar='NUMBER', help='how many times run the tests', nargs='?', const='10', default=10, type=int) @@ -64,9 +63,11 @@ def check_programs(walrus): print("git not found") exit(1) - if walrus is not None and os.path.isfile(walrus) is False: - print("walrus not found") - exit(1) + for w in walrus: + path = w.split(" ")[0] + if os.path.isfile(path) is False: + print(path + " not found") + exit(1) print("Checks done") @@ -116,24 +117,6 @@ def compile_tests(path, only_game=False, compile_anyway=False, run=None): return test_names - -def run_walrus_jit(engine, path, name): - if not os.path.exists(path): - print("invalid path for walrus run") - exit(1) - - result = subprocess.check_output(engine + " --run-export runtime --jit " + path + "/wasm/" + name + ".wasm", - shell=True) - - if float(f'{float(result):.9f}') != float(expectedValues[name]): - print("walrus jit failed with " + name + ".wasm", file=sys.stderr) - print("Expected: " + str(expectedValues[name]), file=sys.stderr) - print("Got: " + str(result), file=sys.stderr) - return False - - return True - - def run_walrus(engine, path, name): if not os.path.exists(path): print("invalid path for walrus run") @@ -170,21 +153,26 @@ def run_tests(path, test_names, walrus, number_of_runs): ret_val = [] for name in test_names: print("running " + name) - measurements_walrus = [] - measurements_walrus_jit = [] + measurements_walrus = {} + for w in walrus: + measurements_walrus[w] = [] for i in range(0, number_of_runs): print("round " + str(i + 1)) - measurements_walrus.append(measure_time(path, name, run_walrus, walrus)) - measurements_walrus_jit.append(measure_time(path, name, run_walrus_jit, walrus)) + for w in walrus: + measurements_walrus[w].append(measure_time(path, name, run_walrus, w)) result_list = {"test": name} - min_walrus = min(measurements_walrus) - min_walrus_jit = min(measurements_walrus_jit) - result_list["walrus [s]"] = "{:.3f}".format(min_walrus / 1000000000) + " ({:.3f}x)".format(1) - result_list["walrus-jit [s]"] = "{:.3f}".format(min_walrus_jit / 1000000000) + " ({:.3f}x)".format( - (min_walrus / min_walrus_jit)) + min_walrus_first = False + min_walrus = {} + for w in walrus: + min_walrus[w] = min(measurements_walrus[w]) + if min_walrus_first is False: + min_walrus_first = min_walrus[w] + + for w in walrus: + result_list[w + " [s]"] = "{:.3f}".format(min_walrus[w] / 1000000000) + " ({:.3f}x)".format((min_walrus[w] / min_walrus_first)) ret_val.append(result_list)