86e373342cb6bcbeb94215700a6bb8be226e82c1
[WebKit-https.git] / Source / JavaScriptCore / dfg / DFGJITCompiler.h
1 /*
2  * Copyright (C) 2011, 2013-2015 Apple Inc. All rights reserved.
3  *
4  * Redistribution and use in source and binary forms, with or without
5  * modification, are permitted provided that the following conditions
6  * are met:
7  * 1. Redistributions of source code must retain the above copyright
8  *    notice, this list of conditions and the following disclaimer.
9  * 2. Redistributions in binary form must reproduce the above copyright
10  *    notice, this list of conditions and the following disclaimer in the
11  *    documentation and/or other materials provided with the distribution.
12  *
13  * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
14  * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
15  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
16  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL APPLE INC. OR
17  * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
18  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
19  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
20  * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
21  * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
22  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
23  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 
24  */
25
26 #pragma once
27
28 #if ENABLE(DFG_JIT)
29
30 #include "CCallHelpers.h"
31 #include "CodeBlock.h"
32 #include "DFGDisassembler.h"
33 #include "DFGGraph.h"
34 #include "DFGInlineCacheWrapper.h"
35 #include "DFGJITCode.h"
36 #include "DFGOSRExitCompilationInfo.h"
37 #include "DFGRegisterBank.h"
38 #include "FPRInfo.h"
39 #include "GPRInfo.h"
40 #include "HandlerInfo.h"
41 #include "JITCode.h"
42 #include "JITInlineCacheGenerator.h"
43 #include "LinkBuffer.h"
44 #include "MacroAssembler.h"
45 #include "PCToCodeOriginMap.h"
46 #include "TempRegisterSet.h"
47
48 namespace JSC {
49
50 class AbstractSamplingCounter;
51 class CodeBlock;
52 class VM;
53
54 namespace DFG {
55
56 class JITCodeGenerator;
57 class NodeToRegisterMap;
58 class OSRExitJumpPlaceholder;
59 class SlowPathGenerator;
60 class SpeculativeJIT;
61 class SpeculationRecovery;
62
63 struct EntryLocation;
64 struct OSRExit;
65
66 // === CallLinkRecord ===
67 //
68 // A record of a call out from JIT code that needs linking to a helper function.
69 // Every CallLinkRecord contains a reference to the call instruction & the function
70 // that it needs to be linked to.
71 struct CallLinkRecord {
72     CallLinkRecord(MacroAssembler::Call call, FunctionPtr function)
73         : m_call(call)
74         , m_function(function)
75     {
76     }
77
78     MacroAssembler::Call m_call;
79     FunctionPtr m_function;
80 };
81
82 struct InRecord {
83     InRecord(
84         MacroAssembler::PatchableJump jump, MacroAssembler::Label done,
85         SlowPathGenerator* slowPathGenerator, StructureStubInfo* stubInfo)
86         : m_jump(jump)
87         , m_done(done)
88         , m_slowPathGenerator(slowPathGenerator)
89         , m_stubInfo(stubInfo)
90     {
91     }
92     
93     MacroAssembler::PatchableJump m_jump;
94     MacroAssembler::Label m_done;
95     SlowPathGenerator* m_slowPathGenerator;
96     StructureStubInfo* m_stubInfo;
97 };
98
99 // === JITCompiler ===
100 //
101 // DFG::JITCompiler is responsible for generating JIT code from the dataflow graph.
102 // It does so by delegating to the speculative & non-speculative JITs, which
103 // generate to a MacroAssembler (which the JITCompiler owns through an inheritance
104 // relationship). The JITCompiler holds references to information required during
105 // compilation, and also records information used in linking (e.g. a list of all
106 // call to be linked).
107 class JITCompiler : public CCallHelpers {
108 public:
109     JITCompiler(Graph& dfg);
110     ~JITCompiler();
111     
112     void compile();
113     void compileFunction();
114     
115     // Accessors for properties.
116     Graph& graph() { return m_graph; }
117     
118     // Methods to set labels for the disassembler.
119     void setStartOfCode()
120     {
121         m_pcToCodeOriginMapBuilder.appendItem(labelIgnoringWatchpoints(), CodeOrigin(0, nullptr));
122         if (LIKELY(!m_disassembler))
123             return;
124         m_disassembler->setStartOfCode(labelIgnoringWatchpoints());
125     }
126     
127     void setForBlockIndex(BlockIndex blockIndex)
128     {
129         if (LIKELY(!m_disassembler))
130             return;
131         m_disassembler->setForBlockIndex(blockIndex, labelIgnoringWatchpoints());
132     }
133     
134     void setForNode(Node* node)
135     {
136         if (LIKELY(!m_disassembler))
137             return;
138         m_disassembler->setForNode(node, labelIgnoringWatchpoints());
139     }
140     
141     void setEndOfMainPath();
142     void setEndOfCode();
143     
144     CallSiteIndex addCallSite(CodeOrigin codeOrigin)
145     {
146         return m_jitCode->common.addCodeOrigin(codeOrigin);
147     }
148
149     CallSiteIndex emitStoreCodeOrigin(CodeOrigin codeOrigin)
150     {
151         CallSiteIndex callSite = addCallSite(codeOrigin);
152         emitStoreCallSiteIndex(callSite);
153         return callSite;
154     }
155
156     void emitStoreCallSiteIndex(CallSiteIndex callSite)
157     {
158         store32(TrustedImm32(callSite.bits()), tagFor(static_cast<VirtualRegister>(CallFrameSlot::argumentCount)));
159     }
160
161     // Add a call out from JIT code, without an exception check.
162     Call appendCall(const FunctionPtr& function)
163     {
164         Call functionCall = call();
165         m_calls.append(CallLinkRecord(functionCall, function));
166         return functionCall;
167     }
168     
169     void exceptionCheck();
170
171     void exceptionCheckWithCallFrameRollback()
172     {
173         m_exceptionChecksWithCallFrameRollback.append(emitExceptionCheck(*vm()));
174     }
175
176     // Add a call out from JIT code, with a fast exception check that tests if the return value is zero.
177     void fastExceptionCheck()
178     {
179         callExceptionFuzz(*vm());
180         m_exceptionChecks.append(branchTestPtr(Zero, GPRInfo::returnValueGPR));
181     }
182     
183     OSRExitCompilationInfo& appendExitInfo(MacroAssembler::JumpList jumpsToFail = MacroAssembler::JumpList())
184     {
185         OSRExitCompilationInfo info;
186         info.m_failureJumps = jumpsToFail;
187         m_exitCompilationInfo.append(info);
188         return m_exitCompilationInfo.last();
189     }
190
191 #if USE(JSVALUE32_64)
192     void* addressOfDoubleConstant(Node*);
193 #endif
194
195     void addGetById(const JITGetByIdGenerator& gen, SlowPathGenerator* slowPath)
196     {
197         m_getByIds.append(InlineCacheWrapper<JITGetByIdGenerator>(gen, slowPath));
198     }
199     
200     void addGetByIdWithThis(const JITGetByIdWithThisGenerator& gen, SlowPathGenerator* slowPath)
201     {
202         m_getByIdsWithThis.append(InlineCacheWrapper<JITGetByIdWithThisGenerator>(gen, slowPath));
203     }
204     
205     void addPutById(const JITPutByIdGenerator& gen, SlowPathGenerator* slowPath)
206     {
207         m_putByIds.append(InlineCacheWrapper<JITPutByIdGenerator>(gen, slowPath));
208     }
209
210     void addIn(const InRecord& record)
211     {
212         m_ins.append(record);
213     }
214     
215     void addJSCall(Call fastCall, Call slowCall, DataLabelPtr targetToCheck, CallLinkInfo* info)
216     {
217         m_jsCalls.append(JSCallRecord(fastCall, slowCall, targetToCheck, info));
218     }
219     
220     void addJSDirectCall(Call call, Label slowPath, CallLinkInfo* info)
221     {
222         m_jsDirectCalls.append(JSDirectCallRecord(call, slowPath, info));
223     }
224     
225     void addJSDirectTailCall(PatchableJump patchableJump, Call call, Label slowPath, CallLinkInfo* info)
226     {
227         m_jsDirectTailCalls.append(JSDirectTailCallRecord(patchableJump, call, slowPath, info));
228     }
229     
230     void addWeakReference(JSCell* target)
231     {
232         m_graph.m_plan.weakReferences.addLazily(target);
233     }
234     
235     void addWeakReferences(const StructureSet& structureSet)
236     {
237         for (unsigned i = structureSet.size(); i--;)
238             addWeakReference(structureSet[i]);
239     }
240     
241     template<typename T>
242     Jump branchWeakPtr(RelationalCondition cond, T left, JSCell* weakPtr)
243     {
244         Jump result = branchPtr(cond, left, TrustedImmPtr(weakPtr));
245         addWeakReference(weakPtr);
246         return result;
247     }
248
249     template<typename T>
250     Jump branchWeakStructure(RelationalCondition cond, T left, RegisteredStructure weakStructure)
251     {
252         Structure* structure = weakStructure.get();
253 #if USE(JSVALUE64)
254         Jump result = branch32(cond, left, TrustedImm32(structure->id()));
255         return result;
256 #else
257         return branchPtr(cond, left, TrustedImmPtr(structure));
258 #endif
259     }
260
261     void noticeOSREntry(BasicBlock&, JITCompiler::Label blockHead, LinkBuffer&);
262     
263     RefPtr<JITCode> jitCode() { return m_jitCode; }
264     
265     Vector<Label>& blockHeads() { return m_blockHeads; }
266
267     CallSiteIndex recordCallSiteAndGenerateExceptionHandlingOSRExitIfNeeded(const CodeOrigin&, unsigned eventStreamIndex);
268
269     PCToCodeOriginMapBuilder& pcToCodeOriginMapBuilder() { return m_pcToCodeOriginMapBuilder; }
270
271     VM* vm() { return &m_graph.m_vm; }
272
273 private:
274     friend class OSRExitJumpPlaceholder;
275     
276     // Internal implementation to compile.
277     void compileEntry();
278     void compileSetupRegistersForEntry();
279     void compileEntryExecutionFlag();
280     void compileBody();
281     void link(LinkBuffer&);
282     
283     void exitSpeculativeWithOSR(const OSRExit&, SpeculationRecovery*);
284     void compileExceptionHandlers();
285     void linkOSRExits();
286     void disassemble(LinkBuffer&);
287
288     void appendExceptionHandlingOSRExit(ExitKind, unsigned eventStreamIndex, CodeOrigin, HandlerInfo* exceptionHandler, CallSiteIndex, MacroAssembler::JumpList jumpsToFail = MacroAssembler::JumpList());
289
290     // The dataflow graph currently being generated.
291     Graph& m_graph;
292
293     std::unique_ptr<Disassembler> m_disassembler;
294     
295     RefPtr<JITCode> m_jitCode;
296     
297     // Vector of calls out from JIT code, including exception handler information.
298     // Count of the number of CallRecords with exception handlers.
299     Vector<CallLinkRecord> m_calls;
300     JumpList m_exceptionChecks;
301     JumpList m_exceptionChecksWithCallFrameRollback;
302     
303     Vector<Label> m_blockHeads;
304
305
306     struct JSCallRecord {
307         JSCallRecord(Call fastCall, Call slowCall, DataLabelPtr targetToCheck, CallLinkInfo* info)
308             : fastCall(fastCall)
309             , slowCall(slowCall)
310             , targetToCheck(targetToCheck)
311             , info(info)
312         {
313         }
314         
315         Call fastCall;
316         Call slowCall;
317         DataLabelPtr targetToCheck;
318         CallLinkInfo* info;
319     };
320     
321     struct JSDirectCallRecord {
322         JSDirectCallRecord(Call call, Label slowPath, CallLinkInfo* info)
323             : call(call)
324             , slowPath(slowPath)
325             , info(info)
326         {
327         }
328         
329         Call call;
330         Label slowPath;
331         CallLinkInfo* info;
332     };
333     
334     struct JSDirectTailCallRecord {
335         JSDirectTailCallRecord(PatchableJump patchableJump, Call call, Label slowPath, CallLinkInfo* info)
336             : patchableJump(patchableJump)
337             , call(call)
338             , slowPath(slowPath)
339             , info(info)
340         {
341         }
342         
343         PatchableJump patchableJump;
344         Call call;
345         Label slowPath;
346         CallLinkInfo* info;
347     };
348
349     
350     Vector<InlineCacheWrapper<JITGetByIdGenerator>, 4> m_getByIds;
351     Vector<InlineCacheWrapper<JITGetByIdWithThisGenerator>, 4> m_getByIdsWithThis;
352     Vector<InlineCacheWrapper<JITPutByIdGenerator>, 4> m_putByIds;
353     Vector<InRecord, 4> m_ins;
354     Vector<JSCallRecord, 4> m_jsCalls;
355     Vector<JSDirectCallRecord, 4> m_jsDirectCalls;
356     Vector<JSDirectTailCallRecord, 4> m_jsDirectTailCalls;
357     SegmentedVector<OSRExitCompilationInfo, 4> m_exitCompilationInfo;
358     Vector<Vector<Label>> m_exitSiteLabels;
359     
360     struct ExceptionHandlingOSRExitInfo {
361         OSRExitCompilationInfo& exitInfo;
362         HandlerInfo baselineExceptionHandler;
363         CallSiteIndex callSiteIndex;
364     };
365     Vector<ExceptionHandlingOSRExitInfo> m_exceptionHandlerOSRExitCallSites;
366     
367     Call m_callArityFixup;
368     Label m_arityCheck;
369     std::unique_ptr<SpeculativeJIT> m_speculative;
370     PCToCodeOriginMapBuilder m_pcToCodeOriginMapBuilder;
371 };
372
373 } } // namespace JSC::DFG
374
375 #endif