AssemblyHelpers should not have a VM field
[WebKit.git] / Source / JavaScriptCore / bytecode / PolymorphicAccess.h
1 /*
2  * Copyright (C) 2014-2016 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(JIT)
29
30 #include "AccessCase.h"
31 #include "CodeOrigin.h"
32 #include "JITStubRoutine.h"
33 #include "JSFunctionInlines.h"
34 #include "MacroAssembler.h"
35 #include "ObjectPropertyConditionSet.h"
36 #include "ScratchRegisterAllocator.h"
37 #include "Structure.h"
38 #include <wtf/Vector.h>
39
40 namespace JSC {
41 namespace DOMJIT {
42 class GetterSetter;
43 }
44
45 class CodeBlock;
46 class PolymorphicAccess;
47 class StructureStubInfo;
48 class WatchpointsOnStructureStubInfo;
49 class ScratchRegisterAllocator;
50
51 class AccessGenerationResult {
52 public:
53     enum Kind {
54         MadeNoChanges,
55         GaveUp,
56         Buffered,
57         GeneratedNewCode,
58         GeneratedFinalCode // Generated so much code that we never want to generate code again.
59     };
60     
61     AccessGenerationResult()
62     {
63     }
64     
65     AccessGenerationResult(Kind kind)
66         : m_kind(kind)
67     {
68         RELEASE_ASSERT(kind != GeneratedNewCode);
69         RELEASE_ASSERT(kind != GeneratedFinalCode);
70     }
71     
72     AccessGenerationResult(Kind kind, MacroAssemblerCodePtr code)
73         : m_kind(kind)
74         , m_code(code)
75     {
76         RELEASE_ASSERT(kind == GeneratedNewCode || kind == GeneratedFinalCode);
77         RELEASE_ASSERT(code);
78     }
79     
80     bool operator==(const AccessGenerationResult& other) const
81     {
82         return m_kind == other.m_kind && m_code == other.m_code;
83     }
84     
85     bool operator!=(const AccessGenerationResult& other) const
86     {
87         return !(*this == other);
88     }
89     
90     explicit operator bool() const
91     {
92         return *this != AccessGenerationResult();
93     }
94     
95     Kind kind() const { return m_kind; }
96     
97     const MacroAssemblerCodePtr& code() const { return m_code; }
98     
99     bool madeNoChanges() const { return m_kind == MadeNoChanges; }
100     bool gaveUp() const { return m_kind == GaveUp; }
101     bool buffered() const { return m_kind == Buffered; }
102     bool generatedNewCode() const { return m_kind == GeneratedNewCode; }
103     bool generatedFinalCode() const { return m_kind == GeneratedFinalCode; }
104     
105     // If we gave up on this attempt to generate code, or if we generated the "final" code, then we
106     // should give up after this.
107     bool shouldGiveUpNow() const { return gaveUp() || generatedFinalCode(); }
108     
109     bool generatedSomeCode() const { return generatedNewCode() || generatedFinalCode(); }
110     
111     void dump(PrintStream&) const;
112     
113 private:
114     Kind m_kind;
115     MacroAssemblerCodePtr m_code;
116 };
117
118 class PolymorphicAccess {
119     WTF_MAKE_NONCOPYABLE(PolymorphicAccess);
120     WTF_MAKE_FAST_ALLOCATED;
121 public:
122     PolymorphicAccess();
123     ~PolymorphicAccess();
124
125     // When this fails (returns GaveUp), this will leave the old stub intact but you should not try
126     // to call this method again for that PolymorphicAccess instance.
127     AccessGenerationResult addCases(
128         VM&, CodeBlock*, StructureStubInfo&, const Identifier&, Vector<std::unique_ptr<AccessCase>, 2>);
129
130     AccessGenerationResult addCase(
131         VM&, CodeBlock*, StructureStubInfo&, const Identifier&, std::unique_ptr<AccessCase>);
132     
133     AccessGenerationResult regenerate(VM&, CodeBlock*, StructureStubInfo&, const Identifier&);
134     
135     bool isEmpty() const { return m_list.isEmpty(); }
136     unsigned size() const { return m_list.size(); }
137     const AccessCase& at(unsigned i) const { return *m_list[i]; }
138     const AccessCase& operator[](unsigned i) const { return *m_list[i]; }
139
140     // If this returns false then we are requesting a reset of the owning StructureStubInfo.
141     bool visitWeak(VM&) const;
142     
143     // This returns true if it has marked everything it will ever marked. This can be used as an
144     // optimization to then avoid calling this method again during the fixpoint.
145     bool propagateTransitions(SlotVisitor&) const;
146
147     void aboutToDie();
148
149     void dump(PrintStream& out) const;
150     bool containsPC(void* pc) const
151     { 
152         if (!m_stubRoutine)
153             return false;
154
155         uintptr_t pcAsInt = bitwise_cast<uintptr_t>(pc);
156         return m_stubRoutine->startAddress() <= pcAsInt && pcAsInt <= m_stubRoutine->endAddress();
157     }
158
159 private:
160     friend class AccessCase;
161     friend class CodeBlock;
162     friend struct AccessGenerationState;
163     
164     typedef Vector<std::unique_ptr<AccessCase>, 2> ListType;
165     
166     void commit(
167         VM&, std::unique_ptr<WatchpointsOnStructureStubInfo>&, CodeBlock*, StructureStubInfo&,
168         const Identifier&, AccessCase&);
169
170     MacroAssemblerCodePtr regenerate(
171         VM&, CodeBlock*, StructureStubInfo&, const Identifier&, ListType& cases);
172
173     ListType m_list;
174     RefPtr<JITStubRoutine> m_stubRoutine;
175     std::unique_ptr<WatchpointsOnStructureStubInfo> m_watchpoints;
176     std::unique_ptr<Vector<WriteBarrier<JSCell>>> m_weakReferences;
177 };
178
179 struct AccessGenerationState {
180     AccessGenerationState(VM& vm)
181         : m_vm(vm) 
182         , m_calculatedRegistersForCallAndExceptionHandling(false)
183         , m_needsToRestoreRegistersIfException(false)
184         , m_calculatedCallSiteIndex(false)
185     {
186     }
187     VM& m_vm;
188     CCallHelpers* jit { nullptr };
189     ScratchRegisterAllocator* allocator;
190     ScratchRegisterAllocator::PreservedState preservedReusedRegisterState;
191     PolymorphicAccess* access { nullptr };
192     StructureStubInfo* stubInfo { nullptr };
193     MacroAssembler::JumpList success;
194     MacroAssembler::JumpList failAndRepatch;
195     MacroAssembler::JumpList failAndIgnore;
196     GPRReg baseGPR { InvalidGPRReg };
197     GPRReg thisGPR { InvalidGPRReg };
198     JSValueRegs valueRegs;
199     GPRReg scratchGPR { InvalidGPRReg };
200     const Identifier* ident;
201     std::unique_ptr<WatchpointsOnStructureStubInfo> watchpoints;
202     Vector<WriteBarrier<JSCell>> weakReferences;
203
204     Watchpoint* addWatchpoint(const ObjectPropertyCondition& = ObjectPropertyCondition());
205
206     void restoreScratch();
207     void succeed();
208
209     struct SpillState {
210         SpillState() = default;
211         SpillState(RegisterSet&& regs, unsigned usedStackBytes)
212             : spilledRegisters(WTFMove(regs))
213             , numberOfStackBytesUsedForRegisterPreservation(usedStackBytes)
214         {
215         }
216
217         RegisterSet spilledRegisters { };
218         unsigned numberOfStackBytesUsedForRegisterPreservation { std::numeric_limits<unsigned>::max() };
219
220         bool isEmpty() const { return numberOfStackBytesUsedForRegisterPreservation == std::numeric_limits<unsigned>::max(); }
221     };
222
223     const RegisterSet& calculateLiveRegistersForCallAndExceptionHandling();
224
225     SpillState preserveLiveRegistersToStackForCall(const RegisterSet& extra = RegisterSet());
226
227     void restoreLiveRegistersFromStackForCallWithThrownException(const SpillState&);
228     void restoreLiveRegistersFromStackForCall(const SpillState&, const RegisterSet& dontRestore = RegisterSet());
229
230     const RegisterSet& liveRegistersForCall();
231
232     CallSiteIndex callSiteIndexForExceptionHandlingOrOriginal();
233     CallSiteIndex callSiteIndexForExceptionHandling()
234     {
235         RELEASE_ASSERT(m_calculatedRegistersForCallAndExceptionHandling);
236         RELEASE_ASSERT(m_needsToRestoreRegistersIfException);
237         RELEASE_ASSERT(m_calculatedCallSiteIndex);
238         return m_callSiteIndex;
239     }
240
241     const HandlerInfo& originalExceptionHandler();
242
243     bool needsToRestoreRegistersIfException() const { return m_needsToRestoreRegistersIfException; }
244     CallSiteIndex originalCallSiteIndex() const;
245     
246     void emitExplicitExceptionHandler();
247
248     void setSpillStateForJSGetterSetter(SpillState& spillState)
249     {
250         if (!m_spillStateForJSGetterSetter.isEmpty()) {
251             ASSERT(m_spillStateForJSGetterSetter.numberOfStackBytesUsedForRegisterPreservation == spillState.numberOfStackBytesUsedForRegisterPreservation);
252             ASSERT(m_spillStateForJSGetterSetter.spilledRegisters == spillState.spilledRegisters);
253         }
254         m_spillStateForJSGetterSetter = spillState;
255     }
256     SpillState spillStateForJSGetterSetter() const { return m_spillStateForJSGetterSetter; }
257     
258 private:
259     const RegisterSet& liveRegistersToPreserveAtExceptionHandlingCallSite();
260     
261     RegisterSet m_liveRegistersToPreserveAtExceptionHandlingCallSite;
262     RegisterSet m_liveRegistersForCall;
263     CallSiteIndex m_callSiteIndex { CallSiteIndex(std::numeric_limits<unsigned>::max()) };
264     SpillState m_spillStateForJSGetterSetter;
265     bool m_calculatedRegistersForCallAndExceptionHandling : 1;
266     bool m_needsToRestoreRegistersIfException : 1;
267     bool m_calculatedCallSiteIndex : 1;
268 };
269
270 } // namespace JSC
271
272 namespace WTF {
273
274 void printInternal(PrintStream&, JSC::AccessGenerationResult::Kind);
275 void printInternal(PrintStream&, JSC::AccessCase::AccessType);
276 void printInternal(PrintStream&, JSC::AccessCase::State);
277
278 } // namespace WTF
279
280 #endif // ENABLE(JIT)