forked from chakra-core/ChakraCore
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathEncoderMD.h
More file actions
249 lines (217 loc) · 8.45 KB
/
EncoderMD.h
File metadata and controls
249 lines (217 loc) · 8.45 KB
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
//-------------------------------------------------------------------------------------------------------
// Copyright (C) Microsoft. All rights reserved.
// Licensed under the MIT license. See LICENSE.txt file in the project root for full license information.
//-------------------------------------------------------------------------------------------------------
class Encoder;
enum RelocType {
RelocTypeBranch, // cond, uncond branch
RelocTypeCallPcrel, // calls
RelocTypeLabelUse, // direct use of a label
RelocTypeLabel, // points to label instr
RelocTypeAlignedLabel, // points to loop-top label instr that needs alignment
RelocTypeInlineeEntryOffset, // points to offset immediate in buffer
};
///---------------------------------------------------------------------------
///
/// class EncoderReloc
///
///---------------------------------------------------------------------------
class EncodeRelocAndLabels
{
public:
RelocType m_type;
void * m_ptr; // points to encoded buffer byte or LabelInstr if RelocTypeLabel
void * m_origPtr; // copy of m_ptr to be used to get offset in the source buffer during BR shortening
private:
union
{
IR::LabelInstr* m_labelInstr; // ptr to Br Label
BYTE m_nopCount;
uint64 m_InlineeOffset;
};
bool m_isShortBr;
public:
void init(RelocType type, void* ptr, IR::LabelInstr* labelInstr = nullptr)
{
m_type = type;
m_ptr = ptr;
m_InlineeOffset = 0;
m_isShortBr = false;
if (type == RelocTypeLabel)
{
// preserve original PC for labels
m_origPtr = (void*)((IR::LabelInstr*)ptr)->GetPC();
m_nopCount = 0;
}
else
{
m_origPtr = ptr;
if (type == RelocTypeBranch)
{
Assert(labelInstr);
m_labelInstr = labelInstr;
m_isShortBr = false;
}
else if (type == RelocTypeLabelUse)
{
Assert(labelInstr);
m_labelInstr = labelInstr;
}
}
}
void revert()
{
// recover old label PC
if (isLabel())
{
// recover old label PC and reset alignment nops
// we keep aligned labels type so we align them on the second attempt.
setLabelCurrPC(getLabelOrigPC());
m_nopCount = 0;
return;
}
if (m_type == RelocTypeBranch)
{
m_isShortBr = false;
}
m_ptr = m_origPtr;
}
bool isLabel() const { return isAlignedLabel() || m_type == RelocTypeLabel; }
bool isAlignedLabel() const { return m_type == RelocTypeAlignedLabel; }
bool isLongBr() const { return m_type == RelocTypeBranch && !m_isShortBr; }
bool isShortBr() const { return m_type == RelocTypeBranch && m_isShortBr; }
BYTE* getBrOpCodeByte() const { return (BYTE*)m_origPtr - 1;}
IR::LabelInstr * getBrTargetLabel() const
{
Assert((m_type == RelocTypeBranch || m_type == RelocTypeLabelUse) && m_labelInstr);
return m_labelInstr;
}
IR::LabelInstr * getLabel() const
{
Assert(isLabel());
return (IR::LabelInstr*) m_ptr;
}
// get label original PC without shortening/alignment
BYTE * getLabelOrigPC() const
{
Assert(isLabel());
return ((BYTE*) m_origPtr);
}
// get label PC after shortening/alignment
BYTE * getLabelCurrPC() const
{
Assert(isLabel());
return getLabel()->GetPC();
}
BYTE getLabelNopCount() const
{
Assert(isAlignedLabel());
return m_nopCount;
}
void setLabelCurrPC(BYTE* pc)
{
Assert(isLabel());
getLabel()->SetPC(pc);
}
void setLabelNopCount(BYTE nopCount)
{
Assert(isAlignedLabel());
Assert (nopCount >= 0 && nopCount < 16);
m_nopCount = nopCount;
}
void setAsShortBr()
{
Assert(m_type == RelocTypeBranch);
m_isShortBr = true;
}
// Validates if the branch is short and its target PC fits in one byte
bool validateShortBrTarget() const
{
return isShortBr() &&
getBrTargetLabel()->GetPC() - ((BYTE*)m_ptr + 1) >= -128 &&
getBrTargetLabel()->GetPC() - ((BYTE*)m_ptr + 1) <= 127;
}
uint64 GetInlineOffset()
{
return m_InlineeOffset;
}
void SetInlineOffset(uint64 offset)
{
m_InlineeOffset = offset;
}
};
///---------------------------------------------------------------------------
///
/// class EncoderMD
///
///---------------------------------------------------------------------------
enum Forms : BYTE;
typedef JsUtil::List<EncodeRelocAndLabels, ArenaAllocator> RelocList;
typedef JsUtil::List<InlineeFrameRecord*, ArenaAllocator> InlineeFrameRecords;
struct FixUpMapIndex;
class EncoderMD
{
public:
EncoderMD(Func * func) : m_func(func) {}
ptrdiff_t Encode(IR::Instr * instr, BYTE *pc, BYTE* beginCodeAddress = nullptr);
void Init(Encoder *encoder);
void ApplyRelocs(size_t codeBufferAddress, size_t codeSize, uint* bufferCRC, BOOL isBrShorteningSucceeded, bool isFinalBufferValidation = false);
uint GetRelocDataSize(EncodeRelocAndLabels *reloc);
BYTE * GetRelocBufferAddress(EncodeRelocAndLabels * reloc);
void EncodeInlineeCallInfo(IR::Instr *instr, uint32 offset);
static bool TryConstFold(IR::Instr *instr, IR::RegOpnd *regOpnd);
static bool TryFold(IR::Instr *instr, IR::RegOpnd *regOpnd);
static bool SetsConditionCode(IR::Instr *instr);
static bool UsesConditionCode(IR::Instr *instr);
static bool IsOPEQ(IR::Instr *instr);
static bool IsSHIFT(IR::Instr *instr);
static bool IsMOVEncoding(IR::Instr *instr);
RelocList* GetRelocList() const { return m_relocList; }
int AppendRelocEntry(RelocType type, void *ptr, IR::LabelInstr *label= nullptr);
int FixRelocListEntry(uint32 index, int totalBytesSaved, BYTE *buffStart, BYTE* buffEnd);
void FixMaps(uint32 brOffset, uint32 bytesSaved, FixUpMapIndex *mapIndices);
void UpdateRelocListWithNewBuffer(RelocList * relocList, BYTE * newBuffer, BYTE * oldBufferStart, BYTE * oldBufferEnd);
#ifdef DBG
void VerifyRelocList(BYTE *buffStart, BYTE *buffEnd);
#endif
void AddLabelReloc(BYTE* relocAddress);
private:
BYTE GetOpcodeByte2(IR::Instr *instr);
static Forms GetInstrForm(IR::Instr *instr);
const BYTE * GetFormTemplate(IR::Instr *instr);
const BYTE * GetOpbyte(IR::Instr *instr);
BYTE GetRegEncode(IR::RegOpnd *regOpnd);
BYTE GetRegEncode(RegNum reg);
static uint32 GetOpdope(IR::Instr *instr);
uint32 GetLeadIn(IR::Instr * instr);
BYTE EmitModRM(IR::Instr * instr, IR::Opnd *opnd, BYTE reg1);
void EmitConst(size_t val, int size, bool allowImm64 = false);
BYTE EmitImmed(IR::Opnd * opnd, int opSize, int sbit, bool allowImm64 = false);
static bool FitsInByte(size_t value);
bool IsExtendedRegister(RegNum reg);
BYTE GetMod(IR::IndirOpnd * opr, int* pDispSize);
BYTE GetMod(IR::SymOpnd * opr, int* pDispSize, RegNum& rmReg);
BYTE GetMod(size_t offset, bool regIsRbpOrR13, int * pDispSize);
BYTE GetRexByte(BYTE rexCode, IR::Opnd * opnd);
BYTE GetRexByte(BYTE rexCode, RegNum reg);
int GetOpndSize(IR::Opnd * opnd);
void EmitRexByte(BYTE * prexByte, BYTE rexByte, bool skipRexByte, bool reservedRexByte);
enum
{
REXOVERRIDE = 0x40,
REXW = 8,
REXR = 4,
REXX = 2,
REXB = 1,
};
static const BYTE Mod00 = 0x00 << 6;
static const BYTE Mod01 = 0x01 << 6;
static const BYTE Mod10 = 0x02 << 6;
static const BYTE Mod11 = 0x03 << 6;
private:
Func * m_func;
Encoder * m_encoder;
BYTE * m_pc;
RelocList * m_relocList;
int m_lastLoopLabelPosition;
};