DFG should inline InstanceOf ICs
[WebKit-https.git] / Source / JavaScriptCore / bytecode / StructureStubInfo.cpp
1 /*
2  * Copyright (C) 2008, 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 #include "config.h"
27 #include "StructureStubInfo.h"
28
29 #include "JSObject.h"
30 #include "JSCInlines.h"
31 #include "PolymorphicAccess.h"
32 #include "Repatch.h"
33
34 namespace JSC {
35
36 #if ENABLE(JIT)
37
38 namespace StructureStubInfoInternal {
39 static const bool verbose = false;
40 }
41
42 StructureStubInfo::StructureStubInfo(AccessType accessType)
43     : callSiteIndex(UINT_MAX)
44     , accessType(accessType)
45     , cacheType(CacheType::Unset)
46     , countdown(1) // For a totally clear stub, we'll patch it after the first execution.
47     , repatchCount(0)
48     , numberOfCoolDowns(0)
49     , bufferingCountdown(Options::repatchBufferingCountdown())
50     , resetByGC(false)
51     , tookSlowPath(false)
52     , everConsidered(false)
53     , prototypeIsKnownObject(false)
54     , sawNonCell(false)
55 {
56 }
57
58 StructureStubInfo::~StructureStubInfo()
59 {
60 }
61
62 void StructureStubInfo::initGetByIdSelf(CodeBlock* codeBlock, Structure* baseObjectStructure, PropertyOffset offset)
63 {
64     cacheType = CacheType::GetByIdSelf;
65     
66     u.byIdSelf.baseObjectStructure.set(
67         *codeBlock->vm(), codeBlock, baseObjectStructure);
68     u.byIdSelf.offset = offset;
69 }
70
71 void StructureStubInfo::initArrayLength()
72 {
73     cacheType = CacheType::ArrayLength;
74 }
75
76 void StructureStubInfo::initPutByIdReplace(CodeBlock* codeBlock, Structure* baseObjectStructure, PropertyOffset offset)
77 {
78     cacheType = CacheType::PutByIdReplace;
79     
80     u.byIdSelf.baseObjectStructure.set(
81         *codeBlock->vm(), codeBlock, baseObjectStructure);
82     u.byIdSelf.offset = offset;
83 }
84
85 void StructureStubInfo::initInByIdSelf(CodeBlock* codeBlock, Structure* baseObjectStructure, PropertyOffset offset)
86 {
87     cacheType = CacheType::InByIdSelf;
88
89     u.byIdSelf.baseObjectStructure.set(
90         *codeBlock->vm(), codeBlock, baseObjectStructure);
91     u.byIdSelf.offset = offset;
92 }
93
94 void StructureStubInfo::deref()
95 {
96     switch (cacheType) {
97     case CacheType::Stub:
98         delete u.stub;
99         return;
100     case CacheType::Unset:
101     case CacheType::GetByIdSelf:
102     case CacheType::PutByIdReplace:
103     case CacheType::InByIdSelf:
104     case CacheType::ArrayLength:
105         return;
106     }
107
108     RELEASE_ASSERT_NOT_REACHED();
109 }
110
111 void StructureStubInfo::aboutToDie()
112 {
113     switch (cacheType) {
114     case CacheType::Stub:
115         u.stub->aboutToDie();
116         return;
117     case CacheType::Unset:
118     case CacheType::GetByIdSelf:
119     case CacheType::PutByIdReplace:
120     case CacheType::InByIdSelf:
121     case CacheType::ArrayLength:
122         return;
123     }
124
125     RELEASE_ASSERT_NOT_REACHED();
126 }
127
128 AccessGenerationResult StructureStubInfo::addAccessCase(
129     const GCSafeConcurrentJSLocker& locker, CodeBlock* codeBlock, const Identifier& ident, std::unique_ptr<AccessCase> accessCase)
130 {
131     VM& vm = *codeBlock->vm();
132     
133     if (StructureStubInfoInternal::verbose)
134         dataLog("Adding access case: ", accessCase, "\n");
135     
136     if (!accessCase)
137         return AccessGenerationResult::GaveUp;
138     
139     AccessGenerationResult result;
140     
141     if (cacheType == CacheType::Stub) {
142         result = u.stub->addCase(locker, vm, codeBlock, *this, ident, WTFMove(accessCase));
143         
144         if (StructureStubInfoInternal::verbose)
145             dataLog("Had stub, result: ", result, "\n");
146
147         if (result.shouldResetStubAndFireWatchpoints())
148             return result;
149
150         if (!result.buffered()) {
151             bufferedStructures.clear();
152             return result;
153         }
154     } else {
155         std::unique_ptr<PolymorphicAccess> access = std::make_unique<PolymorphicAccess>();
156         
157         Vector<std::unique_ptr<AccessCase>, 2> accessCases;
158         
159         std::unique_ptr<AccessCase> previousCase =
160             AccessCase::fromStructureStubInfo(vm, codeBlock, *this);
161         if (previousCase)
162             accessCases.append(WTFMove(previousCase));
163         
164         accessCases.append(WTFMove(accessCase));
165         
166         result = access->addCases(locker, vm, codeBlock, *this, ident, WTFMove(accessCases));
167         
168         if (StructureStubInfoInternal::verbose)
169             dataLog("Created stub, result: ", result, "\n");
170
171         if (result.shouldResetStubAndFireWatchpoints())
172             return result;
173
174         if (!result.buffered()) {
175             bufferedStructures.clear();
176             return result;
177         }
178         
179         cacheType = CacheType::Stub;
180         u.stub = access.release();
181     }
182     
183     RELEASE_ASSERT(!result.generatedSomeCode());
184     
185     // If we didn't buffer any cases then bail. If this made no changes then we'll just try again
186     // subject to cool-down.
187     if (!result.buffered()) {
188         if (StructureStubInfoInternal::verbose)
189             dataLog("Didn't buffer anything, bailing.\n");
190         bufferedStructures.clear();
191         return result;
192     }
193     
194     // The buffering countdown tells us if we should be repatching now.
195     if (bufferingCountdown) {
196         if (StructureStubInfoInternal::verbose)
197             dataLog("Countdown is too high: ", bufferingCountdown, ".\n");
198         return result;
199     }
200     
201     // Forget the buffered structures so that all future attempts to cache get fully handled by the
202     // PolymorphicAccess.
203     bufferedStructures.clear();
204     
205     result = u.stub->regenerate(locker, vm, codeBlock, *this, ident);
206     
207     if (StructureStubInfoInternal::verbose)
208         dataLog("Regeneration result: ", result, "\n");
209     
210     RELEASE_ASSERT(!result.buffered());
211     
212     if (!result.generatedSomeCode())
213         return result;
214     
215     // If we generated some code then we don't want to attempt to repatch in the future until we
216     // gather enough cases.
217     bufferingCountdown = Options::repatchBufferingCountdown();
218     return result;
219 }
220
221 void StructureStubInfo::reset(CodeBlock* codeBlock)
222 {
223     bufferedStructures.clear();
224
225     if (cacheType == CacheType::Unset)
226         return;
227
228     if (Options::verboseOSR()) {
229         // This can be called from GC destructor calls, so we don't try to do a full dump
230         // of the CodeBlock.
231         dataLog("Clearing structure cache (kind ", static_cast<int>(accessType), ") in ", RawPointer(codeBlock), ".\n");
232     }
233
234     switch (accessType) {
235     case AccessType::TryGet:
236         resetGetByID(codeBlock, *this, GetByIDKind::Try);
237         break;
238     case AccessType::Get:
239         resetGetByID(codeBlock, *this, GetByIDKind::Normal);
240         break;
241     case AccessType::GetWithThis:
242         resetGetByID(codeBlock, *this, GetByIDKind::WithThis);
243         break;
244     case AccessType::GetDirect:
245         resetGetByID(codeBlock, *this, GetByIDKind::Direct);
246         break;
247     case AccessType::Put:
248         resetPutByID(codeBlock, *this);
249         break;
250     case AccessType::In:
251         resetInByID(codeBlock, *this);
252         break;
253     case AccessType::InstanceOf:
254         resetInstanceOf(*this);
255         break;
256     }
257     
258     deref();
259     cacheType = CacheType::Unset;
260 }
261
262 void StructureStubInfo::visitWeakReferences(CodeBlock* codeBlock)
263 {
264     VM& vm = *codeBlock->vm();
265     
266     bufferedStructures.genericFilter(
267         [&] (Structure* structure) -> bool {
268             return Heap::isMarked(structure);
269         });
270
271     switch (cacheType) {
272     case CacheType::GetByIdSelf:
273     case CacheType::PutByIdReplace:
274     case CacheType::InByIdSelf:
275         if (Heap::isMarked(u.byIdSelf.baseObjectStructure.get()))
276             return;
277         break;
278     case CacheType::Stub:
279         if (u.stub->visitWeak(vm))
280             return;
281         break;
282     default:
283         return;
284     }
285
286     reset(codeBlock);
287     resetByGC = true;
288 }
289
290 bool StructureStubInfo::propagateTransitions(SlotVisitor& visitor)
291 {
292     switch (cacheType) {
293     case CacheType::Unset:
294     case CacheType::ArrayLength:
295         return true;
296     case CacheType::GetByIdSelf:
297     case CacheType::PutByIdReplace:
298     case CacheType::InByIdSelf:
299         return u.byIdSelf.baseObjectStructure->markIfCheap(visitor);
300     case CacheType::Stub:
301         return u.stub->propagateTransitions(visitor);
302     }
303     
304     RELEASE_ASSERT_NOT_REACHED();
305     return true;
306 }
307
308 bool StructureStubInfo::containsPC(void* pc) const
309 {
310     if (cacheType != CacheType::Stub)
311         return false;
312     return u.stub->containsPC(pc);
313 }
314
315 #endif // ENABLE(JIT)
316
317 } // namespace JSC