| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176 |
- //-------------------------------------------------------------------------------------------------------
- // 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
- #include "Language/JavascriptNativeOperators.h"
- class Func;
- class BasicBlock;
- class Region;
- class Lowerer;
- class IRBuilder;
- class IRBuilderAsmJs;
- class FlowGraph;
- class GlobOpt;
- class BailOutInfo;
- struct LazyBailOutRecord;
- typedef JsUtil::KeyValuePair<StackSym *, BailoutConstantValue> ConstantStackSymValue;
- typedef JsUtil::KeyValuePair<StackSym *, StackSym*> CopyPropSyms;
- struct CapturedValues
- {
- SListBase<ConstantStackSymValue> constantValues; // Captured constant values during glob opt
- SListBase<CopyPropSyms> copyPropSyms; // Captured copy prop values during glob opt
- BVSparse<JitArenaAllocator> * argObjSyms; // Captured arg object symbols during glob opt
- ~CapturedValues()
- {
- // Reset SListBase to be exception safe. Captured values are from GlobOpt->func->alloc
- // in normal case the 2 SListBase are empty so no Clear needed, also no need to Clear in exception case
- constantValues.Reset();
- copyPropSyms.Reset();
- }
- };
- class LoweredBasicBlock;
- class BranchJumpTableWrapper
- {
- public:
- BranchJumpTableWrapper(uint tableSize) : defaultTarget(nullptr), labelInstr(nullptr), tableSize(tableSize)
- {
- }
- void** jmpTable;
- void* defaultTarget;
- IR::LabelInstr * labelInstr;
- int tableSize;
- static BranchJumpTableWrapper* New(JitArenaAllocator * allocator, uint tableSize)
- {
- BranchJumpTableWrapper * branchTargets = JitAnew(allocator, BranchJumpTableWrapper, tableSize);
- //Create the jump table for integers
- void* * jmpTable = JitAnewArrayZ(allocator, void*, tableSize);
- branchTargets->jmpTable = jmpTable;
- return branchTargets;
- }
- };
- namespace IR {
- class EntryInstr;
- class ExitInstr;
- class BranchInstr;
- class LabelInstr;
- class JitProfilingInstr;
- class ProfiledInstr;
- class ProfiledLabelInstr;
- class MultiBranchInstr;
- class PragmaInstr;
- class ByteCodeUsesInstr;
- class Opnd;
- class RegOpnd;
- class IndirOpnd;
- class SymOpnd;
- class MemRefOpnd;
- class PropertySymOpnd;
- enum AddrOpndKind : BYTE;
- enum IRKind : BYTE {
- InstrKindInvalid,
- InstrKindInstr,
- InstrKindBranch,
- InstrKindLabel,
- InstrKindProfiled,
- InstrKindProfiledLabel,
- InstrKindEntry,
- InstrKindExit,
- InstrKindPragma,
- InstrKindByteCodeUses,
- InstrKindJitProfiling,
- };
- const int32 InvalidInstrLayout = -1;
- ///---------------------------------------------------------------------------
- ///
- /// class Instr
- /// BranchInstr
- /// MultiBranchInstr
- /// LabelInstr
- /// JitProfilingInstr
- /// ProfiledInstr
- /// EntryInstr
- /// ExitInstr
- /// PragmaInstr
- /// BailoutInstr
- /// ByteCoteUsesInstr
- ///
- ///---------------------------------------------------------------------------
- class Instr
- {
- protected:
- Instr(bool hasBailOutInfo = false) :
- m_next(nullptr),
- m_prev(nullptr),
- m_opcode(Js::OpCode::MaxByteSizedOpcodes),
- m_func(nullptr),
- m_number(Js::Constants::NoByteCodeOffset),
- m_dst(nullptr),
- m_src1(nullptr),
- m_src2(nullptr),
- #if DBG_DUMP
- globOptInstrString(nullptr),
- #endif
- #if _CONTROL_FLOW_GUARD_SHADOW_STACK
- isFsBased(false),
- #endif
- dstIsTempNumber(false),
- dstIsTempNumberTransferred(false),
- dstIsTempObject(false),
- isCloned(false),
- hasBailOutInfo(hasBailOutInfo),
- hasAuxBailOut(false),
- forcePreOpBailOutIfNeeded(false),
- usesStackArgumentsObject(false),
- isInlineeEntryInstr(false),
- ignoreNegativeZero(false),
- dstIsAlwaysConvertedToInt32(false),
- dstIsAlwaysConvertedToNumber(false),
- ignoreIntOverflow(false),
- ignoreIntOverflowInRange(false),
- loadedArrayHeadSegment(false),
- loadedArrayHeadSegmentLength(false),
- extractedUpperBoundCheckWithoutHoisting(false),
- ignoreOverflowBitCount(32),
- isCtorCall(false),
- isCallInstrProtectedByNoProfileBailout(false),
- hasSideEffects(false)
- {
- }
- public:
- static Instr * New(Js::OpCode opcode, Func *func);
- static Instr * New(Js::OpCode opcode, Opnd *dstOpnd, Func *func);
- static Instr * New(Js::OpCode opcode, Opnd *dstOpnd, Opnd *src1Opnd, Func *func);
- static Instr * New(Js::OpCode opcode, Opnd *dstOpnd, Opnd *src1Opnd, Opnd *src2Opnd, Func *func);
- static Instr* NewConstantLoad(IR::RegOpnd* dstOpnd, intptr_t varConst, ValueType type, Func *func, Js::Var varLocal = nullptr);
- public:
- bool IsPlainInstr() const;
- bool IsEntryInstr() const;
- EntryInstr * AsEntryInstr();
- bool IsExitInstr() const;
- ExitInstr * AsExitInstr();
- bool IsBranchInstr() const;
- BranchInstr * AsBranchInstr();
- bool IsLabelInstr() const;
- LabelInstr * AsLabelInstr();
- bool IsJitProfilingInstr() const;
- JitProfilingInstr * AsJitProfilingInstr();
- bool IsProfiledInstr() const;
- ProfiledInstr * AsProfiledInstr();
- bool IsProfiledLabelInstr() const;
- ProfiledLabelInstr * AsProfiledLabelInstr();
- bool IsPragmaInstr() const;
- PragmaInstr * AsPragmaInstr();
- bool IsByteCodeUsesInstr() const;
- ByteCodeUsesInstr * AsByteCodeUsesInstr();
- bool IsLowered() const;
- bool IsRealInstr() const;
- bool IsInlined() const;
- bool IsNewScObjectInstr() const;
- bool IsInvalidInstr() const;
- Instr* GetInvalidInstr();
- bool IsLinked() const { return this->m_prev != nullptr || this->m_next != nullptr; }
- bool StartsBasicBlock() const;
- bool EndsBasicBlock() const;
- bool HasFallThrough() const;
- bool DoStackArgsOpt(Func *topFunc) const;
- bool HasAnyLoadHeapArgsOpCode();
- bool IsEqual(IR::Instr *instr) const;
- bool IsCloned() const { return isCloned; }
- void SetIsCloned(bool isCloned) { this->isCloned = isCloned; }
- bool HasBailOutInfo() const { return hasBailOutInfo; }
- bool HasAuxBailOut() const { return hasAuxBailOut; }
- bool HasTypeCheckBailOut() const;
- bool HasEquivalentTypeCheckBailOut() const;
- void ClearBailOutInfo();
- bool IsDstNotAlwaysConvertedToInt32() const;
- bool IsDstNotAlwaysConvertedToNumber() const;
- bool ShouldCheckForNegativeZero() const;
- bool ShouldCheckForIntOverflow() const;
- bool ShouldCheckFor32BitOverflow() const;
- bool ShouldCheckForNon32BitOverflow() const;
- bool HasAnyImplicitCalls() const;
- bool HasAnySideEffects() const;
- bool AreAllOpndInt64() const;
- IRKind GetKind() const;
- Opnd * GetDst() const;
- Opnd * SetDst(Opnd * newDst);
- Opnd * SetFakeDst(Opnd * newDst);
- Opnd * UnlinkDst();
- void FreeDst();
- Opnd * Replace(Opnd *oldOpnd, Opnd *newOpnd);
- Opnd * DeepReplace(Opnd *const oldOpnd, Opnd *const newOpnd);
- Opnd * ReplaceDst(Opnd * newDst);
- Instr * SinkDst(Js::OpCode assignOpcode, RegNum regNum = RegNOREG, IR::Instr *insertAfterInstr = nullptr);
- Instr * SinkDst(Js::OpCode assignOpcode, StackSym * stackSym, RegNum regNum = RegNOREG, IR::Instr *insertAfterInstr = nullptr);
- Instr * SinkInstrBefore(IR::Instr * instrTarget);
- Opnd * GetSrc1() const;
- Opnd * SetSrc1(Opnd * newSrc);
- Opnd * UnlinkSrc1();
- void FreeSrc1();
- Opnd * ReplaceSrc1(Opnd * newSrc);
- Instr * HoistSrc1(Js::OpCode assignOpcode, RegNum regNum = RegNOREG, StackSym *newSym = nullptr);
- Opnd * GetSrc2() const;
- Opnd * SetSrc2(Opnd * newSrc);
- Opnd * UnlinkSrc2();
- void FreeSrc2();
- Opnd * ReplaceSrc2(Opnd * newSrc);
- Instr * HoistSrc2(Js::OpCode assignOpcode, RegNum regNum = RegNOREG, StackSym *newSym = nullptr);
- Instr * HoistIndirOffset(IndirOpnd *indirOpnd, RegNum regNum = RegNOREG);
- Instr * HoistSymOffset(SymOpnd *symOpnd, RegNum baseReg, uint32 offset, RegNum regNum = RegNOREG);
- Instr * HoistIndirOffsetAsAdd(IndirOpnd *orgOpnd, IR::Opnd *baseOpnd, int offset, RegNum regNum);
- Instr * HoistSymOffsetAsAdd(SymOpnd *orgOpnd, IR::Opnd *baseOpnd, int offset, RegNum regNum);
- Instr * HoistIndirIndexOpndAsAdd(IR::IndirOpnd *orgOpnd, IR::Opnd *baseOpnd, IR::Opnd *indexOpnd, RegNum regNum);
- IndirOpnd * HoistMemRefAddress(MemRefOpnd *const memRefOpnd, const Js::OpCode loadOpCode);
- Opnd * UnlinkSrc(Opnd *src);
- Opnd * ReplaceSrc(Opnd *oldSrc, Opnd * newSrc);
- void InsertBefore(Instr *instr);
- void InsertAfter(Instr *instr);
- void InsertRangeBefore(Instr *startInstr, Instr *endInstr);
- void InsertMultipleBefore(Instr *endInstr);
- void InsertRangeAfter(Instr *startInstr, Instr *endInstr);
- void InsertMultipleAfter(Instr *endInstr);
- void Unlink();
- void Free();
- void Remove();
- void SwapOpnds();
- void TransferTo(Instr * instr);
- void TransferDstAttributesTo(Instr * instr);
- IR::Instr * Copy();
- IR::Instr * Clone();
- IR::Instr * ConvertToBailOutInstr(IR::Instr * bailOutTarget, BailOutKind kind, uint32 bailOutOffset = Js::Constants::NoByteCodeOffset);
- IR::Instr * ConvertToBailOutInstr(BailOutInfo * bailOutInfo, BailOutKind kind, bool useAuxBailout = false);
- IR::Instr * GetNextRealInstr() const;
- IR::Instr * GetNextRealInstrOrLabel() const;
- IR::Instr * GetNextBranchOrLabel() const;
- IR::Instr * GetPrevRealInstr() const;
- IR::Instr * GetPrevRealInstrOrLabel() const;
- IR::Instr * GetInsertBeforeByteCodeUsesInstr();
- IR::LabelInstr *GetOrCreateContinueLabel(const bool isHelper = false);
- RegOpnd * FindRegUse(StackSym *sym);
- static RegOpnd *FindRegUseInRange(StackSym *sym, Instr *instrBegin, Instr *instrEnd);
- RegOpnd * FindRegDef(StackSym *sym);
- static Instr* FindSingleDefInstr(Js::OpCode opCode, Opnd* src);
- BranchInstr * ChangeCmCCToBranchInstr(LabelInstr *targetInstr);
- static void MoveRangeAfter(Instr * instrStart, Instr * instrLast, Instr * instrAfter);
- static IR::Instr * CloneRange(Instr * instrStart, Instr * instrLast, Instr * instrInsert, Lowerer *lowerer, JitArenaAllocator *alloc, bool (*fMapTest)(IR::Instr*), bool clonedInstrGetOrigArgSlot);
- bool CanHaveArgOutChain() const;
- bool HasEmptyArgOutChain(IR::Instr** startCallInstrOut = nullptr);
- bool HasFixedFunctionAddressTarget() const;
- #if ENABLE_DEBUG_CONFIG_OPTIONS
- const char * GetBailOutKindName() const;
- #endif
- #if DBG_DUMP
- virtual void Dump(IRDumpFlags flags);
- void Dump();
- void DumpSimple();
- char16* DumpString();
- void DumpGlobOptInstrString();
- void Dump(int window);
- void DumpRange(Instr *instrEnd);
- void DumpByteCodeOffset();
- #endif
- #if ENABLE_DEBUG_CONFIG_OPTIONS
- void DumpTestTrace();
- void DumpFieldCopyPropTestTrace();
- #endif
- uint32 GetByteCodeOffset() const;
- uint32 GetNumber() const;
- void SetByteCodeOffset(IR::Instr * instr);
- void ClearByteCodeOffset();
- BailOutInfo * GetBailOutInfo() const;
- BailOutInfo * UnlinkBailOutInfo();
- bool ReplaceBailOutInfo(BailOutInfo *newBailOutInfo);
- IR::Instr * ShareBailOut();
- BailOutKind GetBailOutKind() const;
- BailOutKind GetBailOutKindNoBits() const;
- BailOutKind GetAuxBailOutKind() const;
- void SetBailOutKind(const IR::BailOutKind bailOutKind);
- void SetAuxBailOutKind(const IR::BailOutKind bailOutKind);
- void PromoteAuxBailOut();
- void ResetAuxBailOut();
- void UnlinkStartCallFromBailOutInfo(IR::Instr *endInstr) const;
- void ChangeEquivalentToMonoTypeCheckBailOut();
- intptr_t TryOptimizeInstrWithFixedDataProperty(IR::Instr ** pInstr, GlobOpt* globopt);
- Opnd * FindCallArgumentOpnd(const Js::ArgSlot argSlot, IR::Instr * *const ownerInstrRef = nullptr);
- void CopyNumber(IR::Instr *instr) { this->SetNumber(instr->GetNumber()); }
- bool FetchOperands(_Out_writes_(argsOpndLength) IR::Opnd **argsOpnd, uint argsOpndLength);
- template <typename Fn>
- bool ForEachCallDirectArgOutInstrBackward(Fn fn, uint argsOpndLength) const;
- bool IsCmCC_A();
- bool IsCmCC_R8();
- bool IsCmCC_I4();
- bool BinaryCalculator(IntConstType src1Const, IntConstType src2Const, IntConstType *pResult);
- bool UnaryCalculator(IntConstType src1Const, IntConstType *pResult);
- IR::Instr* GetNextArg();
- // Iterates argument chain
- template<class Fn>
- bool IterateArgInstrs(Fn callback)
- {
- StackSym* linkSym = this->GetSrc2()->GetStackSym();
- Assert(linkSym->IsSingleDef());
- IR::Instr *argInstr = linkSym->m_instrDef;
- IR::Instr* nextArg = nullptr;
- do
- {
- // Get the next instr before calling 'callback' since callback might modify the IR.
- if (argInstr->GetSrc2() && argInstr->GetSrc2()->IsSymOpnd())
- {
- linkSym = argInstr->GetSrc2()->AsSymOpnd()->m_sym->AsStackSym();
- Assert(linkSym->IsArgSlotSym());
- // Due to dead code elimination in FGPeeps, it is possible for the definitions of the
- // the instructions that we are visiting during FG to have been freed. In this case,
- // the ArgSlot, even though its was a single def, will report IsSingleDef() as false
- // since instrDef is reset to nullptr when the def instr is freed
- Assert(linkSym->IsSingleDef() ||
- (m_func->IsInPhase(Js::Phase::FGPeepsPhase) || m_func->IsInPhase(Js::Phase::FGBuildPhase)));
- nextArg = linkSym->GetInstrDef();
- }
- else
- {
- nextArg = nullptr;
- }
- if(argInstr->m_opcode == Js::OpCode::ArgOut_A_InlineSpecialized)
- {
- argInstr = nextArg;
- // This is a fake ArgOut, skip it
- continue;
- }
- if (argInstr->m_opcode == Js::OpCode::StartCall)
- {
- Assert(nextArg == nullptr);
- break;
- }
- if(callback(argInstr))
- {
- return true;
- }
- argInstr = nextArg;
- } while(argInstr && !argInstr->IsInvalidInstr());
- // If an instr in the call sequence is invalid (0xFDFDFDFD), it must have been freed.
- // This is possible if some dead-code-removal/peeps code removed only part of the call sequence, while the whole sequence was dead (TH Bug 594245).
- // We allow this possibility here, while relying on the more involved dead-code-removal to remove the rest of the call sequence.
- // Inserting the opcode InvalidOpCode, with no lowering, here to safeguard against the possibility of a dead part of the call sequence not being removed. The lowerer would assert then.
- if (argInstr && argInstr->IsInvalidInstr())
- {
- this->InsertBefore(Instr::New(Js::OpCode::InvalidOpCode, this->m_func));
- }
- return false;
- }
- // Iterates all meta args for inlinee
- template<class Fn>
- bool IterateMetaArgs(Fn callback)
- {
- Assert(this->m_opcode == Js::OpCode::InlineeStart);
- Instr* currentInstr = this;
- while(currentInstr->m_opcode != Js::OpCode::InlineeMetaArg)
- {
- currentInstr = currentInstr->m_prev;
- }
- // backward iteration
- while (currentInstr->m_prev->m_opcode == Js::OpCode::InlineeMetaArg)
- {
- currentInstr = currentInstr->m_prev;
- }
- // forward iteration
- while(currentInstr->m_opcode == Js::OpCode::InlineeMetaArg)
- {
- // cache next instr as callback might move meta arg.
- IR::Instr* nextInstr = currentInstr->m_next;
- if(callback(currentInstr))
- {
- return true;
- }
- currentInstr = nextInstr;
- }
- return false;
- }
- IR::Instr* GetBytecodeArgOutCapture();
- void GenerateBytecodeArgOutCapture();
- bool HasByteCodeArgOutCapture();
- void GenerateArgOutSnapshot();
- IR::Instr* GetArgOutSnapshot();
- JITTimeFixedField* GetFixedFunction() const;
- uint GetArgOutCount(bool getInterpreterArgOutCount);
- IR::PropertySymOpnd *GetPropertySymOpnd() const;
- bool CallsAccessor(IR::PropertySymOpnd* methodOpnd = nullptr);
- bool CallsGetter(IR::PropertySymOpnd* methodOpnd = nullptr);
- bool CallsSetter(IR::PropertySymOpnd* methodOpnd = nullptr);
- bool UsesAllFields();
- void MoveArgs(bool generateByteCodeCapture = false);
- void Move(IR::Instr* insertInstr);
- private:
- void ClearNumber() { this->m_number = 0; }
- void SetNumber(uint32 number);
- friend class ::Func;
- friend class ::Lowerer;
- friend class IR::ByteCodeUsesInstr;
- void SetByteCodeOffset(uint32 number);
- friend class ::IRBuilder;
- friend class ::IRBuilderAsmJs;
- friend class ::FlowGraph;
- void SetBailOutKind_NoAssert(const IR::BailOutKind bailOutKind);
- public:
- // used only for SIMD Ld/St from typed arrays.
- // we keep these here to avoid increase in number of opcodes and to not use ExtendedArgs
- uint8 dataWidth;
- #ifdef BAILOUT_INJECTION
- uint bailOutByteCodeLocation;
- #endif
- Instr * m_next;
- Instr * m_prev;
- Func * m_func;
- #if DBG_DUMP
- char16 * globOptInstrString;
- #endif
- // These should be together to pack into a uint32
- Js::OpCode m_opcode;
- uint8 ignoreOverflowBitCount; // Number of bits after which ovf matters. Currently used for MULs.
- bool isFsBased : 1; // TEMP : just for BS testing
- bool dstIsTempNumber : 1;
- bool dstIsTempNumberTransferred : 1;
- bool dstIsTempObject : 1;
- bool usesStackArgumentsObject: 1;
- // An inlinee entry instruction initializes the InlineeCallInfo on the frame.
- bool isInlineeEntryInstr: 1;
- bool ignoreNegativeZero: 1;
- bool ignoreIntOverflow: 1;
- bool ignoreIntOverflowInRange: 1;
- bool forcePreOpBailOutIfNeeded: 1;
- bool loadedArrayHeadSegment : 1;
- bool loadedArrayHeadSegmentLength : 1;
- bool extractedUpperBoundCheckWithoutHoisting : 1;
- bool isCtorCall : 1;
- bool dstIsAlwaysConvertedToInt32 : 1;
- bool dstIsAlwaysConvertedToNumber : 1;
- bool isCallInstrProtectedByNoProfileBailout : 1;
- bool hasSideEffects : 1; // The instruction cannot be dead stored
- bool isNonFastPathFrameDisplay : 1;
- protected:
- bool isCloned:1;
- bool hasBailOutInfo:1;
- // Used for aux bail out. We are using same bailOutInfo, just different boolean to hide regular bail out.
- // Refer to ConvertToBailOutInstr implementation for details.
- bool hasAuxBailOut:1;
- IRKind m_kind;
- uint32 m_number;
- Opnd * m_dst;
- Opnd * m_src1;
- Opnd * m_src2;
- void Init(Js::OpCode opcode, IRKind kind, Func * func);
- IR::Instr * CloneInstr() const;
- };
- class ByteCodeUsesInstr : public Instr
- {
- private:
- BVSparse<JitArenaAllocator> * byteCodeUpwardExposedUsed;
-
- public:
- static ByteCodeUsesInstr * New(IR::Instr * originalBytecodeInstr);
- static ByteCodeUsesInstr * New(Func * containingFunction, uint32 offset);
- const BVSparse<JitArenaAllocator> * GetByteCodeUpwardExposedUsed() const;
- PropertySym * propertySymUse;
- // In the case of instances where you would like to add a ByteCodeUses to some sym,
- // which doesn't have an operand associated with it (like a block closure sym), use
- // this to set it without needing to pass the check for JIT-Optimized registers.
- void SetNonOpndSymbol(uint symId);
- // In cases where the operand you're working on may be changed between when you get
- // access to it and when you determine that you can set it in the ByteCodeUsesInstr
- // set method, cache the values and use this caller.
- void SetRemovedOpndSymbol(bool isJITOptimizedReg, uint symId);
- void Set(IR::Opnd * originalOperand);
- void Clear(uint symId);
- // Set the byteCodeUpwardExposedUsed bitvector on a new ByteCodeUses instruction.
- void SetBV(BVSparse<JitArenaAllocator>* newbv);
- // If possible, we want to aggregate with subsequent ByteCodeUses Instructions, so
- // that we can do some optimizations in other places where we can simplify args in
- // a compare, but still need to generate them for bailouts. Without this, we cause
- // problems because we end up with an instruction losing atomicity in terms of its
- // bytecode use and generation lifetimes.
- void Aggregate();
- };
- class JitProfilingInstr : public Instr
- {
- public:
- static JitProfilingInstr * New(Js::OpCode opcode, Opnd *dstOpnd, Opnd *src1Opnd, Func * func);
- static JitProfilingInstr * New(Js::OpCode opcode, Opnd *dstOpnd, Opnd *src1Opnd, Opnd *src2Opnd, Func * func);
- JitProfilingInstr* CloneJitProfiling() const;
- JitProfilingInstr* CopyJitProfiling() const;
- Js::ProfileId profileId;
- Js::ProfileId arrayProfileId;
- union
- {
- Js::InlineCacheIndex inlineCacheIndex;
- uint loopNumber;
- };
- bool isProfiledReturnCall : 1;
- bool isBeginSwitch : 1;
- bool isNewArray : 1;
- bool isLoopHelper: 1;
- };
- class ProfiledInstr: public Instr
- {
- protected:
- ProfiledInstr(bool hasBailOutInfo = false) : Instr(hasBailOutInfo) {}
- public:
- static ProfiledInstr * New(Js::OpCode opcode, Opnd *dstOpnd, Opnd *src1Opnd, Func * func);
- static ProfiledInstr * New(Js::OpCode opcode, Opnd *dstOpnd, Opnd *src1Opnd, Opnd *src2Opnd, Func * func);
- ProfiledInstr *CloneProfiledInstr() const;
- ProfiledInstr *CopyProfiledInstr() const;
- union
- {
- public:
- uint profileId;
- const Js::LdElemInfo * ldElemInfo;
- const Js::StElemInfo * stElemInfo;
- private:
- Js::FldInfo::TSize fldInfoData;
- public:
- Js::FldInfo &FldInfo()
- {
- return reinterpret_cast<Js::FldInfo &>(fldInfoData);
- }
- } u;
- static const uint InvalidProfileId = (uint)-1;
- };
- ///---------------------------------------------------------------------------
- ///
- /// class EntryInstr
- ///
- ///---------------------------------------------------------------------------
- class EntryInstr: public Instr
- {
- public:
- static EntryInstr * New(Js::OpCode opcode, Func *func);
- };
- ///---------------------------------------------------------------------------
- ///
- /// class ExitInstr
- ///
- ///---------------------------------------------------------------------------
- class ExitInstr: public Instr
- {
- public:
- static ExitInstr * New(Js::OpCode opcode, Func *func);
- };
- ///---------------------------------------------------------------------------
- ///
- /// class LabelInstr
- ///
- ///---------------------------------------------------------------------------
- class LabelInstr : public Instr
- {
- friend class BranchInstr;
- friend class IRBuilder;
- friend class IRBuilderAsmJs;
- friend class MultiBranchInstr;
- public:
- LabelInstr(JitArenaAllocator * allocator) : Instr(), labelRefs(allocator), m_isLoopTop(false), m_block(nullptr), isOpHelper(false),
- m_hasNonBranchRef(false), m_region(nullptr), m_loweredBasicBlock(nullptr), m_isDataLabel(false), m_isForInExit(false)
- #if DBG
- , m_noHelperAssert(false)
- #endif
- {
- #if DBG_DUMP
- m_id = 0;
- #endif
- m_pc.pc = nullptr;
- }
- static LabelInstr * New(Js::OpCode opcode, Func *func, bool isOpHelper = false);
- public:
- SListCounted<BranchInstr *> labelRefs;
- Lifetime ** m_regContent;
- BYTE m_isLoopTop : 1;
- BYTE isOpHelper : 1;
- BYTE m_hasNonBranchRef : 1;
- BYTE m_isDataLabel : 1;
- // Indicate whether the label is the target of a for in loop exit (BrOnEmpty or BrOnNotEmpty)
- // It is used by Inliner to track inlinee for in loop level to assign stack allocated for in
- // This bit has unknown validity outside of inliner
- BYTE m_isForInExit : 1;
- #if DBG
- BYTE m_noHelperAssert : 1;
- #endif
- unsigned int m_id;
- LoweredBasicBlock* m_loweredBasicBlock;
- private:
- union labelLocation
- {
- BYTE * pc; // Used by encoder and is the real pc offset
- uint32 offset; // Used by preEncoder and is an estimation pc offset, not accurate
- } m_pc;
- BasicBlock * m_block;
- Loop * m_loop;
- Region * m_region;
- public:
- inline void SetPC(BYTE * pc);
- inline BYTE * GetPC(void) const;
- inline void SetOffset(uint32 offset);
- inline void ResetOffset(uint32 offset);
- inline uint32 GetOffset(void) const;
- inline void SetBasicBlock(BasicBlock * block);
- inline BasicBlock * GetBasicBlock(void) const;
- inline void SetLoop(Loop *loop);
- inline Loop * GetLoop(void) const;
- inline void UnlinkBasicBlock(void);
- inline void SetRegion(Region *);
- inline Region * GetRegion(void) const;
- inline BOOL IsUnreferenced(void) const;
- LabelInstr * CloneLabel(BOOL fCreate);
- #if DBG_DUMP
- virtual void Dump(IRDumpFlags flags) override;
- #endif
- private:
- void AddLabelRef(BranchInstr *branchRef);
- void RemoveLabelRef(BranchInstr *branchRef);
- protected:
- void Init(Js::OpCode opcode, IRKind kind, Func *func, bool isOpHelper);
- };
- class ProfiledLabelInstr: public LabelInstr
- {
- private:
- ProfiledLabelInstr(JitArenaAllocator * allocator);
- public:
- static ProfiledLabelInstr * New(Js::OpCode opcode, Func *func, Js::ImplicitCallFlags flags, Js::LoopFlags loopFlags);
- Js::ImplicitCallFlags loopImplicitCallFlags;
- Js::LoopFlags loopFlags;
- #if DBG_DUMP
- uint loopNum;
- #endif
- };
- ///---------------------------------------------------------------------------
- ///
- /// class BranchInstr
- ///
- ///---------------------------------------------------------------------------
- class BranchInstr : public Instr
- {
- public:
- bool m_isAirlock : 1;
- bool m_isSwitchBr : 1;
- bool m_isOrphanedLeave : 1; // A Leave in a loop body in a try, most likely generated because of a return statement.
- #if DBG
- bool m_isMultiBranch;
- bool m_isHelperToNonHelperBranch;
- #endif
- public:
- static BranchInstr * New(Js::OpCode opcode, LabelInstr * branchTarget, Func *func);
- static BranchInstr * New(Js::OpCode opcode, LabelInstr * branchTarget, Opnd *srcOpnd, Func *func);
- static BranchInstr * New(Js::OpCode opcode, Opnd* destOpnd, LabelInstr * branchTarget, Opnd *srcOpnd, Func *func);
- static BranchInstr * New(Js::OpCode opcode, LabelInstr * branchTarget, Opnd *src1Opnd, Opnd *src2Opnd, Func *func);
- BranchInstr(bool hasBailOutInfo = false) : Instr(hasBailOutInfo), m_branchTarget(nullptr), m_isAirlock(false), m_isSwitchBr(false), m_isOrphanedLeave(false)
- {
- #if DBG
- m_isMultiBranch = false;
- #endif
- }
- void SetTarget(LabelInstr *labelInstr); // Only used for non-multi-branch
- bool ReplaceTarget(LabelInstr * oldLabelInstr, LabelInstr * newLabelInstr);
- void ClearTarget();
- LabelInstr * GetTarget() const;
- bool IsConditional() const;
- bool IsUnconditional() const;
- void Invert();
- void RetargetClonedBranch();
- BranchInstr * CloneBranchInstr() const;
- bool IsMultiBranch() const;
- MultiBranchInstr * AsMultiBrInstr();
- void SetByteCodeReg(Js::RegSlot reg) { m_byteCodeReg = reg; }
- Js::RegSlot GetByteCodeReg() { return m_byteCodeReg; }
- bool HasByteCodeReg() { return m_byteCodeReg != Js::Constants::NoRegister; }
- bool IsLoopTail(Func * func);
- public:
- Lifetime ** m_regContent;
- private:
- LabelInstr * m_branchTarget;
- Js::RegSlot m_byteCodeReg;
- };
- ///---------------------------------------------------------------------------
- ///
- /// class MultiBranchInstr
- ///
- ///---------------------------------------------------------------------------
- class MultiBranchInstr : public BranchInstr
- {
- private:
- /*
- The value field in the dictionary has different semantics at different points of time. Hence the 'value' field is implemented as a void *.
- In IR Layer:
- Offset is stored in the dictionary until we generate the Labels in InsertLabels().
- LabelInstr is stored in the dictionary, after we generate the LabelInstrs.
- In Encoder:
- After the fixup, actual machine address corresponding to the LabelInstr is stored as the 'value'.
- */
- private:
- typedef JITJavascriptString* TBranchKey;
- typedef Js::BranchDictionaryWrapper<TBranchKey> BranchDictionaryWrapper;
- typedef BranchDictionaryWrapper::BranchDictionary BranchDictionary;
- typedef BranchJumpTableWrapper BranchJumpTable;
- void * m_branchTargets; // can point to a dictionary or a jump table
- public:
- static MultiBranchInstr * New(Js::OpCode opcode, IR::Opnd * srcOpnd, Func *func);
- static MultiBranchInstr * New(Js::OpCode opcode, Func *func);
- enum Kind
- {
- IntJumpTable,
- StrDictionary,
- SingleCharStrJumpTable,
- };
- Kind m_kind;
- IntConstType m_baseCaseValue;
- IntConstType m_lastCaseValue;
- MultiBranchInstr() :
- m_branchTargets(nullptr)
- {
- #if DBG
- m_isMultiBranch = true;
- #endif
- }
- void AddtoDictionary(uint32 offset, TBranchKey key, void* remoteVar);
- void AddtoJumpTable(uint32 offset, uint32 jmpIndex);
- void CreateBranchTargetsAndSetDefaultTarget(int dictionarySize, Kind kind, uint defaultTargetOffset);
- void ChangeLabelRef(LabelInstr * oldTarget, LabelInstr * newTarget);
- bool ReplaceTarget(IR::LabelInstr * oldLabelInstr, IR::LabelInstr * newLabelInstr);
- void FixMultiBrDefaultTarget(uint32 targetOffset);
- void ClearTarget();
- BranchDictionaryWrapper * GetBranchDictionary();
- BranchJumpTable * GetBranchJumpTable();
- ///---------------------------------------------------------------------------
- ///
- /// template MapMultiBrLabels
- /// - Maps through the branchTargets dictionary for all the labelInstrs
- ///---------------------------------------------------------------------------
- template<class Fn>
- void MapMultiBrLabels(Fn fn)
- {
- MapMultiBrTargetByAddress([fn](void ** value) -> void
- {
- fn((LabelInstr*) *value);
- });
- }
- ///---------------------------------------------------------------------------
- ///
- /// template MapUniqueMultiBrLabels
- /// - Maps through the branchTargets dictionary for all unique labelInstrs
- ///---------------------------------------------------------------------------
- template<class Fn>
- void MapUniqueMultiBrLabels(Fn fn)
- {
- BVSparse<JitArenaAllocator> visitedTargets(m_func->m_alloc);
- MapMultiBrLabels([&](IR::LabelInstr *const targetLabel)
- {
- if(visitedTargets.Test(targetLabel->m_id))
- {
- return;
- }
- visitedTargets.Set(targetLabel->m_id);
- fn(targetLabel);
- });
- }
- ///--------------------------------------------------------------------------------------------
- ///
- /// template UpdateMultiBrTargetOffsets
- /// - Maps through the branchTargets dictionary for updating the target offset by returning the target offset.
- ///--------------------------------------------------------------------------------------------
- template<class Fn>
- void UpdateMultiBrTargetOffsets(Fn fn)
- {
- MapMultiBrTargetByAddress([fn](void ** value) -> void
- {
- *value = (void*)fn(::Math::PointerCastToIntegral<uint32>(*value));
- });
- }
- ///--------------------------------------------------------------------------------------------
- ///
- /// template UpdateMultiBrLabels
- /// - Maps through the branchDictionary for updating the labelInstr
- ///--------------------------------------------------------------------------------------------
- template<class Fn>
- void UpdateMultiBrLabels(Fn fn)
- {
- MapMultiBrTargetByAddress([fn](void ** value) -> void
- {
- IR::LabelInstr * oldLabelInstr = (LabelInstr*)*value;
- IR::LabelInstr * newLabelInstr = fn(oldLabelInstr);
- *value = (void*)newLabelInstr;
- });
- }
- ///-------------------------------------------------------------------------------------------------------------
- ///
- /// template MapMultiBrTargetByAddress
- /// - Maps through the branchDictionary accessing the address of the 'value'
- ///-------------------------------------------------------------------------------------------------------------
- template<class Fn>
- void MapMultiBrTargetByAddress(Fn fn)
- {
- if(!m_branchTargets)
- {
- return;
- }
- void ** defaultTarget = nullptr;
- switch (m_kind)
- {
- case StrDictionary:
- {
- BranchDictionary& branchDictionary = GetBranchDictionary()->dictionary;
- defaultTarget = &(((MultiBranchInstr::BranchDictionaryWrapper*)(m_branchTargets))->defaultTarget);
- branchDictionary.MapAddress([fn](TBranchKey key, void ** value)
- {
- fn(value);
- });
- break;
- }
- case IntJumpTable:
- case SingleCharStrJumpTable:
- {
- void ** branchJumpTable = GetBranchJumpTable()->jmpTable;
- defaultTarget = &(GetBranchJumpTable()->defaultTarget);
- for (IntConstType i = m_baseCaseValue; i <= m_lastCaseValue; i++)
- {
- fn(&branchJumpTable[i - m_baseCaseValue]);
- }
- break;
- }
- default:
- Assert(false);
- };
- fn(defaultTarget);
- }
- };
- ///---------------------------------------------------------------------------
- ///
- /// class PragmaInstr
- ///
- ///---------------------------------------------------------------------------
- class PragmaInstr : public Instr
- {
- public:
- uint32 m_statementIndex;
- uint32 m_offsetInBuffer; // offset in the binary code buffer
- public:
- static PragmaInstr * New(Js::OpCode opcode, uint32 index, Func *func);
- PragmaInstr() : Instr(), m_statementIndex(0)
- {
- }
- #if DBG_DUMP
- virtual void Dump(IRDumpFlags flags) override;
- #endif
- #if DBG_DUMP | defined(VTUNE_PROFILING)
- void Record(uint32 nativeBufferOffset);
- #endif
- PragmaInstr * ClonePragma();
- PragmaInstr * CopyPragma();
- };
- template <typename InstrType>
- class BailOutInstrTemplate : public InstrType
- {
- private:
- BailOutInstrTemplate() : InstrType(true) {}
- public:
- static BailOutInstrTemplate * New(Js::OpCode opcode, BailOutKind kind, IR::Instr * bailOutTarget, Func * func);
- static BailOutInstrTemplate * New(Js::OpCode opcode, IR::Opnd *dst, BailOutKind kind, IR::Instr * bailOutTarget, Func * func);
- static BailOutInstrTemplate * New(Js::OpCode opcode, IR::Opnd *dst, IR::Opnd *src1, BailOutKind kind, IR::Instr * bailOutTarget, Func * func);
- static BailOutInstrTemplate * New(Js::OpCode opcode, IR::Opnd *dst, IR::Opnd *src1, IR::Opnd *src2, BailOutKind kind, IR::Instr * bailOutTarget, Func * func);
- static BailOutInstrTemplate * New(Js::OpCode opcode, BailOutKind kind, BailOutInfo * bailOutInfo, Func * func);
- BailOutInstrTemplate * CloneBailOut() const;
- BailOutInfo * bailOutInfo;
- BailOutKind bailOutKind;
- // Auxiliary bailout kind.
- // This is kind of a decoration on top of main bail out kind and is not used for runtime bail out logic (in globopt, etc).
- // It's added when we convert instr to bailout instr for which there is already bailout,
- // and is not used/just preserved until lowerer, in the beginning of lowerer we split it out.
- // Currently used for debugger bailout when it is shared with main bailout.
- BailOutKind auxBailOutKind;
- };
- typedef BailOutInstrTemplate<Instr> BailOutInstr;
- typedef BailOutInstrTemplate<ProfiledInstr> ProfiledBailOutInstr;
- typedef BailOutInstrTemplate<BranchInstr> BranchBailOutInstr;
- //
- // FOREACH_INSTR iterators
- //
- #ifdef DBG
- # define INIT_PREV IR::Instr * __prevInstrCheck = nullptr
- # define CHECK_PREV(instr)\
- AssertMsg(__prevInstrCheck == nullptr || __prevInstrCheck->m_next == instr, \
- "Modifying instr list but not using EDITING iterator!"); \
- __prevInstrCheck = instr;
- #else
- # define INIT_PREV
- # define CHECK_PREV(instr)
- #endif
- #ifdef DBG
- # define INIT_NEXT IR::Instr * __nextInstrCheck = nullptr
- # define CHECK_NEXT(instr)\
- AssertMsg(__nextInstrCheck == nullptr || __nextInstrCheck->m_prev == instr, \
- "Modifying instr list but not using EDITING iterator!"); \
- __nextInstrCheck = instr;
- #else
- # define INIT_NEXT
- # define CHECK_NEXT(instr)
- #endif
- #define FOREACH_INSTR_IN_RANGE(instr, instrList, instrLast)\
- {\
- INIT_PREV;\
- IR::Instr *instr##Stop = instrLast ? ((IR::Instr*)instrLast)->m_next : nullptr; \
- for ( IR::Instr *instr = instrList;\
- instr != instr##Stop;\
- instr = instr->m_next)\
- {\
- CHECK_PREV(instr);
- #define NEXT_INSTR_IN_RANGE }}
- #define FOREACH_REAL_INSTR_IN_RANGE(instr, instrList, instrLast)\
- FOREACH_INSTR_IN_RANGE(instr, instrList, instrLast)\
- {\
- if (!instr->IsRealInstr())\
- {\
- continue;\
- }
- #define NEXT_REAL_INSTR_IN_RANGE NEXT_INSTR_IN_RANGE }
- #define FOREACH_INSTR_BACKWARD_IN_RANGE(instr, instrList, instrLast)\
- {\
- INIT_NEXT;\
- IR::Instr *instr##Stop = instrLast ? ((IR::Instr*)instrLast)->m_prev : nullptr; \
- for ( IR::Instr *instr = instrList;\
- instr != instr##Stop;\
- instr = instr->m_prev)\
- {\
- CHECK_NEXT(instr);
- #define NEXT_INSTR_BACKWARD_IN_RANGE }}
- #define FOREACH_INSTR_EDITING_IN_RANGE(instr, instrNext, instrList, instrLast)\
- {\
- IR::Instr * instrNext;\
- IR::Instr *instr##Stop = instrLast ? ((IR::Instr*)instrLast)->m_next : nullptr; \
- for ( IR::Instr *instr = instrList;\
- instr != instr##Stop;\
- instr = instrNext)\
- {\
- instrNext = instr->m_next;
- #define NEXT_INSTR_EDITING_IN_RANGE }}
- #define FOREACH_REAL_INSTR_EDITING_IN_RANGE(instr, instrNext, instrList, instrLast)\
- FOREACH_INSTR_EDITING_IN_RANGE(instr, instrNext, instrList, instrLast)\
- {\
- if (!instr->IsRealInstr())\
- {\
- continue;\
- }
- #define NEXT_REAL_INSTR_EDITING_IN_RANGE NEXT_INSTR_EDITING_IN_RANGE }
- #define FOREACH_INSTR_BACKWARD_EDITING_IN_RANGE(instr, instrPrev, instrList, instrLast)\
- {\
- IR::Instr * instrPrev;\
- IR::Instr *instr##Stop = instrLast ? ((IR::Instr*)instrLast)->m_prev : nullptr; \
- for ( IR::Instr *instr = instrList;\
- instr != instr##Stop;\
- instr = instrPrev)\
- {\
- instrPrev = instr->m_prev;
- #define NEXT_INSTR_BACKWARD_EDITING_IN_RANGE }}
- #define FOREACH_INSTR_EDITING(instr, instrNext, instrList)\
- FOREACH_INSTR_EDITING_IN_RANGE(instr, instrNext, instrList, nullptr)
- #define NEXT_INSTR_EDITING NEXT_INSTR_EDITING_IN_RANGE
- #define FOREACH_INSTR(instr, instrList)\
- FOREACH_INSTR_IN_RANGE(instr, instrList, nullptr)
- #define NEXT_INSTR NEXT_INSTR_IN_RANGE
- #define FOREACH_REAL_INSTR(instr, instrList)\
- FOREACH_REAL_INSTR_IN_RANGE(instr, instrList, nullptr)
- #define NEXT_REAL_INSTR NEXT_REAL_INSTR_IN_RANGE
- #define FOREACH_INSTR_BACKWARD(instr, instrList)\
- FOREACH_INSTR_BACKWARD_IN_RANGE(instr, instrList, nullptr)
- #define NEXT_INSTR_BACKWARD NEXT_INSTR_BACKWARD_IN_RANGE
- #define FOREACH_INSTR_EDITING(instr, instrNext, instrList)\
- FOREACH_INSTR_EDITING_IN_RANGE(instr, instrNext, instrList, nullptr)
- #define NEXT_INSTR_EDITING NEXT_INSTR_EDITING_IN_RANGE
- #define FOREACH_REAL_INSTR_EDITING(instr, instrNext, instrList)\
- FOREACH_REAL_INSTR_EDITING_IN_RANGE(instr, instrNext, instrList, nullptr)
- #define NEXT_REAL_INSTR_EDITING NEXT_REAL_INSTR_EDITING_IN_RANGE
- #define FOREACH_INSTR_BACKWARD_EDITING(instr, instrPrev, instrList)\
- FOREACH_INSTR_BACKWARD_EDITING_IN_RANGE(instr, instrPrev, instrList, nullptr)
- #define NEXT_INSTR_BACKWARD_EDITING NEXT_INSTR_BACKWARD_EDITING_IN_RANGE
- #define FOREACH_INSTR_IN_FUNC(instr, func)\
- FOREACH_INSTR(instr, func->m_headInstr)
- #define NEXT_INSTR_IN_FUNC NEXT_INSTR
- #define FOREACH_REAL_INSTR_IN_FUNC(instr, func)\
- FOREACH_REAL_INSTR(instr, func->m_headInstr)
- #define NEXT_REAL_INSTR_IN_FUNC NEXT_REAL_INSTR
- #define FOREACH_INSTR_IN_FUNC_BACKWARD(instr, func)\
- FOREACH_INSTR_BACKWARD(instr, func->m_tailInstr)
- #define NEXT_INSTR_IN_FUNC_BACKWARD NEXT_INSTR_BACKWARD
- #define FOREACH_INSTR_IN_FUNC_EDITING(instr, instrNext, func)\
- FOREACH_INSTR_EDITING(instr, instrNext, func->m_headInstr)
- #define NEXT_INSTR_IN_FUNC_EDITING NEXT_INSTR_EDITING
- #define FOREACH_REAL_INSTR_IN_FUNC_EDITING(instr, instrNext, func)\
- FOREACH_REAL_INSTR_EDITING(instr, instrNext, func->m_headInstr)
- #define NEXT_REAL_INSTR_IN_FUNC_EDITING NEXT_REAL_INSTR_EDITING
- #define FOREACH_INSTR_IN_FUNC_BACKWARD_EDITING(instr, instrPrev, func)\
- FOREACH_INSTR_BACKWARD_EDITING(instr, instrPrev, func->m_tailInstr)
- #define NEXT_INSTR_IN_FUNC_BACKWARD_EDITING NEXT_INSTR_BACKWARD_EDITING
- #define FOREACH_INSTR_IN_BLOCK(instr, block)\
- FOREACH_INSTR_IN_RANGE(instr, block->GetFirstInstr(), block->GetLastInstr())
- #define NEXT_INSTR_IN_BLOCK\
- NEXT_INSTR_IN_RANGE
- #define FOREACH_INSTR_IN_BLOCK_EDITING(instr, instrNext, block)\
- FOREACH_INSTR_EDITING_IN_RANGE(instr, instrNext, block->GetFirstInstr(), block->GetLastInstr())
- #define NEXT_INSTR_IN_BLOCK_EDITING \
- NEXT_INSTR_EDITING_IN_RANGE
- #define FOREACH_INSTR_BACKWARD_IN_BLOCK(instr, block)\
- FOREACH_INSTR_BACKWARD_IN_RANGE(instr, block->GetLastInstr(), block->GetFirstInstr())
- #define NEXT_INSTR_BACKWARD_IN_BLOCK\
- NEXT_INSTR_BACKWARD_IN_RANGE
- #define FOREACH_INSTR_BACKWARD_IN_BLOCK_EDITING(instr, instrPrev, block)\
- FOREACH_INSTR_BACKWARD_EDITING_IN_RANGE(instr, instrPrev, block->GetLastInstr(), block->GetFirstInstr())
- #define NEXT_INSTR_BACKWARD_IN_BLOCK_EDITING\
- NEXT_INSTR_BACKWARD_EDITING_IN_RANGE
- } // namespace IR
- typedef JsUtil::BaseDictionary<IR::Instr*, IR::Instr*, JitArenaAllocator, PrimeSizePolicy> InstrMap;
|