cdd5113924f5727d02eb5b6dc23a650361b53e95
[WebKit-https.git] / Source / JavaScriptCore / bytecode / PolymorphicAccess.h
1 /*
2  * Copyright (C) 2014, 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 #ifndef PolymorphicAccess_h
27 #define PolymorphicAccess_h
28
29 #if ENABLE(JIT)
30
31 #include "CodeOrigin.h"
32 #include "MacroAssembler.h"
33 #include "ObjectPropertyConditionSet.h"
34 #include "Opcode.h"
35 #include "Structure.h"
36 #include <wtf/Vector.h>
37
38 namespace JSC {
39
40 class CodeBlock;
41 class PolymorphicAccess;
42 class StructureStubInfo;
43 class WatchpointsOnStructureStubInfo;
44
45 struct AccessGenerationState;
46
47 class AccessCase {
48     WTF_MAKE_NONCOPYABLE(AccessCase);
49     WTF_MAKE_FAST_ALLOCATED;
50 public:
51     enum AccessType {
52         Load,
53         Transition,
54         Replace,
55         Miss,
56         Getter,
57         Setter,
58         CustomGetter,
59         CustomSetter,
60         InHit,
61         InMiss,
62         ArrayLength,
63         StringLength
64     };
65
66     static bool isGet(AccessType type)
67     {
68         switch (type) {
69         case Transition:
70         case Replace:
71         case Setter:
72         case CustomSetter:
73         case InHit:
74         case InMiss:
75             return false;
76         case Load:
77         case Miss:
78         case Getter:
79         case CustomGetter:
80         case ArrayLength:
81         case StringLength:
82             return true;
83         }
84     }
85
86     static bool isPut(AccessType type)
87     {
88         switch (type) {
89         case Load:
90         case Miss:
91         case Getter:
92         case CustomGetter:
93         case InHit:
94         case InMiss:
95         case ArrayLength:
96         case StringLength:
97             return false;
98         case Transition:
99         case Replace:
100         case Setter:
101         case CustomSetter:
102             return true;
103         }
104     }
105
106     static bool isIn(AccessType type)
107     {
108         switch (type) {
109         case Load:
110         case Miss:
111         case Getter:
112         case CustomGetter:
113         case Transition:
114         case Replace:
115         case Setter:
116         case CustomSetter:
117         case ArrayLength:
118         case StringLength:
119             return false;
120         case InHit:
121         case InMiss:
122             return true;
123         }
124     }
125
126     static std::unique_ptr<AccessCase> get(
127         VM&, JSCell* owner, AccessType, PropertyOffset, Structure*,
128         const ObjectPropertyConditionSet& = ObjectPropertyConditionSet(),
129         bool viaProxy = false,
130         WatchpointSet* additionalSet = nullptr,
131         PropertySlot::GetValueFunc = nullptr,
132         JSObject* customSlotBase = nullptr);
133
134     static std::unique_ptr<AccessCase> replace(VM&, JSCell* owner, Structure*, PropertyOffset);
135
136     static std::unique_ptr<AccessCase> transition(
137         VM&, JSCell* owner, Structure* oldStructure, Structure* newStructure, PropertyOffset,
138         const ObjectPropertyConditionSet& = ObjectPropertyConditionSet());
139
140     static std::unique_ptr<AccessCase> setter(
141         VM&, JSCell* owner, AccessType, Structure*, PropertyOffset,
142         const ObjectPropertyConditionSet&, PutPropertySlot::PutValueFunc = nullptr,
143         JSObject* customSlotBase = nullptr);
144
145     static std::unique_ptr<AccessCase> in(
146         VM&, JSCell* owner, AccessType, Structure*,
147         const ObjectPropertyConditionSet& = ObjectPropertyConditionSet());
148
149     static std::unique_ptr<AccessCase> getLength(VM&, JSCell* owner, AccessType);
150     
151     static std::unique_ptr<AccessCase> fromStructureStubInfo(VM&, JSCell* owner, StructureStubInfo&);
152
153     ~AccessCase();
154     
155     std::unique_ptr<AccessCase> clone() const;
156     
157     AccessType type() const { return m_type; }
158     PropertyOffset offset() const { return m_offset; }
159     bool viaProxy() const { return m_rareData ? m_rareData->viaProxy : false; }
160     
161     Structure* structure() const
162     {
163         if (m_type == Transition)
164             return m_structure->previousID();
165         return m_structure.get();
166     }
167     bool guardedByStructureCheck() const;
168
169     Structure* newStructure() const
170     {
171         ASSERT(m_type == Transition);
172         return m_structure.get();
173     }
174     
175     ObjectPropertyConditionSet conditionSet() const { return m_conditionSet; }
176
177     WatchpointSet* additionalSet() const
178     {
179         return m_rareData ? m_rareData->additionalSet.get() : nullptr;
180     }
181
182     JSObject* customSlotBase() const
183     {
184         return m_rareData ? m_rareData->customSlotBase.get() : nullptr;
185     }
186
187     JSObject* alternateBase() const;
188     
189     bool doesCalls() const
190     {
191         switch (type()) {
192         case Getter:
193         case Setter:
194         case CustomGetter:
195         case CustomSetter:
196             return true;
197         default:
198             return false;
199         }
200     }
201
202     CallLinkInfo* callLinkInfo() const
203     {
204         if (!m_rareData)
205             return nullptr;
206         return m_rareData->callLinkInfo.get();
207     }
208
209     // Is it still possible for this case to ever be taken?
210     bool couldStillSucceed() const;
211
212     // If this method returns true, then it's a good idea to remove 'other' from the access once 'this'
213     // is added. This method assumes that in case of contradictions, 'this' represents a newer, and so
214     // more useful, truth. This method can be conservative; it will return false when it doubt.
215     bool canReplace(const AccessCase& other);
216
217     void dump(PrintStream& out) const;
218     
219 private:
220     friend class CodeBlock;
221     friend class PolymorphicAccess;
222
223     AccessCase();
224
225     bool visitWeak(VM&) const;
226
227     // Fall through on success. Two kinds of failures are supported: fall-through, which means that we
228     // should try a different case; and failure, which means that this was the right case but it needs
229     // help from the slow path.
230     void generateWithGuard(AccessGenerationState&, MacroAssembler::JumpList& fallThrough);
231
232     // Fall through on success, add a jump to the failure list on failure.
233     void generate(AccessGenerationState&);
234     
235     AccessType m_type { Load };
236     PropertyOffset m_offset { invalidOffset };
237
238     // Usually this is the structure that we expect the base object to have. But, this is the *new*
239     // structure for a transition and we rely on the fact that it has a strong reference to the old
240     // structure. For proxies, this is the structure of the object behind the proxy.
241     WriteBarrier<Structure> m_structure;
242
243     ObjectPropertyConditionSet m_conditionSet;
244
245     class RareData {
246         WTF_MAKE_FAST_ALLOCATED;
247     public:
248         RareData()
249             : viaProxy(false)
250         {
251             customAccessor.opaque = nullptr;
252         }
253         
254         bool viaProxy;
255         RefPtr<WatchpointSet> additionalSet;
256         std::unique_ptr<CallLinkInfo> callLinkInfo;
257         union {
258             PropertySlot::GetValueFunc getter;
259             PutPropertySlot::PutValueFunc setter;
260             void* opaque;
261         } customAccessor;
262         WriteBarrier<JSObject> customSlotBase;
263     };
264
265     std::unique_ptr<RareData> m_rareData;
266 };
267
268 class PolymorphicAccess {
269     WTF_MAKE_NONCOPYABLE(PolymorphicAccess);
270     WTF_MAKE_FAST_ALLOCATED;
271 public:
272     PolymorphicAccess();
273     ~PolymorphicAccess();
274
275     // This may return null, in which case the old stub routine is left intact. You are required to
276     // pass a vector of non-null access cases. This will prune the access cases by rejecting any case
277     // in the list that is subsumed by a later case in the list.
278     MacroAssemblerCodePtr regenerateWithCases(
279         VM&, CodeBlock*, StructureStubInfo&, const Identifier&, Vector<std::unique_ptr<AccessCase>>);
280
281     MacroAssemblerCodePtr regenerateWithCase(
282         VM&, CodeBlock*, StructureStubInfo&, const Identifier&, std::unique_ptr<AccessCase>);
283     
284     bool isEmpty() const { return m_list.isEmpty(); }
285     unsigned size() const { return m_list.size(); }
286     const AccessCase& at(unsigned i) const { return *m_list[i]; }
287     const AccessCase& operator[](unsigned i) const { return *m_list[i]; }
288
289     // If this returns false then we are requesting a reset of the owning StructureStubInfo.
290     bool visitWeak(VM&) const;
291
292     void dump(PrintStream& out) const;
293
294 private:
295     friend class AccessCase;
296     friend class CodeBlock;
297     friend struct AccessGenerationState;
298     
299     typedef Vector<std::unique_ptr<AccessCase>, 2> ListType;
300
301     MacroAssemblerCodePtr regenerate(
302         VM&, CodeBlock*, StructureStubInfo&, const Identifier&, ListType& cases);
303
304     ListType m_list;
305     RefPtr<JITStubRoutine> m_stubRoutine;
306     std::unique_ptr<WatchpointsOnStructureStubInfo> m_watchpoints;
307     std::unique_ptr<Vector<WriteBarrier<JSCell>>> m_weakReferences;
308 };
309
310 } // namespace JSC
311
312 namespace WTF {
313
314 void printInternal(PrintStream&, JSC::AccessCase::AccessType);
315
316 } // namespace WTF
317
318 #endif // ENABLE(JIT)
319
320 #endif // PolymorphicAccess_h
321