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