-
Notifications
You must be signed in to change notification settings - Fork 1.2k
/
Copy pathIRBuilder.h
384 lines (347 loc) · 21.1 KB
/
IRBuilder.h
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
//-------------------------------------------------------------------------------------------------------
// 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
///---------------------------------------------------------------------------
///
/// class IRBuilder
///
/// To generate IR from the Jn bytecodes.
///
///---------------------------------------------------------------------------
class BranchReloc
{
public:
BranchReloc(IR::BranchInstr * instr, uint32 branchOffset, uint32 offs)
: branchInstr(instr), branchOffset(branchOffset), offset(offs), isNotBackEdge(false)
{ }
private:
IR::BranchInstr * branchInstr;
uint32 offset;
bool isNotBackEdge;
uint32 branchOffset;
public:
IR::BranchInstr * GetBranchInstr()
{
return this->branchInstr;
}
uint32 GetOffset() const
{
return this->offset;
}
uint32 GetBranchOffset() const
{
return this->branchOffset;
}
bool IsNotBackEdge() const
{
return this->isNotBackEdge;
}
void SetNotBackEdge()
{
this->isNotBackEdge = true;
}
};
class IRBuilder
{
friend struct IRBuilderSwitchAdapter;
public:
IRBuilder(Func * func)
: m_func(func)
, m_argsOnStack(0)
, m_loopBodyRetIPSym(nullptr)
, m_ldSlots(nullptr)
, m_loopCounterSym(nullptr)
, callTreeHasSomeProfileInfo(false)
, finallyBlockLevel(0)
, m_saveLoopImplicitCallFlags(nullptr)
, handlerOffsetStack(nullptr)
, m_switchAdapter(this)
, m_switchBuilder(&m_switchAdapter)
, m_stackFuncPtrSym(nullptr)
, m_loopBodyForInEnumeratorArrayOpnd(nullptr)
, m_paramScopeDone(false)
#if DBG
, m_callsOnStack(0)
, m_usedAsTemp(nullptr)
#endif
#ifdef BAILOUT_INJECTION
, seenLdStackArgPtr(false)
, expectApplyArg(false)
, seenProfiledBeginSwitch(false)
#endif
#ifdef BYTECODE_BRANCH_ISLAND
, longBranchMap(nullptr)
#endif
{
auto loopCount = func->GetJITFunctionBody()->GetLoopCount();
if (loopCount > 0) {
#if DBG
m_saveLoopImplicitCallFlags = AnewArrayZ(func->m_alloc, IR::Opnd*, loopCount);
#else
m_saveLoopImplicitCallFlags = AnewArray(func->m_alloc, IR::Opnd*, loopCount);
#endif
}
// Note: use original byte code without debugging probes, so that we don't jit BPs inserted by the user.
func->m_workItem->InitializeReader(&m_jnReader, &m_statementReader, func->m_alloc);
};
~IRBuilder()
{
Assert(m_func->GetJITFunctionBody()->GetLoopCount() == 0 || m_saveLoopImplicitCallFlags);
if (m_saveLoopImplicitCallFlags)
{
AdeleteArray(m_func->m_alloc, m_func->GetJITFunctionBody()->GetLoopCount(), m_saveLoopImplicitCallFlags);
}
}
void Build();
void InsertLabels();
IR::LabelInstr * CreateLabel(IR::BranchInstr * branchInstr, uint& offset);
private:
void InsertInstr(IR::Instr *instr, IR::Instr* insertBeforeInstr);
void AddInstr(IR::Instr *instr, uint32 offset);
BranchReloc * AddBranchInstr(IR::BranchInstr *instr, uint32 offset, uint32 targetOffset);
#ifdef BYTECODE_BRANCH_ISLAND
void ConsumeBranchIsland();
void EnsureConsumeBranchIsland();
uint ResolveVirtualLongBranch(IR::BranchInstr * branchInstr, uint offset);
#endif
BranchReloc * CreateRelocRecord(IR::BranchInstr * branchInstr, uint32 offset, uint32 targetOffset);
void BuildGeneratorPreamble();
void LoadNativeCodeData();
void BuildConstantLoads();
void BuildImplicitArgIns();
#define LAYOUT_TYPE(layout) \
void Build##layout(Js::OpCode newOpcode, uint32 offset);
#define LAYOUT_TYPE_WMS(layout) \
template <typename SizePolicy> void Build##layout(Js::OpCode newOpcode, uint32 offset);
#include "ByteCode/LayoutTypes.h"
void BuildReg1(Js::OpCode newOpcode, uint32 offset, Js::RegSlot R0);
void BuildReg2(Js::OpCode newOpcode, uint32 offset, Js::RegSlot R0, Js::RegSlot R1, uint32 nextOffset);
void BuildProfiledReg2(Js::OpCode newOpcode, uint32 offset, Js::RegSlot dstRegSlot, Js::RegSlot srcRegSlot, Js::ProfileId profileId);
void BuildReg3(Js::OpCode newOpcode, uint32 offset, Js::RegSlot dstRegSlot, Js::RegSlot src1RegSlot,
Js::RegSlot src2RegSlot, Js::ProfileId profileId);
void BuildIsIn(Js::OpCode newOpcode, uint32 offset, Js::RegSlot dstRegSlot, Js::RegSlot src1RegSlot, Js::RegSlot src2RegSlot, Js::ProfileId profileId);
void BuildReg3C(Js::OpCode newOpCode, uint32 offset, Js::RegSlot dstRegSlot, Js::RegSlot src1RegSlot,
Js::RegSlot src2RegSlot, Js::CacheId inlineCacheIndex);
void BuildReg4(Js::OpCode newOpcode, uint32 offset, Js::RegSlot dstRegSlot, Js::RegSlot src1RegSlot,
Js::RegSlot src2RegSlot, Js::RegSlot src3RegSlot);
void BuildReg2B1(Js::OpCode newOpcode, uint32 offset, Js::RegSlot dstRegSlot, Js::RegSlot srcRegSlot, byte index);
void BuildReg3B1(Js::OpCode newOpcode, uint32 offset, Js::RegSlot dstRegSlot, Js::RegSlot src1RegSlot,
Js::RegSlot src2RegSlot, uint8 index);
void BuildReg5(Js::OpCode newOpcode, uint32 offset, Js::RegSlot dstRegSlot, Js::RegSlot src1RegSlot,
Js::RegSlot src2RegSlot, Js::RegSlot src3RegSlot, Js::RegSlot src4RegSlot);
void BuildUnsigned1(Js::OpCode newOpcode, uint32 offset, uint32 C1);
void BuildReg1Unsigned1(Js::OpCode newOpcode, uint32 offset, Js::RegSlot R0, int32 C1);
void BuildProfiledReg1Unsigned1(Js::OpCode newOpcode, uint32 offset, Js::RegSlot R0, int32 C1, Js::ProfileId profileId);
void BuildReg2Int1(Js::OpCode newOpcode, uint32 offset, Js::RegSlot dstRegSlot, Js::RegSlot srcRegSlot, int32 value);
void BuildElementC(Js::OpCode newOpcode, uint32 offset, Js::RegSlot fieldRegSlot, Js::RegSlot regSlot,
Js::PropertyIdIndexType propertyIdIndex);
void BuildElementScopedC(Js::OpCode newOpcode, uint32 offset, Js::RegSlot regSlot,
Js::PropertyIdIndexType propertyIdIndex);
void BuildElementSlot(Js::OpCode newOpcode, uint32 offset, Js::RegSlot fieldRegSlot, Js::RegSlot regSlot,
int32 slotId, Js::ProfileId profileId);
void BuildElementSlotI1(Js::OpCode newOpcode, uint32 offset, Js::RegSlot regSlot,
int32 slotId, Js::ProfileId profileId);
void BuildElementSlotI2(Js::OpCode newOpcode, uint32 offset, Js::RegSlot regSlot,
int32 slotId1, int32 slotId2, Js::ProfileId profileId);
void BuildElementSlotI3(Js::OpCode newOpcode, uint32 offset, Js::RegSlot fieldRegSlot, Js::RegSlot regSlot,
int32 slotId, Js::RegSlot homeObjLocation, Js::ProfileId profileId);
void BuildArgIn0(uint32 offset, Js::RegSlot R0);
void BuildArg(Js::OpCode newOpcode, uint32 offset, Js::ArgSlot argument, Js::RegSlot srcRegSlot);
void BuildArgIn(uint32 offset, Js::RegSlot dstRegSlot, uint16 argument);
void BuildArgInRest();
void BuildElementP(Js::OpCode newOpcode, uint32 offset, Js::RegSlot regSlot, Js::CacheId inlineCacheIndex);
void BuildElementCP(Js::OpCode newOpcode, uint32 offset, Js::RegSlot instance, Js::RegSlot regSlot, Js::CacheId inlineCacheIndex);
void BuildProfiledElementCP(Js::OpCode newOpcode, uint32 offset, Js::RegSlot instance, Js::RegSlot regSlot, Js::CacheId inlineCacheIndex, Js::ProfileId profileId);
void BuildElementC2(Js::OpCode newOpcode, uint32 offset, Js::RegSlot instanceSlot, Js::RegSlot instance2Slot,
Js::RegSlot regSlot, Js::PropertyIdIndexType propertyIdIndex);
void BuildElementScopedC2(Js::OpCode newOpcode, uint32 offset, Js::RegSlot instance2Slot,
Js::RegSlot regSlot, Js::PropertyIdIndexType propertyIdIndex);
void BuildElementU(Js::OpCode newOpcode, uint32 offset, Js::RegSlot instance, Js::PropertyIdIndexType propertyIdIndex);
void BuildElementI(Js::OpCode newOpcode, uint32 offset, Js::RegSlot baseRegSlot, Js::RegSlot indexRegSlot,
Js::RegSlot regSlot, Js::ProfileId profileId);
void BuildElementUnsigned1(Js::OpCode newOpcode, uint32 offset, Js::RegSlot baseRegSlot, uint32 index, Js::RegSlot regSlot);
IR::Instr * BuildCallI_Helper(Js::OpCode newOpcode, uint32 offset, Js::RegSlot Return, Js::RegSlot Function, Js::ArgSlot ArgCount,
Js::ProfileId profileId, Js::CallFlags flags = Js::CallFlags_None, Js::InlineCacheIndex inlineCacheIndex = Js::Constants::NoInlineCacheIndex);
IR::Instr * BuildProfiledCallI(Js::OpCode opcode, uint32 offset, Js::RegSlot returnValue, Js::RegSlot function,
Js::ArgSlot argCount, Js::ProfileId profileId, Js::CallFlags flags = Js::CallFlags_None, Js::InlineCacheIndex inlineCacheIndex = Js::Constants::NoInlineCacheIndex);
IR::Instr * BuildProfiledCallIExtended(Js::OpCode opcode, uint32 offset, Js::RegSlot returnValue, Js::RegSlot function,
Js::ArgSlot argCount, Js::ProfileId profileId, Js::CallIExtendedOptions options, uint32 spreadAuxOffset, Js::CallFlags flags = Js::CallFlags_None);
IR::Instr * BuildProfiledCallIWithICIndex(Js::OpCode opcode, uint32 offset, Js::RegSlot returnValue, Js::RegSlot function,
Js::ArgSlot argCount, Js::ProfileId profileId, Js::InlineCacheIndex inlineCacheIndex);
void BuildProfiledCallIExtendedFlags(Js::OpCode opcode, uint32 offset, Js::RegSlot returnValue, Js::RegSlot function,
Js::ArgSlot argCount, Js::ProfileId profileId, Js::CallIExtendedOptions options, uint32 spreadAuxOffset);
void BuildProfiledCallIExtendedWithICIndex(Js::OpCode opcode, uint32 offset, Js::RegSlot returnValue, Js::RegSlot function,
Js::ArgSlot argCount, Js::ProfileId profileId, Js::CallIExtendedOptions options, uint32 spreadAuxOffset);
void BuildProfiledCallIExtendedFlagsWithICIndex(Js::OpCode opcode, uint32 offset, Js::RegSlot returnValue, Js::RegSlot function,
Js::ArgSlot argCount, Js::ProfileId profileId, Js::CallIExtendedOptions options, uint32 spreadAuxOffset);
void BuildProfiled2CallI(Js::OpCode opcode, uint32 offset, Js::RegSlot returnValue, Js::RegSlot function,
Js::ArgSlot argCount, Js::ProfileId profileId, Js::ProfileId profileId2);
void BuildProfiled2CallIExtended(Js::OpCode opcode, uint32 offset, Js::RegSlot returnValue, Js::RegSlot function,
Js::ArgSlot argCount, Js::ProfileId profileId, Js::ProfileId profileId2, Js::CallIExtendedOptions options, uint32 spreadAuxOffset);
void BuildLdSpreadIndices(uint32 offset, uint32 spreadAuxOffset);
IR::Instr * BuildCallIExtended(Js::OpCode newOpcode, uint32 offset, Js::RegSlot returnValue, Js::RegSlot function,
Js::ArgSlot argCount, Js::CallIExtendedOptions options, uint32 spreadAuxOffset, Js::CallFlags flags = Js::CallFlags_None);
void BuildCallCommon(IR::Instr *instr, StackSym *symDst, Js::ArgSlot argCount, Js::CallFlags flags = Js::CallFlags_None);
void BuildRegexFromPattern(Js::RegSlot dstRegSlot, uint32 patternIndex, uint32 offset);
void BuildClass(Js::OpCode newOpcode, uint32 offset, Js::RegSlot constructor, Js::RegSlot extends);
void BuildBrReg1(Js::OpCode newOpcode, uint32 offset, uint targetOffset, Js::RegSlot srcRegSlot);
void BuildBrReg2(Js::OpCode newOpcode, uint32 offset, uint targetOffset, Js::RegSlot src1RegSlot, Js::RegSlot src2RegSlot);
void BuildBrBReturn(Js::OpCode newOpcode, uint32 offset, Js::RegSlot DestRegSlot, uint32 forInLoopLevel, uint32 targetOffset);
IR::IndirOpnd * BuildIndirOpnd(IR::RegOpnd *baseReg, IR::RegOpnd *indexReg);
IR::IndirOpnd * BuildIndirOpnd(IR::RegOpnd *baseReg, uint32 offset);
#if DBG_DUMP || defined(ENABLE_IR_VIEWER)
IR::IndirOpnd * BuildIndirOpnd(IR::RegOpnd *baseReg, uint32 offset, const char16 *desc);
#endif
IR::SymOpnd * BuildFieldOpnd(Js::OpCode newOpCode, Js::RegSlot reg, Js::PropertyId propertyId, Js::PropertyIdIndexType propertyIdIndex, PropertyKind propertyKind, uint inlineCacheIndex = -1, bool stableSlotSym = false);
PropertySym * BuildFieldSym(Js::RegSlot reg, Js::PropertyId propertyId, Js::PropertyIdIndexType propertyIdIndex, uint inlineCacheIndex, PropertyKind propertyKind, bool stableSlotSym = false);
SymID BuildSrcStackSymID(Js::RegSlot regSlot);
IR::RegOpnd * BuildDstOpnd(Js::RegSlot dstRegSlot, IRType type = TyVar, bool isCatchObjectSym = false);
IR::RegOpnd * BuildSrcOpnd(Js::RegSlot srcRegSlot, IRType type = TyVar);
IR::AddrOpnd * BuildAuxArrayOpnd(AuxArrayValue auxArrayType, uint32 auxArrayOffset);
IR::Opnd * BuildAuxObjectLiteralTypeRefOpnd(int objectId);
IR::Opnd * BuildForInEnumeratorOpnd(uint forInLoopLevel);
IR::RegOpnd * EnsureLoopBodyForInEnumeratorArrayOpnd();
private:
uint AddStatementBoundary(uint statementIndex, uint offset);
void CheckBuiltIn(PropertySym * propertySym, Js::BuiltinFunction *puBuiltInIndex);
bool IsFloatFunctionCallsite(Js::BuiltinFunction index, size_t argc);
IR::Instr * BuildProfiledFieldLoad(Js::OpCode loadOp, IR::RegOpnd *dstOpnd, IR::SymOpnd *srcOpnd, Js::CacheId inlineCacheIndex, bool *pUnprofiled);
IR::Instr * BuildProfiledSlotLoad(Js::OpCode loadOp, IR::RegOpnd *dstOpnd, IR::SymOpnd *srcOpnd, Js::ProfileId profileId, bool *pUnprofiled);
SymID GetMappedTemp(Js::RegSlot reg)
{
AssertMsg(this->RegIsTemp(reg), "Processing non-temp reg as a temp?");
AssertMsg(this->tempMap, "Processing non-temp reg without a temp map?");
Js::RegSlot tempIndex = reg - this->firstTemp;
AssertOrFailFast(tempIndex < m_func->GetJITFunctionBody()->GetTempCount());
return this->tempMap[tempIndex];
}
void SetMappedTemp(Js::RegSlot reg, SymID tempId)
{
AssertMsg(this->RegIsTemp(reg), "Processing non-temp reg as a temp?");
AssertMsg(this->tempMap, "Processing non-temp reg without a temp map?");
Js::RegSlot tempIndex = reg - this->firstTemp;
AssertOrFailFast(tempIndex < m_func->GetJITFunctionBody()->GetTempCount());
this->tempMap[tempIndex] = tempId;
}
BOOL GetTempUsed(Js::RegSlot reg)
{
AssertMsg(this->RegIsTemp(reg), "Processing non-temp reg as a temp?");
AssertMsg(this->fbvTempUsed, "Processing non-temp reg without a used BV?");
Js::RegSlot tempIndex = reg - this->firstTemp;
AssertOrFailFast(tempIndex < m_func->GetJITFunctionBody()->GetTempCount());
return this->fbvTempUsed->Test(tempIndex);
}
void SetTempUsed(Js::RegSlot reg, BOOL used)
{
AssertMsg(this->RegIsTemp(reg), "Processing non-temp reg as a temp?");
AssertMsg(this->fbvTempUsed, "Processing non-temp reg without a used BV?");
Js::RegSlot tempIndex = reg - this->firstTemp;
AssertOrFailFast(tempIndex < m_func->GetJITFunctionBody()->GetTempCount());
if (used)
{
this->fbvTempUsed->Set(tempIndex);
}
else
{
this->fbvTempUsed->Clear(tempIndex);
}
}
BOOL RegIsTemp(Js::RegSlot reg)
{
return reg >= this->firstTemp;
}
BOOL RegIsConstant(Js::RegSlot reg)
{
return reg > 0 && reg < m_func->GetJITFunctionBody()->GetConstCount();
}
bool IsParamScopeDone() const { return m_paramScopeDone; }
void SetParamScopeDone(bool done = true) { m_paramScopeDone = done; }
Js::RegSlot InnerScopeIndexToRegSlot(uint32) const;
Js::RegSlot GetEnvReg() const;
Js::RegSlot GetEnvRegForEvalCode() const;
Js::RegSlot GetEnvRegForInnerFrameDisplay() const;
void AddEnvOpndForInnerFrameDisplay(IR::Instr *instr, uint offset);
bool DoSlotArrayCheck(IR::SymOpnd *fieldOpnd, bool doDynamicCheck);
void EmitClosureRangeChecks();
void DoClosureRegCheck(Js::RegSlot reg);
void BuildInitCachedScope(int auxOffset, int offset);
void GenerateLoopBodySlotAccesses(uint offset);
void GenerateLoopBodyStSlots(SymID loopParamSymId, uint offset);
IR::Instr * GenerateLoopBodyStSlot(Js::RegSlot regSlot, uint offset = Js::Constants::NoByteCodeOffset);
bool IsLoopBody() const;
bool IsLoopBodyInTry() const;
uint GetLoopBodyExitInstrOffset() const;
IR::SymOpnd * BuildLoopBodySlotOpnd(SymID symId);
void EnsureLoopBodyLoadSlot(SymID symId, bool isCatchObjectSym = false);
void SetLoopBodyStSlot(SymID symID, bool isCatchObjectSym);
bool IsLoopBodyOuterOffset(uint offset) const;
bool IsLoopBodyReturnIPInstr(IR::Instr * instr) const;
IR::Opnd * InsertLoopBodyReturnIPInstr(uint targetOffset, uint offset);
IR::Instr * CreateLoopBodyReturnIPInstr(uint targetOffset, uint offset);
StackSym * EnsureStackFuncPtrSym();
void InsertBailOutForDebugger(uint offset, IR::BailOutKind kind, IR::Instr* insertBeforeInstr = nullptr);
void InsertBailOnNoProfile(uint offset);
void InsertBailOnNoProfile(IR::Instr *const insertBeforeInstr);
bool DoBailOnNoProfile();
void InsertIncrLoopBodyLoopCounter(IR::LabelInstr *loopTopLabelInstr);
void InsertInitLoopBodyLoopCounter(uint loopNum);
void InsertDoneLoopBodyLoopCounter(uint32 lastOffset);
IR::RegOpnd * InsertConvPrimStr(IR::RegOpnd * srcOpnd, uint offset, bool forcePreOpBailOutIfNeeded);
IR::Opnd * GetEnvironmentOperand(uint32 offset);
bool DoLoadInstructionArrayProfileInfo();
bool AllowNativeArrayProfileInfo();
#ifdef BAILOUT_INJECTION
void InjectBailOut(uint offset);
void CheckBailOutInjection(Js::OpCode opcode);
bool seenLdStackArgPtr;
bool expectApplyArg;
bool seenProfiledBeginSwitch;
#endif
JitArenaAllocator * m_tempAlloc;
JitArenaAllocator * m_funcAlloc;
Func * m_func;
IR::Instr * m_lastInstr;
IR::Instr ** m_offsetToInstruction;
uint32 m_offsetToInstructionCount;
uint32 m_functionStartOffset;
Js::ByteCodeReader m_jnReader;
Js::StatementReader<Js::FunctionBody::ArenaStatementMapList> m_statementReader;
SList<IR::Instr *> *m_argStack;
SList<BranchReloc*> *branchRelocList;
typedef Pair<uint, bool> handlerStackElementType;
SList<handlerStackElementType> *handlerOffsetStack;
SymID * tempMap;
BVFixed * fbvTempUsed;
Js::RegSlot firstTemp;
IRBuilderSwitchAdapter m_switchAdapter;
SwitchIRBuilder m_switchBuilder;
BVFixed * m_ldSlots;
BVFixed * m_stSlots;
#if DBG
BVFixed * m_usedAsTemp;
#endif
StackSym * m_loopBodyRetIPSym;
StackSym* m_loopCounterSym;
StackSym * m_stackFuncPtrSym;
bool m_paramScopeDone;
bool callTreeHasSomeProfileInfo;
uint finallyBlockLevel;
// Keep track of how many args we have on the stack whenever
// we make a call so that the max stack used over all calls can be
// used to estimate how much stack we should probe for at the
// beginning of a JITted function.
#if DBG
uint32 m_callsOnStack;
#endif
uint32 m_argsOnStack;
Js::PropertyId m_loopBodyLocalsStartSlot;
IR::Opnd** m_saveLoopImplicitCallFlags;
IR::RegOpnd * m_loopBodyForInEnumeratorArrayOpnd;
#ifdef BYTECODE_BRANCH_ISLAND
typedef JsUtil::BaseDictionary<uint32, uint32, JitArenaAllocator> LongBranchMap;
LongBranchMap * longBranchMap;
static IR::Instr * const VirtualLongBranchInstr;
#endif
};