Debug JSC test failure: stress/multi-put-by-offset-reallocation-butterfly-cse.js...
[WebKit-https.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 #ifndef PolymorphicAccess_h
27 #define PolymorphicAccess_h
28
29 #if ENABLE(JIT)
30
31 #include "CodeOrigin.h"
32 #include "JSFunctionInlines.h"
33 #include "MacroAssembler.h"
34 #include "ObjectPropertyConditionSet.h"
35 #include "Opcode.h"
36 #include "ScratchRegisterAllocator.h"
37 #include "Structure.h"
38 #include <wtf/Vector.h>
39
40 namespace JSC {
41
42 class CodeBlock;
43 class PolymorphicAccess;
44 class StructureStubInfo;
45 class WatchpointsOnStructureStubInfo;
46 class ScratchRegisterAllocator;
47
48 struct AccessGenerationState;
49
50 class AccessCase {
51     WTF_MAKE_NONCOPYABLE(AccessCase);
52     WTF_MAKE_FAST_ALLOCATED;
53 public:
54     enum AccessType {
55         Load,
56         MegamorphicLoad,
57         Transition,
58         Replace,
59         Miss,
60         GetGetter,
61         Getter,
62         Setter,
63         CustomValueGetter,
64         CustomAccessorGetter,
65         CustomValueSetter,
66         CustomAccessorSetter,
67         IntrinsicGetter,
68         InHit,
69         InMiss,
70         ArrayLength,
71         StringLength,
72         DirectArgumentsLength,
73         ScopedArgumentsLength
74     };
75
76     static std::unique_ptr<AccessCase> tryGet(
77         VM&, JSCell* owner, AccessType, PropertyOffset, Structure*,
78         const ObjectPropertyConditionSet& = ObjectPropertyConditionSet(),
79         bool viaProxy = false,
80         WatchpointSet* additionalSet = nullptr);
81
82     static std::unique_ptr<AccessCase> get(
83         VM&, JSCell* owner, AccessType, PropertyOffset, Structure*,
84         const ObjectPropertyConditionSet& = ObjectPropertyConditionSet(),
85         bool viaProxy = false,
86         WatchpointSet* additionalSet = nullptr,
87         PropertySlot::GetValueFunc = nullptr,
88         JSObject* customSlotBase = nullptr);
89     
90     static std::unique_ptr<AccessCase> megamorphicLoad(VM&, JSCell* owner);
91     
92     static std::unique_ptr<AccessCase> replace(VM&, JSCell* owner, Structure*, PropertyOffset);
93
94     static std::unique_ptr<AccessCase> transition(
95         VM&, JSCell* owner, Structure* oldStructure, Structure* newStructure, PropertyOffset,
96         const ObjectPropertyConditionSet& = ObjectPropertyConditionSet());
97
98     static std::unique_ptr<AccessCase> setter(
99         VM&, JSCell* owner, AccessType, Structure*, PropertyOffset,
100         const ObjectPropertyConditionSet&, PutPropertySlot::PutValueFunc = nullptr,
101         JSObject* customSlotBase = nullptr);
102
103     static std::unique_ptr<AccessCase> in(
104         VM&, JSCell* owner, AccessType, Structure*,
105         const ObjectPropertyConditionSet& = ObjectPropertyConditionSet());
106
107     static std::unique_ptr<AccessCase> getLength(VM&, JSCell* owner, AccessType);
108     static std::unique_ptr<AccessCase> getIntrinsic(VM&, JSCell* owner, JSFunction* intrinsic, PropertyOffset, Structure*, const ObjectPropertyConditionSet&);
109     
110     static std::unique_ptr<AccessCase> fromStructureStubInfo(VM&, JSCell* owner, StructureStubInfo&);
111
112     ~AccessCase();
113     
114     std::unique_ptr<AccessCase> clone() const;
115     
116     AccessType type() const { return m_type; }
117     PropertyOffset offset() const { return m_offset; }
118     bool viaProxy() const { return m_rareData ? m_rareData->viaProxy : false; }
119     
120     Structure* structure() const
121     {
122         if (m_type == Transition)
123             return m_structure->previousID();
124         return m_structure.get();
125     }
126     bool guardedByStructureCheck() const;
127
128     Structure* newStructure() const
129     {
130         ASSERT(m_type == Transition);
131         return m_structure.get();
132     }
133     
134     ObjectPropertyConditionSet conditionSet() const { return m_conditionSet; }
135     JSFunction* intrinsicFunction() const
136     {
137         ASSERT(type() == IntrinsicGetter && m_rareData);
138         return m_rareData->intrinsicFunction.get();
139     }
140     Intrinsic intrinsic() const
141     {
142         return intrinsicFunction()->intrinsic();
143     }
144
145     WatchpointSet* additionalSet() const
146     {
147         return m_rareData ? m_rareData->additionalSet.get() : nullptr;
148     }
149
150     JSObject* customSlotBase() const
151     {
152         return m_rareData ? m_rareData->customSlotBase.get() : nullptr;
153     }
154
155     JSObject* alternateBase() const;
156
157     // If you supply the optional vector, this will append the set of cells that this will need to keep alive
158     // past the call.
159     bool doesCalls(Vector<JSCell*>* cellsToMark = nullptr) const;
160
161     bool isGetter() const
162     {
163         switch (type()) {
164         case Getter:
165         case CustomValueGetter:
166         case CustomAccessorGetter:
167             return true;
168         default:
169             return false;
170         }
171     }
172
173     CallLinkInfo* callLinkInfo() const
174     {
175         if (!m_rareData)
176             return nullptr;
177         return m_rareData->callLinkInfo.get();
178     }
179
180     // Is it still possible for this case to ever be taken?
181     bool couldStillSucceed() const;
182     
183     static bool canEmitIntrinsicGetter(JSFunction*, Structure*);
184
185     bool canBeReplacedByMegamorphicLoad() const;
186
187     // If this method returns true, then it's a good idea to remove 'other' from the access once 'this'
188     // is added. This method assumes that in case of contradictions, 'this' represents a newer, and so
189     // more useful, truth. This method can be conservative; it will return false when it doubt.
190     bool canReplace(const AccessCase& other) const;
191
192     void dump(PrintStream& out) const;
193     
194 private:
195     friend class CodeBlock;
196     friend class PolymorphicAccess;
197
198     AccessCase();
199
200     bool visitWeak(VM&) const;
201
202     // Fall through on success. Two kinds of failures are supported: fall-through, which means that we
203     // should try a different case; and failure, which means that this was the right case but it needs
204     // help from the slow path.
205     void generateWithGuard(AccessGenerationState&, MacroAssembler::JumpList& fallThrough);
206
207     // Fall through on success, add a jump to the failure list on failure.
208     void generate(AccessGenerationState&);
209     void emitIntrinsicGetter(AccessGenerationState&);
210     
211     AccessType m_type { Load };
212     PropertyOffset m_offset { invalidOffset };
213
214     // Usually this is the structure that we expect the base object to have. But, this is the *new*
215     // structure for a transition and we rely on the fact that it has a strong reference to the old
216     // structure. For proxies, this is the structure of the object behind the proxy.
217     WriteBarrier<Structure> m_structure;
218
219     ObjectPropertyConditionSet m_conditionSet;
220
221     class RareData {
222         WTF_MAKE_FAST_ALLOCATED;
223     public:
224         RareData()
225             : viaProxy(false)
226         {
227             customAccessor.opaque = nullptr;
228         }
229         
230         bool viaProxy;
231         RefPtr<WatchpointSet> additionalSet;
232         std::unique_ptr<CallLinkInfo> callLinkInfo;
233         union {
234             PropertySlot::GetValueFunc getter;
235             PutPropertySlot::PutValueFunc setter;
236             void* opaque;
237         } customAccessor;
238         WriteBarrier<JSObject> customSlotBase;
239         WriteBarrier<JSFunction> intrinsicFunction;
240     };
241
242     std::unique_ptr<RareData> m_rareData;
243 };
244
245 class AccessGenerationResult {
246 public:
247     enum Kind {
248         MadeNoChanges,
249         GaveUp,
250         GeneratedNewCode
251     };
252     
253     AccessGenerationResult()
254     {
255     }
256     
257     AccessGenerationResult(Kind kind)
258         : m_kind(kind)
259     {
260         ASSERT(kind != GeneratedNewCode);
261     }
262     
263     AccessGenerationResult(MacroAssemblerCodePtr code)
264         : m_kind(GeneratedNewCode)
265         , m_code(code)
266     {
267         RELEASE_ASSERT(code);
268     }
269     
270     bool operator==(const AccessGenerationResult& other) const
271     {
272         return m_kind == other.m_kind && m_code == other.m_code;
273     }
274     
275     bool operator!=(const AccessGenerationResult& other) const
276     {
277         return !(*this == other);
278     }
279     
280     explicit operator bool() const
281     {
282         return *this != AccessGenerationResult();
283     }
284     
285     Kind kind() const { return m_kind; }
286     
287     const MacroAssemblerCodePtr& code() const { return m_code; }
288     
289     bool madeNoChanges() const { return m_kind == MadeNoChanges; }
290     bool gaveUp() const { return m_kind == GaveUp; }
291     bool generatedNewCode() const { return m_kind == GeneratedNewCode; }
292     
293     void dump(PrintStream&) const;
294     
295 private:
296     Kind m_kind;
297     MacroAssemblerCodePtr m_code;
298 };
299
300 class PolymorphicAccess {
301     WTF_MAKE_NONCOPYABLE(PolymorphicAccess);
302     WTF_MAKE_FAST_ALLOCATED;
303 public:
304     PolymorphicAccess();
305     ~PolymorphicAccess();
306
307     // This may return null, in which case the old stub routine is left intact. You are required to
308     // pass a vector of non-null access cases. This will prune the access cases by rejecting any case
309     // in the list that is subsumed by a later case in the list.
310     AccessGenerationResult regenerateWithCases(
311         VM&, CodeBlock*, StructureStubInfo&, const Identifier&, Vector<std::unique_ptr<AccessCase>>);
312
313     AccessGenerationResult regenerateWithCase(
314         VM&, CodeBlock*, StructureStubInfo&, const Identifier&, std::unique_ptr<AccessCase>);
315     
316     bool isEmpty() const { return m_list.isEmpty(); }
317     unsigned size() const { return m_list.size(); }
318     const AccessCase& at(unsigned i) const { return *m_list[i]; }
319     const AccessCase& operator[](unsigned i) const { return *m_list[i]; }
320
321     // If this returns false then we are requesting a reset of the owning StructureStubInfo.
322     bool visitWeak(VM&) const;
323
324     void aboutToDie();
325
326     void dump(PrintStream& out) const;
327     bool containsPC(void* pc) const
328     { 
329         if (!m_stubRoutine)
330             return false;
331
332         uintptr_t pcAsInt = bitwise_cast<uintptr_t>(pc);
333         return m_stubRoutine->startAddress() <= pcAsInt && pcAsInt <= m_stubRoutine->endAddress();
334     }
335
336 private:
337     friend class AccessCase;
338     friend class CodeBlock;
339     friend struct AccessGenerationState;
340     
341     typedef Vector<std::unique_ptr<AccessCase>, 2> ListType;
342
343     MacroAssemblerCodePtr regenerate(
344         VM&, CodeBlock*, StructureStubInfo&, const Identifier&, ListType& cases);
345
346     ListType m_list;
347     RefPtr<JITStubRoutine> m_stubRoutine;
348     std::unique_ptr<WatchpointsOnStructureStubInfo> m_watchpoints;
349     std::unique_ptr<Vector<WriteBarrier<JSCell>>> m_weakReferences;
350 };
351
352 struct AccessGenerationState {
353     AccessGenerationState()
354         : m_calculatedRegistersForCallAndExceptionHandling(false)
355         , m_needsToRestoreRegistersIfException(false)
356         , m_calculatedCallSiteIndex(false)
357     {
358     }
359     CCallHelpers* jit { nullptr };
360     ScratchRegisterAllocator* allocator;
361     ScratchRegisterAllocator::PreservedState preservedReusedRegisterState;
362     PolymorphicAccess* access { nullptr };
363     StructureStubInfo* stubInfo { nullptr };
364     MacroAssembler::JumpList success;
365     MacroAssembler::JumpList failAndRepatch;
366     MacroAssembler::JumpList failAndIgnore;
367     GPRReg baseGPR { InvalidGPRReg };
368     JSValueRegs valueRegs;
369     GPRReg scratchGPR { InvalidGPRReg };
370     const Identifier* ident;
371     std::unique_ptr<WatchpointsOnStructureStubInfo> watchpoints;
372     Vector<WriteBarrier<JSCell>> weakReferences;
373
374     Watchpoint* addWatchpoint(const ObjectPropertyCondition& = ObjectPropertyCondition());
375
376     void restoreScratch();
377     void succeed();
378
379     void calculateLiveRegistersForCallAndExceptionHandling(const RegisterSet& extra = RegisterSet());
380
381     void preserveLiveRegistersToStackForCall(const RegisterSet& extra = RegisterSet());
382
383     void restoreLiveRegistersFromStackForCall(bool isGetter = false);
384     void restoreLiveRegistersFromStackForCallWithThrownException();
385     void restoreLiveRegistersFromStackForCall(const RegisterSet& dontRestore);
386
387     const RegisterSet& liveRegistersForCall()
388     {
389         RELEASE_ASSERT(m_calculatedRegistersForCallAndExceptionHandling);
390         return m_liveRegistersForCall;
391     }
392
393     CallSiteIndex callSiteIndexForExceptionHandlingOrOriginal();
394     CallSiteIndex callSiteIndexForExceptionHandling()
395     {
396         RELEASE_ASSERT(m_calculatedRegistersForCallAndExceptionHandling);
397         RELEASE_ASSERT(m_needsToRestoreRegistersIfException);
398         RELEASE_ASSERT(m_calculatedCallSiteIndex);
399         return m_callSiteIndex;
400     }
401
402     const HandlerInfo& originalExceptionHandler() const;
403     unsigned numberOfStackBytesUsedForRegisterPreservation() const
404     {
405         RELEASE_ASSERT(m_calculatedRegistersForCallAndExceptionHandling);
406         return m_numberOfStackBytesUsedForRegisterPreservation;
407     }
408
409     bool needsToRestoreRegistersIfException() const { return m_needsToRestoreRegistersIfException; }
410     CallSiteIndex originalCallSiteIndex() const;
411     
412     void emitExplicitExceptionHandler();
413     
414 private:
415     const RegisterSet& liveRegistersToPreserveAtExceptionHandlingCallSite()
416     {
417         RELEASE_ASSERT(m_calculatedRegistersForCallAndExceptionHandling);
418         return m_liveRegistersToPreserveAtExceptionHandlingCallSite;
419     }
420     
421     RegisterSet m_liveRegistersToPreserveAtExceptionHandlingCallSite;
422     RegisterSet m_liveRegistersForCall;
423     CallSiteIndex m_callSiteIndex { CallSiteIndex(std::numeric_limits<unsigned>::max()) };
424     unsigned m_numberOfStackBytesUsedForRegisterPreservation { std::numeric_limits<unsigned>::max() };
425     bool m_calculatedRegistersForCallAndExceptionHandling : 1;
426     bool m_needsToRestoreRegistersIfException : 1;
427     bool m_calculatedCallSiteIndex : 1;
428 };
429
430 } // namespace JSC
431
432 namespace WTF {
433
434 void printInternal(PrintStream&, JSC::AccessGenerationResult::Kind);
435 void printInternal(PrintStream&, JSC::AccessCase::AccessType);
436
437 } // namespace WTF
438
439 #endif // ENABLE(JIT)
440
441 #endif // PolymorphicAccess_h
442