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