References from code to Structures should be stronger than weak
[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 #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 // An AccessCase describes one of the cases of a PolymorphicAccess. A PolymorphicAccess represents a
51 // planned (to generate in future) or generated stub for some inline cache. That stub contains fast
52 // path code for some finite number of fast cases, each described by an AccessCase object.
53 //
54 // An AccessCase object has a lifecycle that proceeds through several states. Note that the states
55 // of AccessCase have a lot to do with the global effect epoch (we'll say epoch for short). This is
56 // a simple way of reasoning about the state of the system outside this AccessCase. Any observable
57 // effect - like storing to a property, changing an object's structure, etc. - increments the epoch.
58 // The states are:
59 //
60 // Primordial:   This is an AccessCase that was just allocated. It does not correspond to any actual
61 //               code and it is not owned by any PolymorphicAccess. In this state, the AccessCase
62 //               assumes that it is in the same epoch as when it was created. This is important
63 //               because it may make claims about itself ("I represent a valid case so long as you
64 //               register a watchpoint on this set") that could be contradicted by some outside
65 //               effects (like firing and deleting the watchpoint set in question). This is also the
66 //               state that an AccessCase is in when it is cloned (AccessCase::clone()).
67 //
68 // Committed:    This happens as soon as some PolymorphicAccess takes ownership of this AccessCase.
69 //               In this state, the AccessCase no longer assumes anything about the epoch. To
70 //               accomplish this, PolymorphicAccess calls AccessCase::commit(). This must be done
71 //               during the same epoch when the AccessCase was created, either by the client or by
72 //               clone(). When created by the client, committing during the same epoch works because
73 //               we can be sure that whatever watchpoint sets they spoke of are still valid. When
74 //               created by clone(), we can be sure that the set is still valid because the original
75 //               of the clone still has watchpoints on it.
76 //
77 // Generated:    This is the state when the PolymorphicAccess generates code for this case by
78 //               calling AccessCase::generate() or AccessCase::generateWithGuard(). At this point
79 //               the case object will have some extra stuff in it, like possibly the CallLinkInfo
80 //               object associated with the inline cache.
81 //               FIXME: Moving into the Generated state should not mutate the AccessCase object or
82 //               put more stuff into it. If we fix this, then we can get rid of AccessCase::clone().
83 //               https://bugs.webkit.org/show_bug.cgi?id=156456
84 //
85 // An AccessCase may be destroyed while in any of these states.
86 //
87 // We will sometimes buffer committed AccessCases in the PolymorphicAccess object before generating
88 // code. This allows us to only regenerate once we've accumulated (hopefully) more than one new
89 // AccessCase.
90 class AccessCase {
91     WTF_MAKE_NONCOPYABLE(AccessCase);
92     WTF_MAKE_FAST_ALLOCATED;
93 public:
94     enum AccessType : uint8_t {
95         Load,
96         MegamorphicLoad,
97         Transition,
98         Replace,
99         Miss,
100         GetGetter,
101         Getter,
102         Setter,
103         CustomValueGetter,
104         CustomAccessorGetter,
105         CustomValueSetter,
106         CustomAccessorSetter,
107         IntrinsicGetter,
108         InHit,
109         InMiss,
110         ArrayLength,
111         StringLength,
112         DirectArgumentsLength,
113         ScopedArgumentsLength
114     };
115     
116     enum State : uint8_t {
117         Primordial,
118         Committed,
119         Generated
120     };
121
122     static std::unique_ptr<AccessCase> tryGet(
123         VM&, JSCell* owner, AccessType, PropertyOffset, Structure*,
124         const ObjectPropertyConditionSet& = ObjectPropertyConditionSet(),
125         bool viaProxy = false,
126         WatchpointSet* additionalSet = nullptr);
127
128     static std::unique_ptr<AccessCase> get(
129         VM&, JSCell* owner, AccessType, PropertyOffset, Structure*,
130         const ObjectPropertyConditionSet& = ObjectPropertyConditionSet(),
131         bool viaProxy = false,
132         WatchpointSet* additionalSet = nullptr,
133         PropertySlot::GetValueFunc = nullptr,
134         JSObject* customSlotBase = nullptr);
135     
136     static std::unique_ptr<AccessCase> megamorphicLoad(VM&, JSCell* owner);
137     
138     static std::unique_ptr<AccessCase> replace(VM&, JSCell* owner, Structure*, PropertyOffset);
139
140     static std::unique_ptr<AccessCase> transition(
141         VM&, JSCell* owner, Structure* oldStructure, Structure* newStructure, PropertyOffset,
142         const ObjectPropertyConditionSet& = ObjectPropertyConditionSet());
143
144     static std::unique_ptr<AccessCase> setter(
145         VM&, JSCell* owner, AccessType, Structure*, PropertyOffset,
146         const ObjectPropertyConditionSet&, PutPropertySlot::PutValueFunc = nullptr,
147         JSObject* customSlotBase = nullptr);
148
149     static std::unique_ptr<AccessCase> in(
150         VM&, JSCell* owner, AccessType, Structure*,
151         const ObjectPropertyConditionSet& = ObjectPropertyConditionSet());
152
153     static std::unique_ptr<AccessCase> getLength(VM&, JSCell* owner, AccessType);
154     static std::unique_ptr<AccessCase> getIntrinsic(VM&, JSCell* owner, JSFunction* intrinsic, PropertyOffset, Structure*, const ObjectPropertyConditionSet&);
155     
156     static std::unique_ptr<AccessCase> fromStructureStubInfo(VM&, JSCell* owner, StructureStubInfo&);
157
158     ~AccessCase();
159     
160     AccessType type() const { return m_type; }
161     State state() const { return m_state; }
162     PropertyOffset offset() const { return m_offset; }
163     bool viaProxy() const { return m_rareData ? m_rareData->viaProxy : false; }
164     
165     Structure* structure() const
166     {
167         if (m_type == Transition)
168             return m_structure->previousID();
169         return m_structure.get();
170     }
171     bool guardedByStructureCheck() const;
172
173     Structure* newStructure() const
174     {
175         ASSERT(m_type == Transition);
176         return m_structure.get();
177     }
178     
179     ObjectPropertyConditionSet conditionSet() const { return m_conditionSet; }
180     JSFunction* intrinsicFunction() const
181     {
182         ASSERT(type() == IntrinsicGetter && m_rareData);
183         return m_rareData->intrinsicFunction.get();
184     }
185     Intrinsic intrinsic() const
186     {
187         return intrinsicFunction()->intrinsic();
188     }
189
190     WatchpointSet* additionalSet() const
191     {
192         return m_rareData ? m_rareData->additionalSet.get() : nullptr;
193     }
194
195     JSObject* customSlotBase() const
196     {
197         return m_rareData ? m_rareData->customSlotBase.get() : nullptr;
198     }
199
200     JSObject* alternateBase() const;
201
202     // If you supply the optional vector, this will append the set of cells that this will need to keep alive
203     // past the call.
204     bool doesCalls(Vector<JSCell*>* cellsToMark = nullptr) const;
205
206     bool isGetter() const
207     {
208         switch (type()) {
209         case Getter:
210         case CustomValueGetter:
211         case CustomAccessorGetter:
212             return true;
213         default:
214             return false;
215         }
216     }
217
218     // This can return null even for a getter/setter, if it hasn't been generated yet. That's
219     // actually somewhat likely because of how we do buffering of new cases.
220     CallLinkInfo* callLinkInfo() const
221     {
222         if (!m_rareData)
223             return nullptr;
224         return m_rareData->callLinkInfo.get();
225     }
226     
227     // Is it still possible for this case to ever be taken?  Must call this as a prerequisite for
228     // calling generate() and friends.  If this returns true, then you can call generate().  If
229     // this returns false, then generate() will crash.  You must call generate() in the same epoch
230     // as when you called couldStillSucceed().
231     bool couldStillSucceed() const;
232     
233     static bool canEmitIntrinsicGetter(JSFunction*, Structure*);
234
235     bool canBeReplacedByMegamorphicLoad() const;
236
237     // If this method returns true, then it's a good idea to remove 'other' from the access once 'this'
238     // is added. This method assumes that in case of contradictions, 'this' represents a newer, and so
239     // more useful, truth. This method can be conservative; it will return false when it doubt.
240     bool canReplace(const AccessCase& other) const;
241
242     void dump(PrintStream& out) const;
243     
244 private:
245     friend class CodeBlock;
246     friend class PolymorphicAccess;
247
248     AccessCase();
249
250     bool visitWeak(VM&) const;
251     bool propagateTransitions(SlotVisitor&) const;
252     
253     // FIXME: This only exists because of how AccessCase puts post-generation things into itself.
254     // https://bugs.webkit.org/show_bug.cgi?id=156456
255     std::unique_ptr<AccessCase> clone() const;
256     
257     // Perform any action that must be performed before the end of the epoch in which the case
258     // was created. Returns a set of watchpoint sets that will need to be watched.
259     Vector<WatchpointSet*, 2> commit(VM&, const Identifier&);
260
261     // Fall through on success. Two kinds of failures are supported: fall-through, which means that we
262     // should try a different case; and failure, which means that this was the right case but it needs
263     // help from the slow path.
264     void generateWithGuard(AccessGenerationState&, MacroAssembler::JumpList& fallThrough);
265
266     // Fall through on success, add a jump to the failure list on failure.
267     void generate(AccessGenerationState&);
268     
269     void generateImpl(AccessGenerationState&);
270     void emitIntrinsicGetter(AccessGenerationState&);
271     
272     AccessType m_type { Load };
273     State m_state { Primordial };
274     PropertyOffset m_offset { invalidOffset };
275
276     // Usually this is the structure that we expect the base object to have. But, this is the *new*
277     // structure for a transition and we rely on the fact that it has a strong reference to the old
278     // structure. For proxies, this is the structure of the object behind the proxy.
279     WriteBarrier<Structure> m_structure;
280
281     ObjectPropertyConditionSet m_conditionSet;
282
283     class RareData {
284         WTF_MAKE_FAST_ALLOCATED;
285     public:
286         RareData()
287             : viaProxy(false)
288         {
289             customAccessor.opaque = nullptr;
290         }
291         
292         bool viaProxy;
293         RefPtr<WatchpointSet> additionalSet;
294         // FIXME: This should probably live in the stub routine object.
295         // https://bugs.webkit.org/show_bug.cgi?id=156456
296         std::unique_ptr<CallLinkInfo> callLinkInfo;
297         union {
298             PropertySlot::GetValueFunc getter;
299             PutPropertySlot::PutValueFunc setter;
300             void* opaque;
301         } customAccessor;
302         WriteBarrier<JSObject> customSlotBase;
303         WriteBarrier<JSFunction> intrinsicFunction;
304     };
305
306     std::unique_ptr<RareData> m_rareData;
307 };
308
309 class AccessGenerationResult {
310 public:
311     enum Kind {
312         MadeNoChanges,
313         GaveUp,
314         Buffered,
315         GeneratedNewCode,
316         GeneratedFinalCode // Generated so much code that we never want to generate code again.
317     };
318     
319     AccessGenerationResult()
320     {
321     }
322     
323     AccessGenerationResult(Kind kind)
324         : m_kind(kind)
325     {
326         RELEASE_ASSERT(kind != GeneratedNewCode);
327         RELEASE_ASSERT(kind != GeneratedFinalCode);
328     }
329     
330     AccessGenerationResult(Kind kind, MacroAssemblerCodePtr code)
331         : m_kind(kind)
332         , m_code(code)
333     {
334         RELEASE_ASSERT(kind == GeneratedNewCode || kind == GeneratedFinalCode);
335         RELEASE_ASSERT(code);
336     }
337     
338     bool operator==(const AccessGenerationResult& other) const
339     {
340         return m_kind == other.m_kind && m_code == other.m_code;
341     }
342     
343     bool operator!=(const AccessGenerationResult& other) const
344     {
345         return !(*this == other);
346     }
347     
348     explicit operator bool() const
349     {
350         return *this != AccessGenerationResult();
351     }
352     
353     Kind kind() const { return m_kind; }
354     
355     const MacroAssemblerCodePtr& code() const { return m_code; }
356     
357     bool madeNoChanges() const { return m_kind == MadeNoChanges; }
358     bool gaveUp() const { return m_kind == GaveUp; }
359     bool buffered() const { return m_kind == Buffered; }
360     bool generatedNewCode() const { return m_kind == GeneratedNewCode; }
361     bool generatedFinalCode() const { return m_kind == GeneratedFinalCode; }
362     
363     // If we gave up on this attempt to generate code, or if we generated the "final" code, then we
364     // should give up after this.
365     bool shouldGiveUpNow() const { return gaveUp() || generatedFinalCode(); }
366     
367     bool generatedSomeCode() const { return generatedNewCode() || generatedFinalCode(); }
368     
369     void dump(PrintStream&) const;
370     
371 private:
372     Kind m_kind;
373     MacroAssemblerCodePtr m_code;
374 };
375
376 class PolymorphicAccess {
377     WTF_MAKE_NONCOPYABLE(PolymorphicAccess);
378     WTF_MAKE_FAST_ALLOCATED;
379 public:
380     PolymorphicAccess();
381     ~PolymorphicAccess();
382
383     // When this fails (returns GaveUp), this will leave the old stub intact but you should not try
384     // to call this method again for that PolymorphicAccess instance.
385     AccessGenerationResult addCases(
386         VM&, CodeBlock*, StructureStubInfo&, const Identifier&, Vector<std::unique_ptr<AccessCase>>);
387
388     AccessGenerationResult addCase(
389         VM&, CodeBlock*, StructureStubInfo&, const Identifier&, std::unique_ptr<AccessCase>);
390     
391     AccessGenerationResult regenerate(VM&, CodeBlock*, StructureStubInfo&, const Identifier&);
392     
393     bool isEmpty() const { return m_list.isEmpty(); }
394     unsigned size() const { return m_list.size(); }
395     const AccessCase& at(unsigned i) const { return *m_list[i]; }
396     const AccessCase& operator[](unsigned i) const { return *m_list[i]; }
397
398     // If this returns false then we are requesting a reset of the owning StructureStubInfo.
399     bool visitWeak(VM&) const;
400     
401     // This returns true if it has marked everything it will ever marked. This can be used as an
402     // optimization to then avoid calling this method again during the fixpoint.
403     bool propagateTransitions(SlotVisitor&) const;
404
405     void aboutToDie();
406
407     void dump(PrintStream& out) const;
408     bool containsPC(void* pc) const
409     { 
410         if (!m_stubRoutine)
411             return false;
412
413         uintptr_t pcAsInt = bitwise_cast<uintptr_t>(pc);
414         return m_stubRoutine->startAddress() <= pcAsInt && pcAsInt <= m_stubRoutine->endAddress();
415     }
416
417 private:
418     friend class AccessCase;
419     friend class CodeBlock;
420     friend struct AccessGenerationState;
421     
422     typedef Vector<std::unique_ptr<AccessCase>, 2> ListType;
423     
424     void commit(
425         VM&, std::unique_ptr<WatchpointsOnStructureStubInfo>&, CodeBlock*, StructureStubInfo&,
426         const Identifier&, AccessCase&);
427
428     MacroAssemblerCodePtr regenerate(
429         VM&, CodeBlock*, StructureStubInfo&, const Identifier&, ListType& cases);
430
431     ListType m_list;
432     RefPtr<JITStubRoutine> m_stubRoutine;
433     std::unique_ptr<WatchpointsOnStructureStubInfo> m_watchpoints;
434     std::unique_ptr<Vector<WriteBarrier<JSCell>>> m_weakReferences;
435 };
436
437 struct AccessGenerationState {
438     AccessGenerationState()
439         : m_calculatedRegistersForCallAndExceptionHandling(false)
440         , m_needsToRestoreRegistersIfException(false)
441         , m_calculatedCallSiteIndex(false)
442     {
443     }
444     CCallHelpers* jit { nullptr };
445     ScratchRegisterAllocator* allocator;
446     ScratchRegisterAllocator::PreservedState preservedReusedRegisterState;
447     PolymorphicAccess* access { nullptr };
448     StructureStubInfo* stubInfo { nullptr };
449     MacroAssembler::JumpList success;
450     MacroAssembler::JumpList failAndRepatch;
451     MacroAssembler::JumpList failAndIgnore;
452     GPRReg baseGPR { InvalidGPRReg };
453     JSValueRegs valueRegs;
454     GPRReg scratchGPR { InvalidGPRReg };
455     const Identifier* ident;
456     std::unique_ptr<WatchpointsOnStructureStubInfo> watchpoints;
457     Vector<WriteBarrier<JSCell>> weakReferences;
458
459     Watchpoint* addWatchpoint(const ObjectPropertyCondition& = ObjectPropertyCondition());
460
461     void restoreScratch();
462     void succeed();
463
464     void calculateLiveRegistersForCallAndExceptionHandling(const RegisterSet& extra = RegisterSet());
465
466     void preserveLiveRegistersToStackForCall(const RegisterSet& extra = RegisterSet());
467
468     void restoreLiveRegistersFromStackForCall(bool isGetter = false);
469     void restoreLiveRegistersFromStackForCallWithThrownException();
470     void restoreLiveRegistersFromStackForCall(const RegisterSet& dontRestore);
471
472     const RegisterSet& liveRegistersForCall()
473     {
474         RELEASE_ASSERT(m_calculatedRegistersForCallAndExceptionHandling);
475         return m_liveRegistersForCall;
476     }
477
478     CallSiteIndex callSiteIndexForExceptionHandlingOrOriginal();
479     CallSiteIndex callSiteIndexForExceptionHandling()
480     {
481         RELEASE_ASSERT(m_calculatedRegistersForCallAndExceptionHandling);
482         RELEASE_ASSERT(m_needsToRestoreRegistersIfException);
483         RELEASE_ASSERT(m_calculatedCallSiteIndex);
484         return m_callSiteIndex;
485     }
486
487     const HandlerInfo& originalExceptionHandler() const;
488     unsigned numberOfStackBytesUsedForRegisterPreservation() const
489     {
490         RELEASE_ASSERT(m_calculatedRegistersForCallAndExceptionHandling);
491         return m_numberOfStackBytesUsedForRegisterPreservation;
492     }
493
494     bool needsToRestoreRegistersIfException() const { return m_needsToRestoreRegistersIfException; }
495     CallSiteIndex originalCallSiteIndex() const;
496     
497     void emitExplicitExceptionHandler();
498     
499 private:
500     const RegisterSet& liveRegistersToPreserveAtExceptionHandlingCallSite()
501     {
502         RELEASE_ASSERT(m_calculatedRegistersForCallAndExceptionHandling);
503         return m_liveRegistersToPreserveAtExceptionHandlingCallSite;
504     }
505     
506     RegisterSet m_liveRegistersToPreserveAtExceptionHandlingCallSite;
507     RegisterSet m_liveRegistersForCall;
508     CallSiteIndex m_callSiteIndex { CallSiteIndex(std::numeric_limits<unsigned>::max()) };
509     unsigned m_numberOfStackBytesUsedForRegisterPreservation { std::numeric_limits<unsigned>::max() };
510     bool m_calculatedRegistersForCallAndExceptionHandling : 1;
511     bool m_needsToRestoreRegistersIfException : 1;
512     bool m_calculatedCallSiteIndex : 1;
513 };
514
515 } // namespace JSC
516
517 namespace WTF {
518
519 void printInternal(PrintStream&, JSC::AccessGenerationResult::Kind);
520 void printInternal(PrintStream&, JSC::AccessCase::AccessType);
521 void printInternal(PrintStream&, JSC::AccessCase::State);
522
523 } // namespace WTF
524
525 #endif // ENABLE(JIT)
526
527 #endif // PolymorphicAccess_h
528