1234245e456ee63c5ae0a8dbe071d4c57c66af13
[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     
252     // FIXME: This only exists because of how AccessCase puts post-generation things into itself.
253     // https://bugs.webkit.org/show_bug.cgi?id=156456
254     std::unique_ptr<AccessCase> clone() const;
255     
256     // Perform any action that must be performed before the end of the epoch in which the case
257     // was created. Returns a set of watchpoint sets that will need to be watched.
258     Vector<WatchpointSet*, 2> commit(VM&, const Identifier&);
259
260     // Fall through on success. Two kinds of failures are supported: fall-through, which means that we
261     // should try a different case; and failure, which means that this was the right case but it needs
262     // help from the slow path.
263     void generateWithGuard(AccessGenerationState&, MacroAssembler::JumpList& fallThrough);
264
265     // Fall through on success, add a jump to the failure list on failure.
266     void generate(AccessGenerationState&);
267     
268     void generateImpl(AccessGenerationState&);
269     void emitIntrinsicGetter(AccessGenerationState&);
270     
271     AccessType m_type { Load };
272     State m_state { Primordial };
273     PropertyOffset m_offset { invalidOffset };
274
275     // Usually this is the structure that we expect the base object to have. But, this is the *new*
276     // structure for a transition and we rely on the fact that it has a strong reference to the old
277     // structure. For proxies, this is the structure of the object behind the proxy.
278     WriteBarrier<Structure> m_structure;
279
280     ObjectPropertyConditionSet m_conditionSet;
281
282     class RareData {
283         WTF_MAKE_FAST_ALLOCATED;
284     public:
285         RareData()
286             : viaProxy(false)
287         {
288             customAccessor.opaque = nullptr;
289         }
290         
291         bool viaProxy;
292         RefPtr<WatchpointSet> additionalSet;
293         // FIXME: This should probably live in the stub routine object.
294         // https://bugs.webkit.org/show_bug.cgi?id=156456
295         std::unique_ptr<CallLinkInfo> callLinkInfo;
296         union {
297             PropertySlot::GetValueFunc getter;
298             PutPropertySlot::PutValueFunc setter;
299             void* opaque;
300         } customAccessor;
301         WriteBarrier<JSObject> customSlotBase;
302         WriteBarrier<JSFunction> intrinsicFunction;
303     };
304
305     std::unique_ptr<RareData> m_rareData;
306 };
307
308 class AccessGenerationResult {
309 public:
310     enum Kind {
311         MadeNoChanges,
312         GaveUp,
313         Buffered,
314         GeneratedNewCode,
315         GeneratedFinalCode // Generated so much code that we never want to generate code again.
316     };
317     
318     AccessGenerationResult()
319     {
320     }
321     
322     AccessGenerationResult(Kind kind)
323         : m_kind(kind)
324     {
325         RELEASE_ASSERT(kind != GeneratedNewCode);
326         RELEASE_ASSERT(kind != GeneratedFinalCode);
327     }
328     
329     AccessGenerationResult(Kind kind, MacroAssemblerCodePtr code)
330         : m_kind(kind)
331         , m_code(code)
332     {
333         RELEASE_ASSERT(kind == GeneratedNewCode || kind == GeneratedFinalCode);
334         RELEASE_ASSERT(code);
335     }
336     
337     bool operator==(const AccessGenerationResult& other) const
338     {
339         return m_kind == other.m_kind && m_code == other.m_code;
340     }
341     
342     bool operator!=(const AccessGenerationResult& other) const
343     {
344         return !(*this == other);
345     }
346     
347     explicit operator bool() const
348     {
349         return *this != AccessGenerationResult();
350     }
351     
352     Kind kind() const { return m_kind; }
353     
354     const MacroAssemblerCodePtr& code() const { return m_code; }
355     
356     bool madeNoChanges() const { return m_kind == MadeNoChanges; }
357     bool gaveUp() const { return m_kind == GaveUp; }
358     bool buffered() const { return m_kind == Buffered; }
359     bool generatedNewCode() const { return m_kind == GeneratedNewCode; }
360     bool generatedFinalCode() const { return m_kind == GeneratedFinalCode; }
361     
362     // If we gave up on this attempt to generate code, or if we generated the "final" code, then we
363     // should give up after this.
364     bool shouldGiveUpNow() const { return gaveUp() || generatedFinalCode(); }
365     
366     bool generatedSomeCode() const { return generatedNewCode() || generatedFinalCode(); }
367     
368     void dump(PrintStream&) const;
369     
370 private:
371     Kind m_kind;
372     MacroAssemblerCodePtr m_code;
373 };
374
375 class PolymorphicAccess {
376     WTF_MAKE_NONCOPYABLE(PolymorphicAccess);
377     WTF_MAKE_FAST_ALLOCATED;
378 public:
379     PolymorphicAccess();
380     ~PolymorphicAccess();
381
382     // When this fails (returns GaveUp), this will leave the old stub intact but you should not try
383     // to call this method again for that PolymorphicAccess instance.
384     AccessGenerationResult addCases(
385         VM&, CodeBlock*, StructureStubInfo&, const Identifier&, Vector<std::unique_ptr<AccessCase>>);
386
387     AccessGenerationResult addCase(
388         VM&, CodeBlock*, StructureStubInfo&, const Identifier&, std::unique_ptr<AccessCase>);
389     
390     AccessGenerationResult regenerate(VM&, CodeBlock*, StructureStubInfo&, const Identifier&);
391     
392     bool isEmpty() const { return m_list.isEmpty(); }
393     unsigned size() const { return m_list.size(); }
394     const AccessCase& at(unsigned i) const { return *m_list[i]; }
395     const AccessCase& operator[](unsigned i) const { return *m_list[i]; }
396
397     // If this returns false then we are requesting a reset of the owning StructureStubInfo.
398     bool visitWeak(VM&) const;
399
400     void aboutToDie();
401
402     void dump(PrintStream& out) const;
403     bool containsPC(void* pc) const
404     { 
405         if (!m_stubRoutine)
406             return false;
407
408         uintptr_t pcAsInt = bitwise_cast<uintptr_t>(pc);
409         return m_stubRoutine->startAddress() <= pcAsInt && pcAsInt <= m_stubRoutine->endAddress();
410     }
411
412 private:
413     friend class AccessCase;
414     friend class CodeBlock;
415     friend struct AccessGenerationState;
416     
417     typedef Vector<std::unique_ptr<AccessCase>, 2> ListType;
418     
419     void commit(
420         VM&, std::unique_ptr<WatchpointsOnStructureStubInfo>&, CodeBlock*, StructureStubInfo&,
421         const Identifier&, AccessCase&);
422
423     MacroAssemblerCodePtr regenerate(
424         VM&, CodeBlock*, StructureStubInfo&, const Identifier&, ListType& cases);
425
426     ListType m_list;
427     RefPtr<JITStubRoutine> m_stubRoutine;
428     std::unique_ptr<WatchpointsOnStructureStubInfo> m_watchpoints;
429     std::unique_ptr<Vector<WriteBarrier<JSCell>>> m_weakReferences;
430 };
431
432 struct AccessGenerationState {
433     AccessGenerationState()
434         : m_calculatedRegistersForCallAndExceptionHandling(false)
435         , m_needsToRestoreRegistersIfException(false)
436         , m_calculatedCallSiteIndex(false)
437     {
438     }
439     CCallHelpers* jit { nullptr };
440     ScratchRegisterAllocator* allocator;
441     ScratchRegisterAllocator::PreservedState preservedReusedRegisterState;
442     PolymorphicAccess* access { nullptr };
443     StructureStubInfo* stubInfo { nullptr };
444     MacroAssembler::JumpList success;
445     MacroAssembler::JumpList failAndRepatch;
446     MacroAssembler::JumpList failAndIgnore;
447     GPRReg baseGPR { InvalidGPRReg };
448     JSValueRegs valueRegs;
449     GPRReg scratchGPR { InvalidGPRReg };
450     const Identifier* ident;
451     std::unique_ptr<WatchpointsOnStructureStubInfo> watchpoints;
452     Vector<WriteBarrier<JSCell>> weakReferences;
453
454     Watchpoint* addWatchpoint(const ObjectPropertyCondition& = ObjectPropertyCondition());
455
456     void restoreScratch();
457     void succeed();
458
459     void calculateLiveRegistersForCallAndExceptionHandling(const RegisterSet& extra = RegisterSet());
460
461     void preserveLiveRegistersToStackForCall(const RegisterSet& extra = RegisterSet());
462
463     void restoreLiveRegistersFromStackForCall(bool isGetter = false);
464     void restoreLiveRegistersFromStackForCallWithThrownException();
465     void restoreLiveRegistersFromStackForCall(const RegisterSet& dontRestore);
466
467     const RegisterSet& liveRegistersForCall()
468     {
469         RELEASE_ASSERT(m_calculatedRegistersForCallAndExceptionHandling);
470         return m_liveRegistersForCall;
471     }
472
473     CallSiteIndex callSiteIndexForExceptionHandlingOrOriginal();
474     CallSiteIndex callSiteIndexForExceptionHandling()
475     {
476         RELEASE_ASSERT(m_calculatedRegistersForCallAndExceptionHandling);
477         RELEASE_ASSERT(m_needsToRestoreRegistersIfException);
478         RELEASE_ASSERT(m_calculatedCallSiteIndex);
479         return m_callSiteIndex;
480     }
481
482     const HandlerInfo& originalExceptionHandler() const;
483     unsigned numberOfStackBytesUsedForRegisterPreservation() const
484     {
485         RELEASE_ASSERT(m_calculatedRegistersForCallAndExceptionHandling);
486         return m_numberOfStackBytesUsedForRegisterPreservation;
487     }
488
489     bool needsToRestoreRegistersIfException() const { return m_needsToRestoreRegistersIfException; }
490     CallSiteIndex originalCallSiteIndex() const;
491     
492     void emitExplicitExceptionHandler();
493     
494 private:
495     const RegisterSet& liveRegistersToPreserveAtExceptionHandlingCallSite()
496     {
497         RELEASE_ASSERT(m_calculatedRegistersForCallAndExceptionHandling);
498         return m_liveRegistersToPreserveAtExceptionHandlingCallSite;
499     }
500     
501     RegisterSet m_liveRegistersToPreserveAtExceptionHandlingCallSite;
502     RegisterSet m_liveRegistersForCall;
503     CallSiteIndex m_callSiteIndex { CallSiteIndex(std::numeric_limits<unsigned>::max()) };
504     unsigned m_numberOfStackBytesUsedForRegisterPreservation { std::numeric_limits<unsigned>::max() };
505     bool m_calculatedRegistersForCallAndExceptionHandling : 1;
506     bool m_needsToRestoreRegistersIfException : 1;
507     bool m_calculatedCallSiteIndex : 1;
508 };
509
510 } // namespace JSC
511
512 namespace WTF {
513
514 void printInternal(PrintStream&, JSC::AccessGenerationResult::Kind);
515 void printInternal(PrintStream&, JSC::AccessCase::AccessType);
516 void printInternal(PrintStream&, JSC::AccessCase::State);
517
518 } // namespace WTF
519
520 #endif // ENABLE(JIT)
521
522 #endif // PolymorphicAccess_h
523