blob: b1eecc0050f877fb1e5f65bb38eed82b4c0ed22c [file]
//-------------------------------------------------------------------------------------------------------
// Copyright (C) Microsoft. 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_resultType(WasmTypes::Void),
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 (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::SetResultType(WasmTypes::WasmType type)
{
Assert(m_resultType == WasmTypes::Void);
m_resultType = type;
}
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];
}
WasmTypes::WasmType WasmSignature::GetResultType() const
{
return m_resultType;
}
Js::ArgSlot WasmSignature::GetParamCount() const
{
return m_paramsCount;
}
uint32 WasmSignature::GetSignatureId() const
{
return m_id;
}
size_t WasmSignature::GetShortSig() const
{
return m_shortSig;
}
bool WasmSignature::IsEquivalent(const WasmSignature* sig) const
{
if (m_shortSig != Js::Constants::InvalidSignature)
{
return sig->GetShortSig() == m_shortSig;
}
if (GetResultType() == sig->GetResultType() &&
GetParamCount() == sig->GetParamCount() &&
GetParamsSize() == sig->GetParamsSize())
{
return GetParamCount() == 0 || memcmp(m_params, sig->m_params, GetParamCount() * sizeof(Local)) == 0;
}
return false;
}
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;
default:
throw WasmCompilationException(_u("Invalid param type"));
}
}
void WasmSignature::FinalizeSignature()
{
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"));
}
}
CompileAssert(Local::Limit - 1 <= 4);
CompileAssert(Local::Void == 0);
// 3 bits for result type, 2 for each arg
// we don't need to reserve a sentinel bit because there is no result type with value of 7
uint32 sigSize = ((uint32)paramCount) * 2 + 3;
if (sigSize <= sizeof(m_shortSig) << 3)
{
m_shortSig = (m_shortSig << 3) | m_resultType;
for (Js::ArgSlot i = 0; i < paramCount; ++i)
{
// we can use 2 bits per arg by dropping void
m_shortSig = (m_shortSig << 2) | (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_resultType) == offsetof(WasmSignatureIDL, resultType));
CompileAssert(offsetof(Wasm::WasmSignature, m_id) == offsetof(WasmSignatureIDL, id));
CompileAssert(offsetof(Wasm::WasmSignature, m_paramSize) == offsetof(WasmSignatureIDL, paramSize));
CompileAssert(offsetof(Wasm::WasmSignature, m_paramsCount) == offsetof(WasmSignatureIDL, paramsCount));
CompileAssert(offsetof(Wasm::WasmSignature, m_params) == offsetof(WasmSignatureIDL, params));
CompileAssert(offsetof(Wasm::WasmSignature, m_shortSig) == offsetof(WasmSignatureIDL, shortSig));
CompileAssert(sizeof(Local) == sizeof(int));
return reinterpret_cast<WasmSignature*>(sig);
}
uint32 WasmSignature::WriteSignatureToString(_Out_writes_(maxlen) char16* out, uint32 maxlen)
{
AssertOrFailFast(out != nullptr);
uint32 numwritten = 0;
numwritten += _snwprintf_s(out+numwritten, maxlen-numwritten, _TRUNCATE, _u("("));
for (Js::ArgSlot i = 0; i < this->GetParamCount(); i++)
{
if (i != 0)
{
numwritten += _snwprintf_s(out+numwritten, maxlen-numwritten, _TRUNCATE, _u(", "));
}
numwritten += _snwprintf_s(out+numwritten, maxlen-numwritten, _TRUNCATE, _u("%ls"), WasmTypes::GetTypeName(this->GetParam(i)));
}
if (numwritten >= maxlen-12) {
// null out the last 12 characters so we can properly end it
for (int i = 1; i <= 12; i++) {
*(out + maxlen - i) = 0;
}
numwritten -= 12;
numwritten += _snwprintf_s(out + numwritten, maxlen - numwritten, _TRUNCATE, _u("..."));
}
numwritten += _snwprintf_s(out + numwritten, maxlen - numwritten, _TRUNCATE, _u(")->%ls"), WasmTypes::GetTypeName(this->GetResultType()));
return numwritten;
}
void WasmSignature::Dump()
{
#ifdef ENABLE_DEBUG_CONFIG_OPTIONS
char16 buf[512] = { 0 };
this->WriteSignatureToString(buf, 512);
Output::Print(buf);
#endif
}
} // namespace Wasm
#endif // ENABLE_WASM