| //------------------------------------------------------------------------------------------------------- |
| // Copyright (C) Microsoft. All rights reserved. |
| // Licensed under the MIT license. See LICENSE.txt file in the project root for full license information. |
| //------------------------------------------------------------------------------------------------------- |
| #pragma once |
| |
| namespace Js { |
| |
| ///---------------------------------------------------------------------------- |
| /// |
| /// enum OpCode |
| /// |
| /// OpCode defines the set of p-code instructions available for byte-code. |
| /// |
| ///---------------------------------------------------------------------------- |
| |
| enum class OpCode : ushort |
| { |
| #define DEF_OP(x, y, ...) x, |
| #include "OpCodeList.h" |
| MaxByteSizedOpcodes = 255, |
| #include "ExtendedOpCodeList.h" |
| ByteCodeLast, |
| #if ENABLE_NATIVE_CODEGEN |
| #include "BackendOpCodeList.h" |
| #endif |
| #undef DEF_OP |
| Count // Number of operations |
| }; |
| |
| inline OpCode operator+(OpCode o1, OpCode o2) { return (OpCode)((uint)o1 + (uint)o2); } |
| inline uint operator+(OpCode o1, uint i) { return ((uint)o1 + i); } |
| inline uint operator+(uint i, OpCode &o2) { return (i + (uint)o2); } |
| inline OpCode operator++(OpCode &o) { return o = (OpCode)(o + 1U); } |
| inline OpCode operator++(OpCode &o, int) { OpCode prev_o = o; o = (OpCode)(o + 1U); return prev_o; } |
| inline OpCode operator-(OpCode o1, OpCode o2) { return (OpCode)((uint)o1 - (uint)o2); } |
| inline uint operator-(OpCode o1, uint i) { return ((uint)o1 - i); } |
| inline uint operator-(uint i, OpCode &o2) { return (i - (uint)o2); } |
| inline OpCode operator--(OpCode &o) { return o = (OpCode)(o - 1U); } |
| inline OpCode operator--(OpCode &o, int) { return o = (OpCode)(o - 1U); } |
| inline uint operator<<(OpCode o1, uint i) { return ((uint)o1 << i); } |
| inline OpCode& operator+=(OpCode &o, uint i) { return (o = (OpCode)(o + i)); } |
| inline OpCode& operator-=(OpCode &o, uint i) { return (o = (OpCode)(o - i)); } |
| inline bool operator==(OpCode &o, uint i) { return ((uint)(o) == i); } |
| inline bool operator==(uint i, OpCode &o) { return (i == (uint)(o)); } |
| inline bool operator!=(OpCode &o, uint i) { return ((uint)(o) != i); } |
| inline bool operator!=(uint i, OpCode &o) { return (i != (uint)(o)); } |
| inline bool operator<(OpCode &o, uint i) { return ((uint)(o) < i); } |
| inline bool operator<(uint i, OpCode &o) { return (i < (uint)(o)); } |
| inline bool operator>(OpCode &o, uint i) { return ((uint)(o) > i); } |
| inline bool operator>(uint i, OpCode &o) { return (i > (uint)(o)); } |
| |
| #if ENABLE_NATIVE_CODEGEN |
| inline bool IsSimd128Opcode(OpCode o) { return (o > Js::OpCode::Simd128_Start && o < Js::OpCode::Simd128_End) || (o > Js::OpCode::Simd128_Start_Extend && o < Js::OpCode::Simd128_End_Extend); } |
| inline uint Simd128OpcodeCount() { return (uint)(Js::OpCode::Simd128_End - Js::OpCode::Simd128_Start) + 1 + (uint)(Js::OpCode::Simd128_End_Extend - Js::OpCode::Simd128_Start_Extend) + 1; } |
| inline bool IsSimd128Load(OpCode o){ return o == Js::OpCode::Simd128_LdArr_I4 || o == Js::OpCode::Simd128_LdArr_F4; } |
| inline bool IsSimd128Store(OpCode o){ return o == Js::OpCode::Simd128_StArr_I4 || o == Js::OpCode::Simd128_StArr_F4; } |
| inline bool IsSimd128LoadStore(OpCode o) { return IsSimd128Load(o) || IsSimd128Store(o); } |
| #endif |
| |
| ///---------------------------------------------------------------------------- |
| /// |
| /// enum OpLayoutType |
| /// |
| /// OpLayoutType defines a set of layouts available for OpCodes. These layouts |
| /// correspond to "OpLayout" structs defined below, such as "OpLayoutReg1". |
| /// |
| ///---------------------------------------------------------------------------- |
| |
| BEGIN_ENUM_UINT(OpLayoutType) |
| // This define only one enum for each layout type, but not for each layout variant |
| #define LAYOUT_TYPE(x) x, |
| #define LAYOUT_TYPE_WMS LAYOUT_TYPE |
| #include "LayoutTypes.h" |
| Count, |
| END_ENUM_UINT() |
| |
| ///---------------------------------------------------------------------------- |
| /// |
| /// struct OpLayoutXYZ |
| /// |
| /// OpLayoutXYZ structs define the standard patterns used to layout each |
| /// OpCode's arguments. |
| /// |
| /// Set up packing: |
| /// - Since we are reading / writing from a byte-stream, and we want everything |
| /// to be tightly aligned with no unintended spaces, change to 'byte' |
| /// packing. |
| /// - On processors with alignment requirements, this will automatically |
| /// generate read / write code to handle 'unaligned' access. |
| /// |
| /// - 3/9/10: Changing the layouts to make all fields well-aligned. This involves |
| /// reducing the RegSlot from 4 bytes to 2, increasing the OpCode from 1 byte to 2, |
| /// reordering fields, and adding pads where appropriate. Note that we assume all |
| /// layouts are preceded by a 2-byte op. The orderings and padding will need to |
| /// be revisited for Win64. |
| /// |
| /// - 5/2: X86-64 alignment: Changing code to expect all opcode layout structs |
| /// to be aligned on 4 byte boundaries (on I386 and x86-64). This aligns all |
| /// members on their natural boundaries except for Call and Regex which require |
| /// padding before the pointers on x86-64. |
| /// |
| /// - 09/12: Adding one-byte RegSlot based OpLayout. These remove all the paddings to be |
| /// able to compress the size. Also remove paddings for non ARM build |
| /// |
| /// - 08/22/2011: Removed paddings for ARM & x64 as well as both support unaligned access |
| /// There is still paddings to make sure every opcode starts at 2 byte boundary to avoid |
| /// pathological cases. |
| /// Note: RegSlot is changed to 4 byte instead of 1 byte in this change. |
| /// |
| ///---------------------------------------------------------------------------- |
| |
| #pragma pack(push, 1) |
| |
| template <typename SizePolicy> |
| struct OpLayoutT_Reg1 // R0 <- op |
| { |
| typename SizePolicy::RegSlotType R0; |
| }; |
| |
| template <typename SizePolicy> |
| struct OpLayoutT_Reg1Unsigned1 // R0 <- op |
| { |
| typename SizePolicy::RegSlotType R0; |
| typename SizePolicy::UnsignedType C1; |
| }; |
| |
| template <typename SizePolicy> |
| struct OpLayoutT_Reg2 // R0 <- op R1 |
| { |
| typename SizePolicy::RegSlotType R0; |
| typename SizePolicy::RegSlotType R1; |
| }; |
| |
| template <typename SizePolicy> |
| struct OpLayoutT_Reg2WithICIndex : public OpLayoutT_Reg2<SizePolicy> |
| { |
| InlineCacheIndex inlineCacheIndex; |
| }; |
| |
| template <typename SizePolicy> |
| struct OpLayoutT_Reg3 // R0 <- R1 op R2 -- or -- R0 op R1 <- R2 |
| { |
| typename SizePolicy::RegSlotType R0; |
| typename SizePolicy::RegSlotType R1; |
| typename SizePolicy::RegSlotType R2; |
| }; |
| |
| template <typename SizePolicy> |
| struct OpLayoutT_Reg3C // R0 <- R1 op R2 with space for FastPath |
| { |
| typename SizePolicy::RegSlotType R0; |
| typename SizePolicy::RegSlotType R1; |
| typename SizePolicy::RegSlotType R2; |
| typename SizePolicy::CacheIdType inlineCacheIndex; |
| }; |
| |
| template <typename SizePolicy> |
| struct OpLayoutT_Reg2B1 |
| { |
| typename SizePolicy::RegSlotType R0; |
| typename SizePolicy::RegSlotType R1; |
| byte B2; |
| }; |
| |
| template <typename SizePolicy> |
| struct OpLayoutT_Reg3B1 |
| { |
| typename SizePolicy::RegSlotType R0; |
| typename SizePolicy::RegSlotType R1; |
| typename SizePolicy::RegSlotType R2; |
| byte B3; |
| }; |
| |
| template <typename SizePolicy> |
| struct OpLayoutT_Reg4 // R0 <- R1 op R2 op R3 |
| { |
| typename SizePolicy::RegSlotType R0; |
| typename SizePolicy::RegSlotType R1; |
| typename SizePolicy::RegSlotType R2; |
| typename SizePolicy::RegSlotType R3; |
| }; |
| |
| template <typename SizePolicy> |
| struct OpLayoutT_Reg5 // R0 <- R1 op R2 op R3 op R4 |
| { |
| typename SizePolicy::RegSlotType R0; |
| typename SizePolicy::RegSlotType R1; |
| typename SizePolicy::RegSlotType R2; |
| typename SizePolicy::RegSlotType R3; |
| typename SizePolicy::RegSlotType R4; |
| }; |
| |
| template <typename SizePolicy> |
| struct OpLayoutT_ArgNoSrc // OutArg |
| { |
| typename SizePolicy::ArgSlotType Arg; |
| }; |
| |
| template <typename SizePolicy> |
| struct OpLayoutT_Arg // OutArg <- Reg -- or -- Reg <- InArg |
| { |
| typename SizePolicy::ArgSlotType Arg; |
| typename SizePolicy::RegSlotType Reg; |
| }; |
| |
| struct OpLayoutBr // goto Offset |
| { |
| JumpOffset RelativeJumpOffset; |
| }; |
| |
| struct OpLayoutBrS // if (op val) goto Offset |
| { |
| JumpOffset RelativeJumpOffset; |
| byte val; |
| }; |
| |
| template <typename SizePolicy> |
| struct OpLayoutT_BrReg1 // if (op R1) goto Offset |
| { |
| JumpOffset RelativeJumpOffset; |
| typename SizePolicy::RegSlotType R1; |
| }; |
| |
| template <typename SizePolicy> |
| struct OpLayoutT_BrReg1Unsigned1 |
| { |
| JumpOffset RelativeJumpOffset; |
| typename SizePolicy::RegSlotType R1; |
| typename SizePolicy::RegSlotType C2; |
| }; |
| |
| template <typename SizePolicy> |
| struct OpLayoutT_BrReg2 // if (R1 op R2) goto Offset |
| { |
| JumpOffset RelativeJumpOffset; |
| typename SizePolicy::RegSlotType R1; |
| typename SizePolicy::RegSlotType R2; |
| }; |
| |
| struct OpLayoutBrProperty // if (R1.id) goto Offset |
| { |
| JumpOffset RelativeJumpOffset; |
| RegSlot Instance; |
| PropertyIdIndexType PropertyIdIndex; |
| }; |
| |
| struct OpLayoutBrLocalProperty // if (id) goto Offset |
| { |
| JumpOffset RelativeJumpOffset; |
| PropertyIdIndexType PropertyIdIndex; |
| }; |
| |
| struct OpLayoutBrEnvProperty // if ([1].id) goto Offset |
| { |
| JumpOffset RelativeJumpOffset; |
| PropertyIdIndexType PropertyIdIndex; |
| int32 SlotIndex; |
| }; |
| |
| #ifdef BYTECODE_BRANCH_ISLAND |
| struct OpLayoutBrLong |
| { |
| LongJumpOffset RelativeJumpOffset; |
| }; |
| #endif |
| |
| struct OpLayoutStartCall |
| { |
| ArgSlot ArgCount; |
| }; |
| |
| enum CallIExtendedOptions : byte |
| { |
| CallIExtended_None = 0, |
| CallIExtended_SpreadArgs = 1 << 0 // This call has arguments that need to be spread |
| }; |
| |
| template <typename SizePolicy> |
| struct OpLayoutT_CallI // Return = Function(ArgCount) |
| { |
| typename SizePolicy::ArgSlotType ArgCount; |
| typename SizePolicy::RegSlotSType Return; |
| typename SizePolicy::RegSlotType Function; |
| }; |
| |
| template <typename SizePolicy> |
| struct OpLayoutT_CallIExtended : public OpLayoutT_CallI<SizePolicy> |
| { |
| CallIExtendedOptions Options; |
| uint32 SpreadAuxOffset; // Valid with Options & CallIExtended_SpreadArgs |
| }; |
| |
| template <typename SizePolicy> |
| struct OpLayoutT_CallIFlags : public OpLayoutT_CallI<SizePolicy> |
| { |
| CallFlags callFlags; |
| }; |
| |
| template <typename SizePolicy> |
| struct OpLayoutT_CallIWithICIndex : public OpLayoutT_CallI<SizePolicy> |
| { |
| InlineCacheIndex inlineCacheIndex; |
| }; |
| |
| template <typename SizePolicy> |
| struct OpLayoutT_CallIFlagsWithICIndex : public OpLayoutT_CallIWithICIndex<SizePolicy> |
| { |
| CallFlags callFlags; |
| }; |
| |
| template <typename SizePolicy> |
| struct OpLayoutT_CallIExtendedFlags : public OpLayoutT_CallIExtended<SizePolicy> |
| { |
| CallFlags callFlags; |
| }; |
| |
| template <typename SizePolicy> |
| struct OpLayoutT_CallIExtendedWithICIndex : public OpLayoutT_CallIExtended<SizePolicy> |
| { |
| InlineCacheIndex inlineCacheIndex; |
| }; |
| |
| template <typename SizePolicy> |
| struct OpLayoutT_CallIExtendedFlagsWithICIndex : public OpLayoutT_CallIExtendedWithICIndex<SizePolicy> |
| { |
| CallFlags callFlags; |
| }; |
| |
| template <typename SizePolicy> |
| struct OpLayoutT_Class // class _ extends Extends { Constructor(...) { ... } } |
| { |
| typename SizePolicy::RegSlotType Constructor; |
| typename SizePolicy::RegSlotSType Extends; |
| }; |
| |
| template <typename SizePolicy> |
| struct OpLayoutT_ElementU // Instance.PropertyIndex = <some constant value>. e.g. undefined |
| { |
| typename SizePolicy::RegSlotType Instance; |
| typename SizePolicy::PropertyIdIndexType PropertyIdIndex; |
| }; |
| |
| template <typename SizePolicy> |
| struct OpLayoutT_ElementScopedU // [env].PropertyIndex = <some constant value>. e.g. undefined |
| { |
| typename SizePolicy::PropertyIdIndexType PropertyIdIndex; |
| }; |
| |
| template <typename SizePolicy> |
| struct OpLayoutT_ElementRootU // Root.PropertyIndex = <some constant value>. e.g. undefined |
| { |
| typename SizePolicy::PropertyIdIndexType PropertyIdIndex; |
| }; |
| |
| template <typename SizePolicy> |
| struct OpLayoutT_ElementC // Value = Instance.PropertyIndex or Instance.PropertyIndex = Value |
| { |
| typename SizePolicy::RegSlotType Value; |
| typename SizePolicy::RegSlotType Instance; |
| typename SizePolicy::PropertyIdIndexType PropertyIdIndex; |
| }; |
| |
| template <typename SizePolicy> |
| struct OpLayoutT_ElementScopedC // Value = [env].PropertyIndex or [env].PropertyIndex = Value |
| { |
| typename SizePolicy::RegSlotType Value; |
| typename SizePolicy::PropertyIdIndexType PropertyIdIndex; |
| }; |
| |
| template <typename SizePolicy> |
| struct OpLayoutT_ElementSlot // Value = Instance[SlotIndex] or Instance[SlotIndex] = Value |
| { |
| int32 SlotIndex; // TODO: Make this one byte? |
| typename SizePolicy::RegSlotType Value; |
| typename SizePolicy::RegSlotType Instance; |
| }; |
| |
| template <typename SizePolicy> |
| struct OpLayoutT_ElementSlotI1 |
| { |
| int32 SlotIndex; // TODO: Make this one byte? |
| typename SizePolicy::RegSlotType Value; |
| }; |
| |
| template <typename SizePolicy> |
| struct OpLayoutT_ElementSlotI2 |
| { |
| int32 SlotIndex1; // TODO: Make this one byte? |
| int32 SlotIndex2; // TODO: Make this one byte? |
| typename SizePolicy::RegSlotType Value; |
| }; |
| |
| template <typename SizePolicy> |
| struct OpLayoutT_ElementCP // As OpLayoutElementC, with space for a FastPath LoadPatch |
| { |
| typename SizePolicy::RegSlotType Value; |
| typename SizePolicy::RegSlotType Instance; |
| typename SizePolicy::CacheIdType inlineCacheIndex; |
| }; |
| |
| template <typename SizePolicy> |
| struct OpLayoutT_ElementP // As OpLayoutElementCP, but with no base pointer |
| { |
| typename SizePolicy::RegSlotType Value; |
| typename SizePolicy::CacheIdType inlineCacheIndex; |
| }; |
| |
| template <typename SizePolicy> |
| struct OpLayoutT_ElementPIndexed // As OpLayoutElementCP, but with scope index instead of base pointer |
| { |
| typename SizePolicy::RegSlotType Value; |
| typename SizePolicy::CacheIdType inlineCacheIndex; |
| typename SizePolicy::UnsignedType scopeIndex; |
| }; |
| |
| template <typename SizePolicy> |
| struct OpLayoutT_ElementRootCP // Same as ElementCP, but for root object |
| { |
| RootCacheId inlineCacheIndex; |
| typename SizePolicy::RegSlotType Value; |
| }; |
| |
| template <typename SizePolicy> |
| struct OpLayoutT_ElementScopedC2 // [implied base].PropertyIndex = Value, Instance2 |
| { |
| typename SizePolicy::RegSlotType Value; |
| typename SizePolicy::RegSlotType Value2; |
| typename SizePolicy::PropertyIdIndexType PropertyIdIndex; |
| }; |
| |
| template <typename SizePolicy> |
| struct OpLayoutT_ElementC2 // Instance.PropertyIndex = Value, Instance2 |
| { |
| typename SizePolicy::RegSlotType Value; |
| typename SizePolicy::RegSlotType Instance; |
| typename SizePolicy::RegSlotType Value2; |
| typename SizePolicy::PropertyIdIndexType PropertyIdIndex; |
| }; |
| |
| template <typename SizePolicy> |
| struct OpLayoutT_ElementI // Value = Instance[Element] or Instance[Element] = Value |
| { |
| typename SizePolicy::RegSlotType Value; |
| typename SizePolicy::RegSlotType Instance; |
| typename SizePolicy::RegSlotType Element; |
| }; |
| |
| template <typename SizePolicy> |
| struct OpLayoutT_ElementUnsigned1 // Value = Instance[Element] or Instance[Element] = Value |
| { |
| typename SizePolicy::UnsignedType Element; |
| typename SizePolicy::RegSlotType Value; |
| typename SizePolicy::RegSlotType Instance; |
| }; |
| |
| struct OpLayoutW1 |
| { |
| unsigned short C1; |
| }; |
| |
| struct OpLayoutReg1Int2 // R0 <- Var(C1, C2) |
| { |
| RegSlot R0; |
| int32 C1; |
| int32 C2; |
| }; |
| |
| template <typename SizePolicy> |
| struct OpLayoutT_Reg2Int1 // R0 <- func(R1, C1) |
| { |
| int32 C1; |
| typename SizePolicy::RegSlotType R0; |
| typename SizePolicy::RegSlotType R1; |
| }; |
| |
| struct OpLayoutAuxNoReg |
| { |
| uint32 Offset; |
| int32 C1; |
| }; |
| |
| struct OpLayoutAuxiliary : public OpLayoutAuxNoReg // R0 <- Load(Offset, C1) |
| { |
| RegSlot R0; |
| }; |
| |
| struct OpLayoutReg2Aux : public OpLayoutAuxiliary // R0 <- Load(Offset, R1, C1) |
| { |
| RegSlot R1; |
| }; |
| |
| template <typename SizePolicy> |
| struct OpLayoutT_Unsigned1 |
| { |
| typename SizePolicy::UnsignedType C1; |
| }; |
| |
| // Dynamic profile layout wrapper |
| template <typename LayoutType> |
| struct OpLayoutDynamicProfile : public LayoutType |
| { |
| ProfileId profileId; |
| }; |
| |
| template <typename LayoutType> |
| struct OpLayoutDynamicProfile2 : public LayoutType |
| { |
| ProfileId profileId; |
| ProfileId profileId2; |
| }; |
| |
| // Generate the multi size layout type defs |
| #define LAYOUT_TYPE_WMS(layout) \ |
| typedef OpLayoutT_##layout<LargeLayoutSizePolicy> OpLayout##layout##_Large; \ |
| typedef OpLayoutT_##layout<MediumLayoutSizePolicy> OpLayout##layout##_Medium; \ |
| typedef OpLayoutT_##layout<SmallLayoutSizePolicy> OpLayout##layout##_Small; |
| |
| // Generate the profiled type defs |
| #define LAYOUT_TYPE_PROFILED(layout) \ |
| typedef OpLayoutDynamicProfile<OpLayout##layout> OpLayoutProfiled##layout; |
| #define LAYOUT_TYPE_PROFILED2(layout) \ |
| typedef OpLayoutDynamicProfile2<OpLayout##layout> OpLayoutProfiled2##layout; |
| #define LAYOUT_TYPE_PROFILED_WMS(layout) \ |
| LAYOUT_TYPE_WMS(layout) \ |
| LAYOUT_TYPE_PROFILED(layout##_Large) \ |
| LAYOUT_TYPE_PROFILED(layout##_Medium) \ |
| LAYOUT_TYPE_PROFILED(layout##_Small) |
| #define LAYOUT_TYPE_PROFILED2_WMS(layout) \ |
| LAYOUT_TYPE_PROFILED_WMS(layout) \ |
| LAYOUT_TYPE_PROFILED2(layout##_Large) \ |
| LAYOUT_TYPE_PROFILED2(layout##_Medium) \ |
| LAYOUT_TYPE_PROFILED2(layout##_Small) |
| #include "LayoutTypes.h" |
| |
| #pragma pack(pop) |
| |
| // Generate structure to automatically map layout to its info |
| template <OpLayoutType::_E layout> struct OpLayoutInfo; |
| |
| #define LAYOUT_TYPE(layout) \ |
| CompileAssert(sizeof(OpLayout##layout) <= MaxLayoutSize); \ |
| template <> struct OpLayoutInfo<OpLayoutType::layout> \ |
| { \ |
| static const bool HasMultiSizeLayout = false; \ |
| }; |
| |
| #define LAYOUT_TYPE_WMS(layout) \ |
| CompileAssert(sizeof(OpLayout##layout##_Large) <= MaxLayoutSize); \ |
| template <> struct OpLayoutInfo<OpLayoutType::layout> \ |
| { \ |
| static const bool HasMultiSizeLayout = true; \ |
| }; |
| #include "LayoutTypes.h" |
| |
| // Generate structure to automatically map opcode to its info |
| // Also generate assert to make sure the layout and opcode use the same macro with and without multiple size layout |
| template <OpCode opcode> struct OpCodeInfo; |
| |
| #define DEFINE_OPCODEINFO(op, layout, extended) \ |
| CompileAssert(!OpLayoutInfo<OpLayoutType::layout>::HasMultiSizeLayout); \ |
| template <> struct OpCodeInfo<OpCode::op> \ |
| { \ |
| static const OpLayoutType::_E Layout = OpLayoutType::layout; \ |
| static const bool HasMultiSizeLayout = false; \ |
| static const bool IsExtendedOpcode = extended; \ |
| typedef OpLayout##layout LayoutType; \ |
| }; |
| #define DEFINE_OPCODEINFO_WMS(op, layout, extended) \ |
| CompileAssert(OpLayoutInfo<OpLayoutType::layout>::HasMultiSizeLayout); \ |
| template <> struct OpCodeInfo<OpCode::op> \ |
| { \ |
| static const OpLayoutType::_E Layout = OpLayoutType::layout; \ |
| static const bool HasMultiSizeLayout = true; \ |
| static const bool IsExtendedOpcode = extended; \ |
| typedef OpLayout##layout##_Large LayoutType_Large; \ |
| typedef OpLayout##layout##_Medium LayoutType_Medium; \ |
| typedef OpLayout##layout##_Small LayoutType_Small; \ |
| }; |
| #define MACRO(op, layout, ...) DEFINE_OPCODEINFO(op, layout, false) |
| #define MACRO_WMS(op, layout, ...) DEFINE_OPCODEINFO_WMS(op, layout, false) |
| #define MACRO_EXTEND(op, layout, ...) DEFINE_OPCODEINFO(op, layout, true) |
| #define MACRO_EXTEND_WMS(op, layout, ...) DEFINE_OPCODEINFO_WMS(op, layout, true) |
| #include "OpCodes.h" |
| #undef DEFINE_OPCODEINFO |
| #undef DEFINE_OPCODEINFO_WMS |
| |
| } // namespace Js |