forked from chakra-core/ChakraCore
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathNativeCodeGenerator.h
More file actions
300 lines (246 loc) · 10.7 KB
/
NativeCodeGenerator.h
File metadata and controls
300 lines (246 loc) · 10.7 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
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
//-------------------------------------------------------------------------------------------------------
// 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
struct CodeGenWorkItem;
struct JsFunctionCodeGen;
struct JsLoopBodyCodeGen;
class InliningDecider;
namespace Js
{
class ObjTypeSpecFldInfo;
class FunctionCodeGenJitTimeData;
};
class NativeCodeGenerator sealed : public JsUtil::WaitableJobManager
{
#if ENABLE_DEBUG_CONFIG_OPTIONS
static volatile UINT_PTR CodegenFailureSeed;
#endif
friend JsUtil::ForegroundJobProcessor;
friend JsUtil::BackgroundJobProcessor;
friend Js::RemoteScriptContext;
public:
NativeCodeGenerator(Js::ScriptContext * scriptContext);
~NativeCodeGenerator();
void Close();
JsFunctionCodeGen * NewFunctionCodeGen(Js::FunctionBody *functionBody, Js::EntryPointInfo* info);
JsLoopBodyCodeGen * NewLoopBodyCodeGen(Js::FunctionBody *functionBody, Js::EntryPointInfo* info);
bool GenerateFunction(Js::FunctionBody * fn, Js::ScriptFunction * function = nullptr);
void GenerateLoopBody(Js::FunctionBody * functionBody, Js::LoopHeader * loopHeader, Js::EntryPointInfo* info = nullptr, uint localCount = 0, Js::Var localSlots[] = nullptr);
static bool IsValidVar(const Js::Var var, Recycler *const recycler);
#ifdef ENABLE_PREJIT
void GenerateAllFunctions(Js::FunctionBody * fn);
bool DoBackEnd(Js::FunctionBody * fn);
#endif
#ifdef IR_VIEWER
Js::Var RejitIRViewerFunction(Js::FunctionBody *fn, Js::ScriptContext *scriptContext);
#endif
void SetProfileMode(BOOL fSet);
public:
static Js::Var CheckCodeGenThunk(Js::RecyclableObject* function, Js::CallInfo callInfo, ...);
#ifdef ASMJS_PLAT
static Js::Var CheckAsmJsCodeGenThunk(Js::RecyclableObject* function, Js::CallInfo callInfo, ...);
#endif
static bool IsThunk(Js::JavascriptMethod codeAddress);
static bool IsAsmJsCodeGenThunk(Js::JavascriptMethod codeAddress);
static CheckCodeGenFunction GetCheckCodeGenFunction(Js::JavascriptMethod codeAddress);
static Js::JavascriptMethod CheckCodeGen(Js::ScriptFunction * function);
static Js::Var CheckAsmJsCodeGen(Js::ScriptFunction * function);
public:
static void Jit_TransitionFromSimpleJit(void *const framePointer);
private:
static void TransitionFromSimpleJit(Js::ScriptFunction *const function);
private:
static Js::JavascriptMethod CheckCodeGenDone(Js::FunctionBody *const functionBody, Js::FunctionEntryPointInfo *const entryPointInfo, Js::ScriptFunction * function);
CodeGenWorkItem *GetJob(Js::EntryPointInfo *const entryPoint) const;
bool WasAddedToJobProcessor(JsUtil::Job *const job) const;
bool ShouldProcessInForeground(const bool willWaitForJob, const unsigned int numJobsInQueue) const;
void Prioritize(JsUtil::Job *const job, const bool forceAddJobToProcessor = false, void* function = nullptr);
void PrioritizedButNotYetProcessed(JsUtil::Job *const job);
void BeforeWaitForJob(Js::EntryPointInfo *const entryPoint) const;
void AfterWaitForJob(Js::EntryPointInfo *const entryPoint) const;
static bool WorkItemExceedsJITLimits(CodeGenWorkItem *const codeGenWork);
virtual bool Process(JsUtil::Job *const job, JsUtil::ParallelThreadData *threadData) override;
virtual void JobProcessed(JsUtil::Job *const job, const bool succeeded) override;
JsUtil::Job *GetJobToProcessProactively();
void AddToJitQueue(CodeGenWorkItem *const codeGenWorkItem, bool prioritize, bool lock, void* function = nullptr);
void RemoveProactiveJobs();
typedef SListCounted<Js::ObjTypeSpecFldInfo*, ArenaAllocator> ObjTypeSpecFldInfoList;
template<bool IsInlinee> void GatherCodeGenData(
Recycler *const recycler,
Js::FunctionBody *const topFunctionBody,
Js::FunctionBody *const functionBody,
Js::EntryPointInfo *const entryPoint,
InliningDecider &inliningDecider,
ObjTypeSpecFldInfoList *objTypeSpecFldInfoList,
Js::FunctionCodeGenJitTimeData *const jitTimeData,
Js::FunctionCodeGenRuntimeData *const runtimeData,
Js::JavascriptFunction* function = nullptr,
bool isJitTimeDataComputed = false,
uint32 recursiveInlineDepth = 0);
Js::CodeGenRecyclableData *GatherCodeGenData(Js::FunctionBody *const topFunctionBody, Js::FunctionBody *const functionBody, Js::EntryPointInfo *const entryPoint, CodeGenWorkItem* workItem, void* function = nullptr);
public:
void UpdateQueueForDebugMode();
bool IsBackgroundJIT() const;
void EnterScriptStart();
bool IsNativeFunctionAddr(void * address);
void FreeNativeCodeGenAllocation(void* address);
bool TryReleaseNonHiPriWorkItem(CodeGenWorkItem* workItem);
void QueueFreeNativeCodeGenAllocation(void* address);
bool IsClosed() { return isClosed; }
void AddWorkItem(CodeGenWorkItem* workItem);
CodeGenAllocators* GetCodeGenAllocator(PageAllocator* pageallocator){ return EnsureForegroundAllocators(pageallocator); }
#if DBG_DUMP
FILE * asmFile;
#endif
#ifdef PROFILE_EXEC
void CreateProfiler(Js::ScriptContextProfiler * profiler);
void SetProfilerFromNativeCodeGen(NativeCodeGenerator * nativeCodeGen);
Js::ScriptContextProfiler *EnsureForegroundCodeGenProfiler();
static void ProfileBegin(Js::ScriptContextProfiler *const profiler, Js::Phase);
static void ProfileEnd(Js::ScriptContextProfiler *const profiler, Js::Phase);
void ProfilePrint();
#endif
private:
void CodeGen(PageAllocator * pageAllocator, CodeGenWorkItem* workItem, const bool foreground);
CodeGenAllocators *CreateAllocators(PageAllocator *const pageAllocator)
{
return HeapNew(CodeGenAllocators, pageAllocator->GetAllocationPolicyManager(), scriptContext);
}
CodeGenAllocators *EnsureForegroundAllocators(PageAllocator * pageAllocator)
{
if (this->foregroundAllocators == nullptr)
{
this->foregroundAllocators = CreateAllocators(pageAllocator);
#if !_M_X64_OR_ARM64 && _CONTROL_FLOW_GUARD
if (this->scriptContext->webWorkerId != Js::Constants::NonWebWorkerContextId)
{
this->foregroundAllocators->canCreatePreReservedSegment = true;
}
#endif
}
return this->foregroundAllocators;
}
CodeGenAllocators * GetBackgroundAllocator(PageAllocator *pageAllocator)
{
return this->backgroundAllocators;
}
Js::ScriptContextProfiler * GetBackgroundCodeGenProfiler(PageAllocator *allocator);
void AllocateBackgroundCodeGenProfiler(PageAllocator * pageAllocator);
void AllocateBackgroundAllocators(PageAllocator * pageAllocator)
{
if (!this->backgroundAllocators)
{
this->backgroundAllocators = CreateAllocators(pageAllocator);
#if !_M_X64_OR_ARM64 && _CONTROL_FLOW_GUARD
this->backgroundAllocators->canCreatePreReservedSegment = true;
#endif
}
AllocateBackgroundCodeGenProfiler(pageAllocator);
}
virtual void ProcessorThreadSpecificCallBack(PageAllocator * pageAllocator) override
{
AllocateBackgroundAllocators(pageAllocator);
}
bool IsInDebugMode() const;
static ExecutionMode PrejitJitMode(Js::FunctionBody *const functionBody);
bool TryAggressiveInlining(Js::FunctionBody *const topFunctionBody, Js::FunctionBody *const functionBody, InliningDecider &inliningDecider, uint32& inlineeCount, uint recursiveInlineDepth);
private:
Js::ScriptContext * scriptContext;
Js::FunctionBody::SetNativeEntryPointFuncType SetNativeEntryPoint;
uint pendingCodeGenWorkItems;
JsUtil::DoublyLinkedList<CodeGenWorkItem> workItems;
JsUtil::DoublyLinkedList<QueuedFullJitWorkItem> queuedFullJitWorkItems;
uint queuedFullJitWorkItemCount;
uint byteCodeSizeGenerated;
bool isOptimizedForManyInstances;
bool isClosed;
bool hasUpdatedQForDebugMode;
class FreeLoopBodyJob: public JsUtil::Job
{
public:
FreeLoopBodyJob(JsUtil::JobManager *const manager, void* address, bool isHeapAllocated = true):
JsUtil::Job(manager),
codeAddress(address),
heapAllocated(isHeapAllocated)
{
}
bool heapAllocated;
void* codeAddress;
};
class FreeLoopBodyJobManager sealed: public WaitableJobManager
{
public:
FreeLoopBodyJobManager(JsUtil::JobProcessor* processor)
: JsUtil::WaitableJobManager(processor)
, autoClose(true)
, isClosed(false)
{
Processor()->AddManager(this);
}
virtual ~FreeLoopBodyJobManager()
{
if (autoClose && !isClosed)
{
Close();
}
Assert(this->isClosed);
}
void Close()
{
Assert(!this->isClosed);
Processor()->RemoveManager(this);
this->isClosed = true;
}
void SetAutoClose(bool autoClose)
{
this->autoClose = autoClose;
}
FreeLoopBodyJob* GetJob(FreeLoopBodyJob* job)
{
return job;
}
bool WasAddedToJobProcessor(JsUtil::Job *const job) const
{
return true;
}
void SetNativeCodeGen(NativeCodeGenerator* nativeCodeGen)
{
this->nativeCodeGen = nativeCodeGen;
}
void BeforeWaitForJob(FreeLoopBodyJob*) const {}
void AfterWaitForJob(FreeLoopBodyJob*) const {}
virtual bool Process(JsUtil::Job *const job, JsUtil::ParallelThreadData *threadData) override
{
FreeLoopBodyJob* freeLoopBodyJob = static_cast<FreeLoopBodyJob*>(job);
// Free Loop Body
nativeCodeGen->FreeNativeCodeGenAllocation(freeLoopBodyJob->codeAddress);
return true;
}
virtual void JobProcessed(JsUtil::Job *const job, const bool succeeded) override
{
FreeLoopBodyJob* freeLoopBodyJob = static_cast<FreeLoopBodyJob*>(job);
if (freeLoopBodyJob->heapAllocated)
{
HeapDelete(freeLoopBodyJob);
}
}
void QueueFreeLoopBodyJob(void* codeAddress);
private:
NativeCodeGenerator* nativeCodeGen;
bool autoClose;
bool isClosed;
};
FreeLoopBodyJobManager freeLoopBodyManager;
CodeGenAllocators * foregroundAllocators;
CodeGenAllocators * backgroundAllocators;
#ifdef PROFILE_EXEC
Js::ScriptContextProfiler * foregroundCodeGenProfiler;
Js::ScriptContextProfiler * backgroundCodeGenProfiler;
#endif
#if DBG
ThreadContextId mainThreadId;
friend void CheckIsExecutable(Js::RecyclableObject * function, Js::JavascriptMethod entrypoint);
#endif
};