blob: 8b8d43c69bcc6b279da49f2e1ea7964062a99496 [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 "RuntimeByteCodePch.h"
namespace Js
{
bool OpCodeUtil::IsPrefixOpcode(OpCode op)
{
return op <= OpCode::ExtendedLargeLayoutPrefix && op != OpCode::EndOfBlock;
}
void OpCodeUtil::ConvertOpToNonProfiled(OpCode& op)
{
if (IsProfiledCallOp(op) || IsProfiledCallOpWithICIndex(op))
{
op = ConvertProfiledCallOpToNonProfiled(op);
}
else if (IsProfiledReturnTypeCallOp(op))
{
op = ConvertProfiledReturnTypeCallOpToNonProfiled(op);
}
else
{
ConvertNonCallOpToNonProfiled(op);
}
}
void OpCodeUtil::ConvertNonCallOpToProfiled(OpCode& op)
{
Assert(OpCodeAttr::HasProfiledOp(op));
op += 1;
Assert(OpCodeAttr::IsProfiledOp(op));
}
void OpCodeUtil::ConvertNonCallOpToProfiledWithICIndex(OpCode& op)
{
Assert(OpCodeAttr::HasProfiledOp(op) && OpCodeAttr::HasProfiledOpWithICIndex(op));
op += 2;
Assert(OpCodeAttr::IsProfiledOpWithICIndex(op));
}
void OpCodeUtil::ConvertNonCallOpToNonProfiled(OpCode& op)
{
if (OpCodeAttr::IsProfiledOp(op))
{
op -= 1;
Assert(OpCodeAttr::HasProfiledOp(op));
}
else if (OpCodeAttr::IsProfiledOpWithICIndex(op))
{
op -= 2;
Assert(OpCodeAttr::HasProfiledOpWithICIndex(op));
}
else
{
Assert(false);
}
}
bool OpCodeUtil::IsCallOp(OpCode op)
{
return op >= Js::OpCode::CallI && op <= Js::OpCode::CallIExtendedFlags;
}
bool OpCodeUtil::IsProfiledCallOp(OpCode op)
{
return op >= Js::OpCode::ProfiledCallI && op <= Js::OpCode::ProfiledCallIExtendedFlags;
}
bool OpCodeUtil::IsProfiledCallOpWithICIndex(OpCode op)
{
return op >= Js::OpCode::ProfiledCallIWithICIndex && op <= Js::OpCode::ProfiledCallIExtendedFlagsWithICIndex;
}
bool OpCodeUtil::IsProfiledConstructorCall(OpCode op)
{
return ((op >= Js::OpCode::NewScObject && op <= Js::OpCode::ProfiledNewScObjArraySpread) || op == Js::OpCode::ProfiledNewScObjectSpread) && (OpCodeAttr::IsProfiledOp(op) || OpCodeAttr::IsProfiledOpWithICIndex(op));
}
bool OpCodeUtil::IsProfiledReturnTypeCallOp(OpCode op)
{
return op >= Js::OpCode::ProfiledReturnTypeCallI && op <= Js::OpCode::ProfiledReturnTypeCallIExtendedFlags;
}
#if DBG
OpCode OpCodeUtil::DebugConvertProfiledCallToNonProfiled(OpCode op)
{
switch (op)
{
case Js::OpCode::ProfiledCallI:
case Js::OpCode::ProfiledCallIWithICIndex:
return Js::OpCode::CallI;
case Js::OpCode::ProfiledCallIFlags:
case Js::OpCode::ProfiledCallIFlagsWithICIndex:
return Js::OpCode::CallIFlags;
case Js::OpCode::ProfiledCallIExtendedFlags:
case Js::OpCode::ProfiledCallIExtendedFlagsWithICIndex:
return Js::OpCode::CallIExtendedFlags;
case Js::OpCode::ProfiledCallIExtended:
case Js::OpCode::ProfiledCallIExtendedWithICIndex:
return Js::OpCode::CallIExtended;
default:
Assert(false);
};
return Js::OpCode::Nop;
}
OpCode OpCodeUtil::DebugConvertProfiledReturnTypeCallToNonProfiled(OpCode op)
{
switch (op)
{
case Js::OpCode::ProfiledReturnTypeCallI:
return Js::OpCode::CallI;
case Js::OpCode::ProfiledReturnTypeCallIFlags:
return Js::OpCode::CallIFlags;
case Js::OpCode::ProfiledReturnTypeCallIExtendedFlags:
return Js::OpCode::CallIExtendedFlags;
case Js::OpCode::ProfiledReturnTypeCallIExtended:
return Js::OpCode::CallIExtended;
default:
Assert(false);
};
return Js::OpCode::Nop;
}
#endif
OpCode OpCodeUtil::ConvertProfiledCallOpToNonProfiled(OpCode op)
{
OpCode newOpcode;
if (IsProfiledCallOp(op))
{
newOpcode = (OpCode)(op - Js::OpCode::ProfiledCallI + Js::OpCode::CallI);
}
else if (IsProfiledCallOpWithICIndex(op))
{
newOpcode = (OpCode)(op - Js::OpCode::ProfiledCallIWithICIndex + Js::OpCode::CallI);
}
else
{
Assert(false);
__assume(false);
}
Assert(DebugConvertProfiledCallToNonProfiled(op) == newOpcode);
return newOpcode;
}
OpCode OpCodeUtil::ConvertProfiledReturnTypeCallOpToNonProfiled(OpCode op)
{
OpCode newOpcode;
if (IsProfiledReturnTypeCallOp(op))
{
newOpcode = (OpCode)(op - Js::OpCode::ProfiledReturnTypeCallI + Js::OpCode::CallI);
}
else
{
Assert(false);
__assume(false);
}
Assert(DebugConvertProfiledReturnTypeCallToNonProfiled(op) == newOpcode);
return newOpcode;
}
OpCode OpCodeUtil::ConvertCallOpToProfiled(OpCode op, bool withICIndex)
{
return (!withICIndex) ?
(OpCode)(op - OpCode::CallI + OpCode::ProfiledCallI) :
(OpCode)(op - OpCode::CallI + OpCode::ProfiledCallIWithICIndex);
}
OpCode OpCodeUtil::ConvertCallOpToProfiledReturnType(OpCode op)
{
return (OpCode)(op - OpCode::CallI + OpCode::ProfiledReturnTypeCallI);
}
CompileAssert(((int)Js::OpCode::CallIExtendedFlags - (int)Js::OpCode::CallI) == ((int)Js::OpCode::ProfiledCallIExtendedFlags - (int)Js::OpCode::ProfiledCallI));
CompileAssert(((int)Js::OpCode::CallIExtendedFlags - (int)Js::OpCode::CallI) == ((int)Js::OpCode::ProfiledReturnTypeCallIExtendedFlags - (int)Js::OpCode::ProfiledReturnTypeCallI));
CompileAssert(((int)Js::OpCode::CallIExtendedFlags - (int)Js::OpCode::CallI) == ((int)Js::OpCode::ProfiledCallIExtendedFlagsWithICIndex - (int)Js::OpCode::ProfiledCallIWithICIndex));
// Only include the opcode name on debug and test build
#if DBG_DUMP || ENABLE_DEBUG_CONFIG_OPTIONS
char16 const * const OpCodeUtil::OpCodeNames[] =
{
#define DEF_OP(x, y, ...) _u("") STRINGIZEW(x) _u(""),
#include "OpCodeList.h"
#undef DEF_OP
};
char16 const * const OpCodeUtil::ExtendedOpCodeNames[] =
{
#define DEF_OP(x, y, ...) _u("") STRINGIZEW(x) _u(""),
#include "ExtendedOpCodeList.h"
#undef DEF_OP
};
char16 const * const OpCodeUtil::BackendOpCodeNames[] =
{
#define DEF_OP(x, y, ...) _u("") STRINGIZEW(x) _u(""),
#include "BackendOpCodeList.h"
#undef DEF_OP
};
char16 const * OpCodeUtil::GetOpCodeName(OpCode op)
{
if (op <= Js::OpCode::MaxByteSizedOpcodes)
{
Assert((uint)op < _countof(OpCodeNames));
__analysis_assume((uint)op < _countof(OpCodeNames));
return OpCodeNames[(uint)op];
}
else if (op < Js::OpCode::ByteCodeLast)
{
uint opIndex = op - (Js::OpCode::MaxByteSizedOpcodes + 1);
Assert(opIndex < _countof(ExtendedOpCodeNames));
__analysis_assume(opIndex < _countof(ExtendedOpCodeNames));
return ExtendedOpCodeNames[opIndex];
}
uint opIndex = op - (Js::OpCode::ByteCodeLast + 1);
Assert(opIndex < _countof(BackendOpCodeNames));
__analysis_assume(opIndex < _countof(BackendOpCodeNames));
return BackendOpCodeNames[opIndex];
}
#else
wchar const * OpCodeUtil::GetOpCodeName(OpCode op)
{
return _u("<NotAvail>");
}
#endif
OpLayoutType const OpCodeUtil::OpCodeLayouts[] =
{
#define DEF_OP(x, y, ...) OpLayoutType::y,
#include "OpCodeList.h"
};
OpLayoutType const OpCodeUtil::ExtendedOpCodeLayouts[] =
{
#define DEF_OP(x, y, ...) OpLayoutType::y,
#include "ExtendedOpCodeList.h"
};
OpLayoutType const OpCodeUtil::BackendOpCodeLayouts[] =
{
#define DEF_OP(x, y, ...) OpLayoutType::y,
#include "BackendOpCodeList.h"
};
OpLayoutType OpCodeUtil::GetOpCodeLayout(OpCode op)
{
if ((uint)op <= (uint)Js::OpCode::MaxByteSizedOpcodes)
{
AnalysisAssert((uint)op < _countof(OpCodeLayouts));
return OpCodeLayouts[(uint)op];
}
else if (op < Js::OpCode::ByteCodeLast)
{
uint opIndex = op - (Js::OpCode::MaxByteSizedOpcodes + 1);
AnalysisAssert(opIndex < _countof(ExtendedOpCodeLayouts));
return ExtendedOpCodeLayouts[opIndex];
}
uint opIndex = op - (Js::OpCode::ByteCodeLast + 1);
AnalysisAssert(opIndex < _countof(BackendOpCodeLayouts));
return BackendOpCodeLayouts[opIndex];
}
bool OpCodeUtil::IsValidByteCodeOpcode(OpCode op)
{
CompileAssert((int)Js::OpCode::MaxByteSizedOpcodes + 1 + _countof(OpCodeUtil::ExtendedOpCodeLayouts) == (int)Js::OpCode::ByteCodeLast);
return (uint)op < _countof(OpCodeLayouts)
|| (op > Js::OpCode::MaxByteSizedOpcodes && op < Js::OpCode::ByteCodeLast);
}
bool OpCodeUtil::IsValidOpcode(OpCode op)
{
return IsValidByteCodeOpcode(op)
|| (op > Js::OpCode::ByteCodeLast && op < Js::OpCode::Count);
}
};