6d033552898a4b9ed7e3411f3b2d32beabfe9d34
[WebKit-https.git] / Source / JavaScriptCore / bytecode / StructureStubInfo.h
1 /*
2  * Copyright (C) 2008-2018 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 #pragma once
27
28 #include "CodeBlock.h"
29 #include "CodeOrigin.h"
30 #include "Instruction.h"
31 #include "JITStubRoutine.h"
32 #include "MacroAssembler.h"
33 #include "Options.h"
34 #include "RegisterSet.h"
35 #include "Structure.h"
36 #include "StructureSet.h"
37 #include "StructureStubClearingWatchpoint.h"
38 #include "StubInfoSummary.h"
39
40 namespace JSC {
41
42 #if ENABLE(JIT)
43
44 class AccessCase;
45 class AccessGenerationResult;
46 class PolymorphicAccess;
47
48 enum class AccessType : int8_t {
49     Get,
50     GetWithThis,
51     GetDirect,
52     TryGet,
53     Put,
54     In,
55     InstanceOf
56 };
57
58 enum class CacheType : int8_t {
59     Unset,
60     GetByIdSelf,
61     PutByIdReplace,
62     InByIdSelf,
63     Stub,
64     ArrayLength
65 };
66
67 class StructureStubInfo {
68     WTF_MAKE_NONCOPYABLE(StructureStubInfo);
69     WTF_MAKE_FAST_ALLOCATED;
70 public:
71     StructureStubInfo(AccessType);
72     ~StructureStubInfo();
73
74     void initGetByIdSelf(CodeBlock*, Structure* baseObjectStructure, PropertyOffset);
75     void initArrayLength();
76     void initPutByIdReplace(CodeBlock*, Structure* baseObjectStructure, PropertyOffset);
77     void initInByIdSelf(CodeBlock*, Structure* baseObjectStructure, PropertyOffset);
78
79     AccessGenerationResult addAccessCase(const GCSafeConcurrentJSLocker&, CodeBlock*, const Identifier&, std::unique_ptr<AccessCase>);
80
81     void reset(CodeBlock*);
82
83     void deref();
84     void aboutToDie();
85
86     // Check if the stub has weak references that are dead. If it does, then it resets itself,
87     // either entirely or just enough to ensure that those dead pointers don't get used anymore.
88     void visitWeakReferences(CodeBlock*);
89     
90     // This returns true if it has marked everything that it will ever mark.
91     bool propagateTransitions(SlotVisitor&);
92         
93     ALWAYS_INLINE bool considerCaching(CodeBlock* codeBlock, Structure* structure)
94     {
95         // We never cache non-cells.
96         if (!structure) {
97             sawNonCell = true;
98             return false;
99         }
100         
101         // This method is called from the Optimize variants of IC slow paths. The first part of this
102         // method tries to determine if the Optimize variant should really behave like the
103         // non-Optimize variant and leave the IC untouched.
104         //
105         // If we determine that we should do something to the IC then the next order of business is
106         // to determine if this Structure would impact the IC at all. We know that it won't, if we
107         // have already buffered something on its behalf. That's what the bufferedStructures set is
108         // for.
109         
110         everConsidered = true;
111         if (!countdown) {
112             // Check if we have been doing repatching too frequently. If so, then we should cool off
113             // for a while.
114             WTF::incrementWithSaturation(repatchCount);
115             if (repatchCount > Options::repatchCountForCoolDown()) {
116                 // We've been repatching too much, so don't do it now.
117                 repatchCount = 0;
118                 // The amount of time we require for cool-down depends on the number of times we've
119                 // had to cool down in the past. The relationship is exponential. The max value we
120                 // allow here is 2^256 - 2, since the slow paths may increment the count to indicate
121                 // that they'd like to temporarily skip patching just this once.
122                 countdown = WTF::leftShiftWithSaturation(
123                     static_cast<uint8_t>(Options::initialCoolDownCount()),
124                     numberOfCoolDowns,
125                     static_cast<uint8_t>(std::numeric_limits<uint8_t>::max() - 1));
126                 WTF::incrementWithSaturation(numberOfCoolDowns);
127                 
128                 // We may still have had something buffered. Trigger generation now.
129                 bufferingCountdown = 0;
130                 return true;
131             }
132             
133             // We don't want to return false due to buffering indefinitely.
134             if (!bufferingCountdown) {
135                 // Note that when this returns true, it's possible that we will not even get an
136                 // AccessCase because this may cause Repatch.cpp to simply do an in-place
137                 // repatching.
138                 return true;
139             }
140             
141             bufferingCountdown--;
142             
143             // Now protect the IC buffering. We want to proceed only if this is a structure that
144             // we don't already have a case buffered for. Note that if this returns true but the
145             // bufferingCountdown is not zero then we will buffer the access case for later without
146             // immediately generating code for it.
147             //
148             // NOTE: This will behave oddly for InstanceOf if the user varies the prototype but not
149             // the base's structure. That seems unlikely for the canonical use of instanceof, where
150             // the prototype is fixed.
151             bool isNewlyAdded = bufferedStructures.add(structure);
152             if (isNewlyAdded) {
153                 VM& vm = *codeBlock->vm();
154                 vm.heap.writeBarrier(codeBlock);
155             }
156             return isNewlyAdded;
157         }
158         countdown--;
159         return false;
160     }
161
162     StubInfoSummary summary() const;
163     
164     static StubInfoSummary summary(const StructureStubInfo*);
165
166     bool containsPC(void* pc) const;
167
168     CodeOrigin codeOrigin;
169     CallSiteIndex callSiteIndex;
170
171     union {
172         struct {
173             WriteBarrierBase<Structure> baseObjectStructure;
174             PropertyOffset offset;
175         } byIdSelf;
176         PolymorphicAccess* stub;
177     } u;
178     
179     // Represents those structures that already have buffered AccessCases in the PolymorphicAccess.
180     // Note that it's always safe to clear this. If we clear it prematurely, then if we see the same
181     // structure again during this buffering countdown, we will create an AccessCase object for it.
182     // That's not so bad - we'll get rid of the redundant ones once we regenerate.
183     StructureSet bufferedStructures;
184     
185     struct {
186         CodeLocationLabel<JITStubRoutinePtrTag> start; // This is either the start of the inline IC for *byId caches. or the location of patchable jump for 'instanceof' caches.
187         RegisterSet usedRegisters;
188         uint32_t inlineSize;
189         int32_t deltaFromStartToSlowPathCallLocation;
190         int32_t deltaFromStartToSlowPathStart;
191
192         int8_t baseGPR;
193         int8_t valueGPR;
194         int8_t thisGPR;
195 #if USE(JSVALUE32_64)
196         int8_t valueTagGPR;
197         int8_t baseTagGPR;
198         int8_t thisTagGPR;
199 #endif
200     } patch;
201
202     CodeLocationCall<JSInternalPtrTag> slowPathCallLocation() { return patch.start.callAtOffset<JSInternalPtrTag>(patch.deltaFromStartToSlowPathCallLocation); }
203     CodeLocationLabel<JSInternalPtrTag> doneLocation() { return patch.start.labelAtOffset<JSInternalPtrTag>(patch.inlineSize); }
204     CodeLocationLabel<JITStubRoutinePtrTag> slowPathStartLocation() { return patch.start.labelAtOffset(patch.deltaFromStartToSlowPathStart); }
205     CodeLocationJump<JSInternalPtrTag> patchableJump()
206     { 
207         ASSERT(accessType == AccessType::InstanceOf);
208         return patch.start.jumpAtOffset<JSInternalPtrTag>(0);
209     }
210
211     JSValueRegs valueRegs() const
212     {
213         return JSValueRegs(
214 #if USE(JSVALUE32_64)
215             static_cast<GPRReg>(patch.valueTagGPR),
216 #endif
217             static_cast<GPRReg>(patch.valueGPR));
218     }
219
220
221     AccessType accessType;
222     CacheType cacheType;
223     uint8_t countdown; // We repatch only when this is zero. If not zero, we decrement.
224     uint8_t repatchCount;
225     uint8_t numberOfCoolDowns;
226     uint8_t bufferingCountdown;
227     bool resetByGC : 1;
228     bool tookSlowPath : 1;
229     bool everConsidered : 1;
230     bool prototypeIsKnownObject : 1; // Only relevant for InstanceOf.
231     bool sawNonCell : 1;
232 };
233
234 inline CodeOrigin getStructureStubInfoCodeOrigin(StructureStubInfo& structureStubInfo)
235 {
236     return structureStubInfo.codeOrigin;
237 }
238
239 inline J_JITOperation_ESsiJI appropriateOptimizingGetByIdFunction(AccessType type)
240 {
241     switch (type) {
242     case AccessType::Get:
243         return operationGetByIdOptimize;
244     case AccessType::TryGet:
245         return operationTryGetByIdOptimize;
246     case AccessType::GetDirect:
247         return operationGetByIdDirectOptimize;
248     case AccessType::GetWithThis:
249     default:
250         ASSERT_NOT_REACHED();
251         return nullptr;
252     }
253 }
254
255 inline J_JITOperation_EJI appropriateGenericGetByIdFunction(AccessType type)
256 {
257     switch (type) {
258     case AccessType::Get:
259         return operationGetByIdGeneric;
260     case AccessType::TryGet:
261         return operationTryGetByIdGeneric;
262     case AccessType::GetDirect:
263         return operationGetByIdDirectGeneric;
264     case AccessType::GetWithThis:
265     default:
266         ASSERT_NOT_REACHED();
267         return nullptr;
268     }
269 }
270
271 #else
272
273 class StructureStubInfo;
274
275 #endif // ENABLE(JIT)
276
277 typedef HashMap<CodeOrigin, StructureStubInfo*, CodeOriginApproximateHash> StubInfoMap;
278
279 } // namespace JSC