3229799d091b12aa519971105a2e41c1e18be6cb
[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     bool doesCalls() const
158     {
159         switch (type()) {
160         case Getter:
161         case Setter:
162         case CustomValueGetter:
163         case CustomAccessorGetter:
164         case CustomValueSetter:
165         case CustomAccessorSetter:
166             return true;
167         default:
168             return false;
169         }
170     }
171
172     bool isGetter() const
173     {
174         switch (type()) {
175         case Getter:
176         case CustomValueGetter:
177         case CustomAccessorGetter:
178             return true;
179         default:
180             return false;
181         }
182     }
183
184     CallLinkInfo* callLinkInfo() const
185     {
186         if (!m_rareData)
187             return nullptr;
188         return m_rareData->callLinkInfo.get();
189     }
190
191     // Is it still possible for this case to ever be taken?
192     bool couldStillSucceed() const;
193     
194     static bool canEmitIntrinsicGetter(JSFunction*, Structure*);
195
196     bool canBeReplacedByMegamorphicLoad() const;
197
198     // If this method returns true, then it's a good idea to remove 'other' from the access once 'this'
199     // is added. This method assumes that in case of contradictions, 'this' represents a newer, and so
200     // more useful, truth. This method can be conservative; it will return false when it doubt.
201     bool canReplace(const AccessCase& other) const;
202
203     void dump(PrintStream& out) const;
204     
205 private:
206     friend class CodeBlock;
207     friend class PolymorphicAccess;
208
209     AccessCase();
210
211     bool visitWeak(VM&) const;
212
213     // Fall through on success. Two kinds of failures are supported: fall-through, which means that we
214     // should try a different case; and failure, which means that this was the right case but it needs
215     // help from the slow path.
216     void generateWithGuard(AccessGenerationState&, MacroAssembler::JumpList& fallThrough);
217
218     // Fall through on success, add a jump to the failure list on failure.
219     void generate(AccessGenerationState&);
220     void emitIntrinsicGetter(AccessGenerationState&);
221     
222     AccessType m_type { Load };
223     PropertyOffset m_offset { invalidOffset };
224
225     // Usually this is the structure that we expect the base object to have. But, this is the *new*
226     // structure for a transition and we rely on the fact that it has a strong reference to the old
227     // structure. For proxies, this is the structure of the object behind the proxy.
228     WriteBarrier<Structure> m_structure;
229
230     ObjectPropertyConditionSet m_conditionSet;
231
232     class RareData {
233         WTF_MAKE_FAST_ALLOCATED;
234     public:
235         RareData()
236             : viaProxy(false)
237         {
238             customAccessor.opaque = nullptr;
239         }
240         
241         bool viaProxy;
242         RefPtr<WatchpointSet> additionalSet;
243         std::unique_ptr<CallLinkInfo> callLinkInfo;
244         union {
245             PropertySlot::GetValueFunc getter;
246             PutPropertySlot::PutValueFunc setter;
247             void* opaque;
248         } customAccessor;
249         WriteBarrier<JSObject> customSlotBase;
250         WriteBarrier<JSFunction> intrinsicFunction;
251     };
252
253     std::unique_ptr<RareData> m_rareData;
254 };
255
256 class AccessGenerationResult {
257 public:
258     enum Kind {
259         MadeNoChanges,
260         GaveUp,
261         GeneratedNewCode
262     };
263     
264     AccessGenerationResult()
265     {
266     }
267     
268     AccessGenerationResult(Kind kind)
269         : m_kind(kind)
270     {
271         ASSERT(kind != GeneratedNewCode);
272     }
273     
274     AccessGenerationResult(MacroAssemblerCodePtr code)
275         : m_kind(GeneratedNewCode)
276         , m_code(code)
277     {
278         RELEASE_ASSERT(code);
279     }
280     
281     bool operator==(const AccessGenerationResult& other) const
282     {
283         return m_kind == other.m_kind && m_code == other.m_code;
284     }
285     
286     bool operator!=(const AccessGenerationResult& other) const
287     {
288         return !(*this == other);
289     }
290     
291     explicit operator bool() const
292     {
293         return *this != AccessGenerationResult();
294     }
295     
296     Kind kind() const { return m_kind; }
297     
298     const MacroAssemblerCodePtr& code() const { return m_code; }
299     
300     bool madeNoChanges() const { return m_kind == MadeNoChanges; }
301     bool gaveUp() const { return m_kind == GaveUp; }
302     bool generatedNewCode() const { return m_kind == GeneratedNewCode; }
303     
304     void dump(PrintStream&) const;
305     
306 private:
307     Kind m_kind;
308     MacroAssemblerCodePtr m_code;
309 };
310
311 class PolymorphicAccess {
312     WTF_MAKE_NONCOPYABLE(PolymorphicAccess);
313     WTF_MAKE_FAST_ALLOCATED;
314 public:
315     PolymorphicAccess();
316     ~PolymorphicAccess();
317
318     // This may return null, in which case the old stub routine is left intact. You are required to
319     // pass a vector of non-null access cases. This will prune the access cases by rejecting any case
320     // in the list that is subsumed by a later case in the list.
321     AccessGenerationResult regenerateWithCases(
322         VM&, CodeBlock*, StructureStubInfo&, const Identifier&, Vector<std::unique_ptr<AccessCase>>);
323
324     AccessGenerationResult regenerateWithCase(
325         VM&, CodeBlock*, StructureStubInfo&, const Identifier&, std::unique_ptr<AccessCase>);
326     
327     bool isEmpty() const { return m_list.isEmpty(); }
328     unsigned size() const { return m_list.size(); }
329     const AccessCase& at(unsigned i) const { return *m_list[i]; }
330     const AccessCase& operator[](unsigned i) const { return *m_list[i]; }
331
332     // If this returns false then we are requesting a reset of the owning StructureStubInfo.
333     bool visitWeak(VM&) const;
334
335     void aboutToDie();
336
337     void dump(PrintStream& out) const;
338     bool containsPC(void* pc) const
339     { 
340         if (!m_stubRoutine)
341             return false;
342
343         uintptr_t pcAsInt = bitwise_cast<uintptr_t>(pc);
344         return m_stubRoutine->startAddress() <= pcAsInt && pcAsInt <= m_stubRoutine->endAddress();
345     }
346
347 private:
348     friend class AccessCase;
349     friend class CodeBlock;
350     friend struct AccessGenerationState;
351     
352     typedef Vector<std::unique_ptr<AccessCase>, 2> ListType;
353
354     MacroAssemblerCodePtr regenerate(
355         VM&, CodeBlock*, StructureStubInfo&, const Identifier&, ListType& cases);
356
357     ListType m_list;
358     RefPtr<JITStubRoutine> m_stubRoutine;
359     std::unique_ptr<WatchpointsOnStructureStubInfo> m_watchpoints;
360     std::unique_ptr<Vector<WriteBarrier<JSCell>>> m_weakReferences;
361 };
362
363 struct AccessGenerationState {
364     AccessGenerationState()
365         : m_calculatedRegistersForCallAndExceptionHandling(false)
366         , m_needsToRestoreRegistersIfException(false)
367         , m_calculatedCallSiteIndex(false)
368     {
369     }
370     CCallHelpers* jit { nullptr };
371     ScratchRegisterAllocator* allocator;
372     ScratchRegisterAllocator::PreservedState preservedReusedRegisterState;
373     PolymorphicAccess* access { nullptr };
374     StructureStubInfo* stubInfo { nullptr };
375     MacroAssembler::JumpList success;
376     MacroAssembler::JumpList failAndRepatch;
377     MacroAssembler::JumpList failAndIgnore;
378     GPRReg baseGPR { InvalidGPRReg };
379     JSValueRegs valueRegs;
380     GPRReg scratchGPR { InvalidGPRReg };
381     const Identifier* ident;
382     std::unique_ptr<WatchpointsOnStructureStubInfo> watchpoints;
383     Vector<WriteBarrier<JSCell>> weakReferences;
384
385     Watchpoint* addWatchpoint(const ObjectPropertyCondition& = ObjectPropertyCondition());
386
387     void restoreScratch();
388     void succeed();
389
390     void calculateLiveRegistersForCallAndExceptionHandling(const RegisterSet& extra = RegisterSet());
391
392     void preserveLiveRegistersToStackForCall(const RegisterSet& extra = RegisterSet());
393
394     void restoreLiveRegistersFromStackForCall(bool isGetter = false);
395     void restoreLiveRegistersFromStackForCallWithThrownException();
396     void restoreLiveRegistersFromStackForCall(const RegisterSet& dontRestore);
397
398     const RegisterSet& liveRegistersForCall()
399     {
400         RELEASE_ASSERT(m_calculatedRegistersForCallAndExceptionHandling);
401         return m_liveRegistersForCall;
402     }
403
404     CallSiteIndex callSiteIndexForExceptionHandlingOrOriginal();
405     CallSiteIndex callSiteIndexForExceptionHandling()
406     {
407         RELEASE_ASSERT(m_calculatedRegistersForCallAndExceptionHandling);
408         RELEASE_ASSERT(m_needsToRestoreRegistersIfException);
409         RELEASE_ASSERT(m_calculatedCallSiteIndex);
410         return m_callSiteIndex;
411     }
412
413     const HandlerInfo& originalExceptionHandler() const;
414     unsigned numberOfStackBytesUsedForRegisterPreservation() const
415     {
416         RELEASE_ASSERT(m_calculatedRegistersForCallAndExceptionHandling);
417         return m_numberOfStackBytesUsedForRegisterPreservation;
418     }
419
420     bool needsToRestoreRegistersIfException() const { return m_needsToRestoreRegistersIfException; }
421     CallSiteIndex originalCallSiteIndex() const;
422     
423     void emitExplicitExceptionHandler();
424     
425 private:
426     const RegisterSet& liveRegistersToPreserveAtExceptionHandlingCallSite()
427     {
428         RELEASE_ASSERT(m_calculatedRegistersForCallAndExceptionHandling);
429         return m_liveRegistersToPreserveAtExceptionHandlingCallSite;
430     }
431     
432     RegisterSet m_liveRegistersToPreserveAtExceptionHandlingCallSite;
433     RegisterSet m_liveRegistersForCall;
434     CallSiteIndex m_callSiteIndex { CallSiteIndex(std::numeric_limits<unsigned>::max()) };
435     unsigned m_numberOfStackBytesUsedForRegisterPreservation { std::numeric_limits<unsigned>::max() };
436     bool m_calculatedRegistersForCallAndExceptionHandling : 1;
437     bool m_needsToRestoreRegistersIfException : 1;
438     bool m_calculatedCallSiteIndex : 1;
439 };
440
441 } // namespace JSC
442
443 namespace WTF {
444
445 void printInternal(PrintStream&, JSC::AccessGenerationResult::Kind);
446 void printInternal(PrintStream&, JSC::AccessCase::AccessType);
447
448 } // namespace WTF
449
450 #endif // ENABLE(JIT)
451
452 #endif // PolymorphicAccess_h
453