References from code to Structures should be stronger than weak
[WebKit.git] / Source / JavaScriptCore / bytecode / StructureStubInfo.h
1 /*
2  * Copyright (C) 2008, 2012-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 StructureStubInfo_h
27 #define StructureStubInfo_h
28
29 #include "CodeOrigin.h"
30 #include "Instruction.h"
31 #include "JITStubRoutine.h"
32 #include "MacroAssembler.h"
33 #include "ObjectPropertyConditionSet.h"
34 #include "Opcode.h"
35 #include "Options.h"
36 #include "RegisterSet.h"
37 #include "Structure.h"
38 #include "StructureSet.h"
39 #include "StructureStubClearingWatchpoint.h"
40
41 namespace JSC {
42
43 #if ENABLE(JIT)
44
45 class AccessCase;
46 class AccessGenerationResult;
47 class PolymorphicAccess;
48
49 enum class AccessType : int8_t {
50     Get,
51     GetPure,
52     Put,
53     In
54 };
55
56 enum class CacheType : int8_t {
57     Unset,
58     GetByIdSelf,
59     PutByIdReplace,
60     Stub
61 };
62
63 class StructureStubInfo {
64     WTF_MAKE_NONCOPYABLE(StructureStubInfo);
65     WTF_MAKE_FAST_ALLOCATED;
66 public:
67     StructureStubInfo(AccessType);
68     ~StructureStubInfo();
69
70     void initGetByIdSelf(CodeBlock*, Structure* baseObjectStructure, PropertyOffset);
71     void initPutByIdReplace(CodeBlock*, Structure* baseObjectStructure, PropertyOffset);
72     void initStub(CodeBlock*, std::unique_ptr<PolymorphicAccess>);
73
74     AccessGenerationResult addAccessCase(CodeBlock*, const Identifier&, std::unique_ptr<AccessCase>);
75
76     void reset(CodeBlock*);
77
78     void deref();
79     void aboutToDie();
80
81     // Check if the stub has weak references that are dead. If it does, then it resets itself,
82     // either entirely or just enough to ensure that those dead pointers don't get used anymore.
83     void visitWeakReferences(CodeBlock*);
84     
85     // This returns true if it has marked everything that it will ever mark.
86     bool propagateTransitions(SlotVisitor&);
87         
88     ALWAYS_INLINE bool considerCaching(Structure* structure)
89     {
90         // We never cache non-cells.
91         if (!structure)
92             return false;
93         
94         // This method is called from the Optimize variants of IC slow paths. The first part of this
95         // method tries to determine if the Optimize variant should really behave like the
96         // non-Optimize variant and leave the IC untouched.
97         //
98         // If we determine that we should do something to the IC then the next order of business is
99         // to determine if this Structure would impact the IC at all. We know that it won't, if we
100         // have already buffered something on its behalf. That's what the bufferedStructures set is
101         // for.
102         
103         everConsidered = true;
104         if (!countdown) {
105             // Check if we have been doing repatching too frequently. If so, then we should cool off
106             // for a while.
107             WTF::incrementWithSaturation(repatchCount);
108             if (repatchCount > Options::repatchCountForCoolDown()) {
109                 // We've been repatching too much, so don't do it now.
110                 repatchCount = 0;
111                 // The amount of time we require for cool-down depends on the number of times we've
112                 // had to cool down in the past. The relationship is exponential. The max value we
113                 // allow here is 2^256 - 2, since the slow paths may increment the count to indicate
114                 // that they'd like to temporarily skip patching just this once.
115                 countdown = WTF::leftShiftWithSaturation(
116                     static_cast<uint8_t>(Options::initialCoolDownCount()),
117                     numberOfCoolDowns,
118                     static_cast<uint8_t>(std::numeric_limits<uint8_t>::max() - 1));
119                 WTF::incrementWithSaturation(numberOfCoolDowns);
120                 
121                 // We may still have had something buffered. Trigger generation now.
122                 bufferingCountdown = 0;
123                 return true;
124             }
125             
126             // We don't want to return false due to buffering indefinitely.
127             if (!bufferingCountdown) {
128                 // Note that when this returns true, it's possible that we will not even get an
129                 // AccessCase because this may cause Repatch.cpp to simply do an in-place
130                 // repatching.
131                 return true;
132             }
133             
134             bufferingCountdown--;
135             
136             // Now protect the IC buffering. We want to proceed only if this is a structure that
137             // we don't already have a case buffered for. Note that if this returns true but the
138             // bufferingCountdown is not zero then we will buffer the access case for later without
139             // immediately generating code for it.
140             return bufferedStructures.add(structure);
141         }
142         countdown--;
143         return false;
144     }
145
146     CodeLocationCall callReturnLocation;
147
148     CodeOrigin codeOrigin;
149     CallSiteIndex callSiteIndex;
150
151     bool containsPC(void* pc) const;
152
153     union {
154         struct {
155             WriteBarrierBase<Structure> baseObjectStructure;
156             PropertyOffset offset;
157         } byIdSelf;
158         PolymorphicAccess* stub;
159     } u;
160     
161     // Represents those structures that already have buffered AccessCases in the PolymorphicAccess.
162     // Note that it's always safe to clear this. If we clear it prematurely, then if we see the same
163     // structure again during this buffering countdown, we will create an AccessCase object for it.
164     // That's not so bad - we'll get rid of the redundant ones once we regenerate.
165     StructureSet bufferedStructures;
166     
167     struct {
168         int8_t baseGPR;
169 #if USE(JSVALUE32_64)
170         int8_t valueTagGPR;
171         int8_t baseTagGPR;
172 #endif
173         int8_t valueGPR;
174         RegisterSet usedRegisters;
175         int32_t deltaCallToDone;
176         int32_t deltaCallToJump;
177         int32_t deltaCallToSlowCase;
178         int32_t deltaCheckImmToCall;
179 #if USE(JSVALUE64)
180         int32_t deltaCallToLoadOrStore;
181 #else
182         int32_t deltaCallToTagLoadOrStore;
183         int32_t deltaCallToPayloadLoadOrStore;
184 #endif
185     } patch;
186
187     AccessType accessType;
188     CacheType cacheType;
189     uint8_t countdown; // We repatch only when this is zero. If not zero, we decrement.
190     uint8_t repatchCount;
191     uint8_t numberOfCoolDowns;
192     uint8_t bufferingCountdown;
193     bool resetByGC : 1;
194     bool tookSlowPath : 1;
195     bool everConsidered : 1;
196 };
197
198 inline CodeOrigin getStructureStubInfoCodeOrigin(StructureStubInfo& structureStubInfo)
199 {
200     return structureStubInfo.codeOrigin;
201 }
202
203 #else
204
205 class StructureStubInfo;
206
207 #endif // ENABLE(JIT)
208
209 typedef HashMap<CodeOrigin, StructureStubInfo*, CodeOriginApproximateHash> StubInfoMap;
210
211 } // namespace JSC
212
213 #endif // StructureStubInfo_h