| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316 |
- //-------------------------------------------------------------------------------------------------------
- // Copyright (C) Microsoft Corporation and contributors. All rights reserved.
- // Licensed under the MIT license. See LICENSE.txt file in the project root for full license information.
- //-------------------------------------------------------------------------------------------------------
- #include "WasmReaderPch.h"
- #ifdef ENABLE_WASM
- namespace Wasm
- {
- WasmSignature::WasmSignature() :
- m_id(Js::Constants::UninitializedValue),
- m_paramSize(Js::Constants::InvalidArgSlot),
- m_params(nullptr),
- m_paramsCount(0),
- m_shortSig(Js::Constants::InvalidSignature)
- {
- }
- void WasmSignature::AllocateParams(Js::ArgSlot count, Recycler * recycler)
- {
- if (GetParamCount() != 0)
- {
- throw WasmCompilationException(_u("Invalid call to WasmSignature::AllocateParams: Params are already allocated"));
- }
- if (count > 0)
- {
- m_params = RecyclerNewArrayLeafZ(recycler, Local, count);
- }
- m_paramsCount = count;
- }
- void WasmSignature::SetParam(WasmTypes::WasmType type, Js::ArgSlot index)
- {
- if (index >= GetParamCount())
- {
- throw WasmCompilationException(_u("Parameter %u out of range (max %u)"), index, GetParamCount());
- }
- m_params[index] = Local(type);
- }
- void WasmSignature::AllocateResults(uint32 count, Recycler * recycler)
- {
- if (GetResultCount() != 0)
- {
- throw WasmCompilationException(_u("Invalid call to WasmSignature::AllocateResults: Results are already allocated"));
- }
- if (count > 0)
- {
- m_results = RecyclerNewArrayLeafZ(recycler, WasmTypes::WasmType, count);
- }
- m_resultsCount = count;
- }
- void WasmSignature::SetResult(Local type, uint32 index)
- {
- if (index >= GetResultCount())
- {
- throw WasmCompilationException(_u("Result %u out of range (max %u)"), index, GetResultCount());
- }
- m_results[index] = type;
- }
- Wasm::Local WasmSignature::GetResult(uint32 index) const
- {
- if (index >= GetResultCount())
- {
- throw WasmCompilationException(_u("Result %u out of range (max %u)"), index, GetResultCount());
- }
- return m_results[index];
- }
- void WasmSignature::SetSignatureId(uint32 id)
- {
- Assert(m_id == Js::Constants::UninitializedValue);
- m_id = id;
- }
- Local WasmSignature::GetParam(Js::ArgSlot index) const
- {
- if (index >= GetParamCount())
- {
- throw WasmCompilationException(_u("Parameter %u out of range (max %u)"), index, GetParamCount());
- }
- return m_params[index];
- }
- Js::ArgSlot WasmSignature::GetParamCount() const
- {
- return m_paramsCount;
- }
- uint32 WasmSignature::GetSignatureId() const
- {
- return m_id;
- }
- size_t WasmSignature::GetShortSig() const
- {
- return m_shortSig;
- }
- template<bool useShortSig>
- bool WasmSignature::IsEquivalent(const WasmSignature* sig) const
- {
- if (useShortSig && m_shortSig != Js::Constants::InvalidSignature)
- {
- bool isEquivalent = sig->GetShortSig() == m_shortSig;
- Assert(this->IsEquivalent<false>(sig) == isEquivalent);
- return isEquivalent;
- }
- if (GetResultCount() == sig->GetResultCount() &&
- GetParamCount() == sig->GetParamCount() &&
- GetParamsSize() == sig->GetParamsSize())
- {
- return (
- (GetParamCount() == 0 || memcmp(m_params, sig->m_params, GetParamCount() * sizeof(Local)) == 0) &&
- (GetResultCount() == 0 || memcmp(m_results, sig->m_results, GetResultCount() * sizeof(Local)) == 0)
- );
- }
- return false;
- }
- template bool WasmSignature::IsEquivalent<true>(const WasmSignature*) const;
- template bool WasmSignature::IsEquivalent<false>(const WasmSignature*) const;
- Js::ArgSlot WasmSignature::GetParamSize(Js::ArgSlot index) const
- {
- switch (GetParam(index))
- {
- case WasmTypes::F32:
- case WasmTypes::I32:
- CompileAssert(sizeof(float) == sizeof(int32));
- #ifdef _M_X64
- // on x64, we always alloc (at least) 8 bytes per arguments
- return sizeof(void*);
- #elif _M_IX86
- return sizeof(int32);
- #else
- Assert(UNREACHED);
- #endif
- break;
- case WasmTypes::F64:
- case WasmTypes::I64:
- CompileAssert(sizeof(double) == sizeof(int64));
- return sizeof(int64);
- break;
- #ifdef ENABLE_WASM_SIMD
- case WasmTypes::V128:
- Wasm::Simd::EnsureSimdIsEnabled();
- CompileAssert(sizeof(Simd::simdvec) == 16);
- return sizeof(Simd::simdvec);
- break;
- #endif
- default:
- WasmTypes::CompileAssertCasesNoFailFast<WasmTypes::I32, WasmTypes::I64, WasmTypes::F32, WasmTypes::F64, WASM_V128_CHECK_TYPE>();
- throw WasmCompilationException(_u("Invalid param type"));
- }
- }
- void WasmSignature::FinalizeSignature()
- {
- if (GetResultCount() > 1)
- {
- // Do not support short signature with multiple returns at this time
- return;
- }
- Local resultType = GetResultCount() == 1 ? GetResult(0) : WasmTypes::Void;
- Assert(m_paramSize == Js::Constants::InvalidArgSlot);
- Assert(m_shortSig == Js::Constants::InvalidSignature);
- const Js::ArgSlot paramCount = GetParamCount();
- m_paramSize = 0;
- for (Js::ArgSlot i = 0; i < paramCount; ++i)
- {
- if (ArgSlotMath::Add(m_paramSize, GetParamSize(i), &m_paramSize))
- {
- throw WasmCompilationException(_u("Argument size too big"));
- }
- }
- // 3 bits for result type, 3 for each arg
- const uint32 nBitsForResult = 3;
- #ifdef ENABLE_WASM_SIMD
- const uint32 nBitsForArgs = 3;
- #else
- // We can drop 1 bit by excluding void
- const uint32 nBitsForArgs = 2;
- #endif
- CompileAssert(Local::Void == 0);
- // Make sure we can encode all types (including void) with the number of bits reserved
- CompileAssert(Local::Limit <= (1 << nBitsForResult));
- // Make sure we can encode all types (excluding void) with the number of bits reserved
- CompileAssert(Local::Limit - 1 <= (1 << nBitsForArgs));
- ::Math::RecordOverflowPolicy sigOverflow;
- const uint32 bitsRequiredForSig = UInt32Math::MulAdd<nBitsForArgs, nBitsForResult>((uint32)paramCount, sigOverflow);
- if (sigOverflow.HasOverflowed())
- {
- return;
- }
- // we don't need to reserve a sentinel bit because there is no result type with value of 7
- CompileAssert(Local::Limit <= 0b111);
- const uint32 nAvailableBits = sizeof(m_shortSig) * 8;
- if (bitsRequiredForSig <= nAvailableBits)
- {
- // Append the result type to the signature
- m_shortSig = (m_shortSig << nBitsForResult) | resultType;
- for (Js::ArgSlot i = 0; i < paramCount; ++i)
- {
- // Append the param type to the signature, -1 to exclude Void
- m_shortSig = (m_shortSig << nBitsForArgs) | (m_params[i] - 1);
- }
- }
- }
- Js::ArgSlot WasmSignature::GetParamsSize() const
- {
- return m_paramSize;
- }
- WasmSignature* WasmSignature::FromIDL(WasmSignatureIDL* sig)
- {
- // must update WasmSignatureIDL when changing WasmSignature
- CompileAssert(sizeof(Wasm::WasmSignature) == sizeof(WasmSignatureIDL));
- CompileAssert(offsetof(Wasm::WasmSignature, m_id) == offsetof(WasmSignatureIDL, id));
- CompileAssert(offsetof(Wasm::WasmSignature, m_resultsCount) == offsetof(WasmSignatureIDL, resultsCount));
- CompileAssert(offsetof(Wasm::WasmSignature, m_paramSize) == offsetof(WasmSignatureIDL, paramSize));
- CompileAssert(offsetof(Wasm::WasmSignature, m_paramsCount) == offsetof(WasmSignatureIDL, paramsCount));
- CompileAssert(offsetof(Wasm::WasmSignature, m_shortSig) == offsetof(WasmSignatureIDL, shortSig));
- CompileAssert(offsetof(Wasm::WasmSignature, m_params) == offsetof(WasmSignatureIDL, params));
- CompileAssert(offsetof(Wasm::WasmSignature, m_results) == offsetof(WasmSignatureIDL, results));
- CompileAssert(sizeof(Local) == sizeof(int));
- return reinterpret_cast<WasmSignature*>(sig);
- }
- uint32 WasmSignature::WriteSignatureToString(_Out_writes_(maxlen) char16* out, uint32 maxlen)
- {
- bool hasMultiResults = GetResultCount() > 1;
- const uint32 minEnd = GetResultCount() > 1 ? 20 : 12;
- AssertOrFailFast(maxlen > minEnd);
- AssertOrFailFast(out != nullptr);
- uint32 numwritten = 0;
- #define WRITE_BUF(msg, ...) numwritten += _snwprintf_s(out+numwritten, maxlen-numwritten, _TRUNCATE, msg, ##__VA_ARGS__);
- WRITE_BUF(_u("("));
- for (Js::ArgSlot i = 0; i < GetParamCount(); i++)
- {
- if (i != 0)
- {
- WRITE_BUF(_u(", "));
- }
- WRITE_BUF(_u("%ls"), WasmTypes::GetTypeName(this->GetParam(i)));
- }
- if (numwritten >= maxlen - minEnd) {
- // null out the last 12 characters so we can properly end it
- for (uint32 i = 1; i <= minEnd; i++)
- {
- *(out + maxlen - i) = 0;
- }
- if (numwritten < minEnd)
- {
- numwritten = 0;
- }
- else
- {
- numwritten -= minEnd;
- }
- WRITE_BUF(_u("..."));
- if (hasMultiResults)
- {
- // If the signature has multiple results, just print the first one then terminate.
- WRITE_BUF(_u(")->(%s, ...)"), WasmTypes::GetTypeName(this->GetResult(0)));
- return numwritten;
- }
- }
- if (GetResultCount() == 0)
- {
- WRITE_BUF(_u(")->void"));
- }
- else if (GetResultCount() == 1)
- {
- WRITE_BUF(_u(")->%ls"), WasmTypes::GetTypeName(this->GetResult(0)));
- }
- else
- {
- WRITE_BUF(_u(")->("));
- for (uint32 i = 0; i < GetResultCount(); i++)
- {
- if (i != 0)
- {
- WRITE_BUF(_u(", "));
- }
- WRITE_BUF(_u("%ls"), WasmTypes::GetTypeName(this->GetResult(i)));
- }
- WRITE_BUF(_u(")"));
- }
- #undef WRITE_BUF
- return numwritten;
- }
- void WasmSignature::Dump(uint32 maxlen)
- {
- #ifdef ENABLE_DEBUG_CONFIG_OPTIONS
- char16 buf[512] = { 0 };
- this->WriteSignatureToString(buf, min(maxlen, 512u));
- Output::Print(buf);
- #endif
- }
- } // namespace Wasm
- #endif // ENABLE_WASM
|