]> git.saurik.com Git - apple/javascriptcore.git/blame - bytecode/GetByIdStatus.cpp
JavaScriptCore-7600.1.4.15.12.tar.gz
[apple/javascriptcore.git] / bytecode / GetByIdStatus.cpp
CommitLineData
6fe7ccc8 1/*
81345200 2 * Copyright (C) 2012, 2013, 2014 Apple Inc. All rights reserved.
6fe7ccc8
A
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 "GetByIdStatus.h"
28
29#include "CodeBlock.h"
81345200 30#include "JSCInlines.h"
93a37866
A
31#include "JSScope.h"
32#include "LLIntData.h"
6fe7ccc8 33#include "LowLevelInterpreter.h"
81345200
A
34#include "PolymorphicGetByIdList.h"
35#include <wtf/ListDump.h>
6fe7ccc8
A
36
37namespace JSC {
38
81345200
A
39bool GetByIdStatus::appendVariant(const GetByIdVariant& variant)
40{
41 for (unsigned i = 0; i < m_variants.size(); ++i) {
42 if (m_variants[i].structureSet().overlaps(variant.structureSet()))
43 return false;
44 }
45 m_variants.append(variant);
46 return true;
47}
48
49#if ENABLE(DFG_JIT)
50bool GetByIdStatus::hasExitSite(const ConcurrentJITLocker& locker, CodeBlock* profiledBlock, unsigned bytecodeIndex, ExitingJITType jitType)
51{
52 return profiledBlock->hasExitSite(locker, DFG::FrequentExitSite(bytecodeIndex, BadCache, jitType))
53 || profiledBlock->hasExitSite(locker, DFG::FrequentExitSite(bytecodeIndex, BadCacheWatchpoint, jitType))
54 || profiledBlock->hasExitSite(locker, DFG::FrequentExitSite(bytecodeIndex, BadWeakConstantCache, jitType))
55 || profiledBlock->hasExitSite(locker, DFG::FrequentExitSite(bytecodeIndex, BadWeakConstantCacheWatchpoint, jitType));
56}
57#endif
58
59GetByIdStatus GetByIdStatus::computeFromLLInt(CodeBlock* profiledBlock, unsigned bytecodeIndex, StringImpl* uid)
6fe7ccc8
A
60{
61 UNUSED_PARAM(profiledBlock);
62 UNUSED_PARAM(bytecodeIndex);
81345200 63 UNUSED_PARAM(uid);
6fe7ccc8
A
64 Instruction* instruction = profiledBlock->instructions().begin() + bytecodeIndex;
65
81345200 66 if (instruction[0].u.opcode == LLInt::getOpcode(op_get_array_length))
93a37866 67 return GetByIdStatus(NoInformation, false);
6fe7ccc8
A
68
69 Structure* structure = instruction[4].u.structure.get();
70 if (!structure)
93a37866 71 return GetByIdStatus(NoInformation, false);
81345200
A
72
73 if (structure->takesSlowPathInDFGForImpureProperty())
74 return GetByIdStatus(NoInformation, false);
75
93a37866
A
76 unsigned attributesIgnored;
77 JSCell* specificValue;
81345200
A
78 PropertyOffset offset = structure->getConcurrently(
79 *profiledBlock->vm(), uid, attributesIgnored, specificValue);
93a37866
A
80 if (structure->isDictionary())
81 specificValue = 0;
82 if (!isValidOffset(offset))
83 return GetByIdStatus(NoInformation, false);
6fe7ccc8 84
81345200 85 return GetByIdStatus(Simple, false, GetByIdVariant(StructureSet(structure), offset, specificValue));
93a37866
A
86}
87
81345200 88bool GetByIdStatus::computeForChain(CodeBlock* profiledBlock, StringImpl* uid, PassRefPtr<IntendedStructureChain> passedChain)
93a37866 89{
81345200
A
90#if ENABLE(JIT)
91 RefPtr<IntendedStructureChain> chain = passedChain;
92
93a37866
A
93 // Validate the chain. If the chain is invalid, then currently the best thing
94 // we can do is to assume that TakesSlow is true. In the future, it might be
95 // worth exploring reifying the structure chain from the structure we've got
96 // instead of using the one from the cache, since that will do the right things
97 // if the structure chain has changed. But that may be harder, because we may
98 // then end up having a different type of access altogether. And it currently
99 // does not appear to be worth it to do so -- effectively, the heuristic we
100 // have now is that if the structure chain has changed between when it was
101 // cached on in the baseline JIT and when the DFG tried to inline the access,
102 // then we fall back on a polymorphic access.
81345200
A
103 if (!chain->isStillValid())
104 return false;
105
106 if (chain->head()->takesSlowPathInDFGForImpureProperty())
107 return false;
108 size_t chainSize = chain->size();
109 for (size_t i = 0; i < chainSize; i++) {
110 if (chain->at(i)->takesSlowPathInDFGForImpureProperty())
111 return false;
93a37866 112 }
81345200
A
113
114 JSObject* currentObject = chain->terminalPrototype();
115 Structure* currentStructure = chain->last();
116
117 ASSERT_UNUSED(currentObject, currentObject);
93a37866 118
93a37866
A
119 unsigned attributesIgnored;
120 JSCell* specificValue;
81345200
A
121
122 PropertyOffset offset = currentStructure->getConcurrently(
123 *profiledBlock->vm(), uid, attributesIgnored, specificValue);
93a37866
A
124 if (currentStructure->isDictionary())
125 specificValue = 0;
81345200
A
126 if (!isValidOffset(offset))
127 return false;
128
129 return appendVariant(GetByIdVariant(StructureSet(chain->head()), offset, specificValue, chain));
130#else // ENABLE(JIT)
93a37866 131 UNUSED_PARAM(profiledBlock);
81345200
A
132 UNUSED_PARAM(uid);
133 UNUSED_PARAM(passedChain);
93a37866 134 UNREACHABLE_FOR_PLATFORM();
81345200
A
135 return false;
136#endif // ENABLE(JIT)
6fe7ccc8
A
137}
138
81345200 139GetByIdStatus GetByIdStatus::computeFor(CodeBlock* profiledBlock, StubInfoMap& map, unsigned bytecodeIndex, StringImpl* uid)
6fe7ccc8 140{
81345200
A
141 ConcurrentJITLocker locker(profiledBlock->m_lock);
142
143 GetByIdStatus result;
144
145#if ENABLE(DFG_JIT)
146 result = computeForStubInfo(
147 locker, profiledBlock, map.get(CodeOrigin(bytecodeIndex)), uid);
6fe7ccc8 148
81345200
A
149 if (!result.takesSlowPath()
150 && (hasExitSite(locker, profiledBlock, bytecodeIndex)
151 || profiledBlock->likelyToTakeSlowCase(bytecodeIndex)))
152 return GetByIdStatus(TakesSlowPath, true);
153#else
154 UNUSED_PARAM(map);
155#endif
156
157 if (!result)
158 return computeFromLLInt(profiledBlock, bytecodeIndex, uid);
159
160 return result;
161}
162
163#if ENABLE(JIT)
164GetByIdStatus GetByIdStatus::computeForStubInfo(
165 const ConcurrentJITLocker&, CodeBlock* profiledBlock, StructureStubInfo* stubInfo,
166 StringImpl* uid)
167{
168 if (!stubInfo || !stubInfo->seen)
169 return GetByIdStatus(NoInformation);
6fe7ccc8 170
81345200 171 if (stubInfo->resetByGC)
93a37866
A
172 return GetByIdStatus(TakesSlowPath, true);
173
81345200
A
174 PolymorphicGetByIdList* list = 0;
175 if (stubInfo->accessType == access_get_by_id_list) {
176 list = stubInfo->u.getByIdList.list;
177 bool makesCalls = false;
178 bool isWatched = false;
179 for (unsigned i = 0; i < list->size(); ++i) {
180 const GetByIdAccess& access = list->at(i);
181 if (access.doesCalls()) {
182 makesCalls = true;
183 break;
184 }
185 if (access.isWatched()) {
186 isWatched = true;
187 continue;
188 }
189 }
190 if (makesCalls)
93a37866 191 return GetByIdStatus(MakesCalls, true);
81345200
A
192 if (isWatched)
193 return GetByIdStatus(TakesSlowPath, true);
6fe7ccc8
A
194 }
195
6fe7ccc8
A
196 // Finally figure out if we can derive an access strategy.
197 GetByIdStatus result;
81345200 198 result.m_state = Simple;
93a37866 199 result.m_wasSeenInJIT = true; // This is interesting for bytecode dumping only.
81345200 200 switch (stubInfo->accessType) {
6fe7ccc8 201 case access_unset:
81345200 202 return GetByIdStatus(NoInformation);
6fe7ccc8
A
203
204 case access_get_by_id_self: {
81345200
A
205 Structure* structure = stubInfo->u.getByIdSelf.baseObjectStructure.get();
206 if (structure->takesSlowPathInDFGForImpureProperty())
207 return GetByIdStatus(TakesSlowPath, true);
93a37866
A
208 unsigned attributesIgnored;
209 JSCell* specificValue;
81345200
A
210 GetByIdVariant variant;
211 variant.m_offset = structure->getConcurrently(
212 *profiledBlock->vm(), uid, attributesIgnored, specificValue);
213 if (!isValidOffset(variant.m_offset))
214 return GetByIdStatus(TakesSlowPath, true);
215
93a37866
A
216 if (structure->isDictionary())
217 specificValue = 0;
6fe7ccc8 218
81345200
A
219 variant.m_structureSet.add(structure);
220 variant.m_specificValue = JSValue(specificValue);
221 result.appendVariant(variant);
222 return result;
6fe7ccc8
A
223 }
224
81345200
A
225 case access_get_by_id_list: {
226 for (unsigned listIndex = 0; listIndex < list->size(); ++listIndex) {
227 ASSERT(list->at(listIndex).isSimple());
228
229 Structure* structure = list->at(listIndex).structure();
230
231 // FIXME: We should assert that we never see a structure that
232 // hasImpureGetOwnPropertySlot() but for which we don't
233 // newImpurePropertyFiresWatchpoints(). We're not at a point where we can do
234 // that, yet.
235 // https://bugs.webkit.org/show_bug.cgi?id=131810
6fe7ccc8 236
81345200
A
237 if (structure->takesSlowPathInDFGForImpureProperty())
238 return GetByIdStatus(TakesSlowPath, true);
239
240 if (list->at(listIndex).chain()) {
241 RefPtr<IntendedStructureChain> chain = adoptRef(new IntendedStructureChain(
242 profiledBlock, structure, list->at(listIndex).chain(),
243 list->at(listIndex).chainCount()));
244 if (!result.computeForChain(profiledBlock, uid, chain))
245 return GetByIdStatus(TakesSlowPath, true);
6fe7ccc8 246 continue;
81345200 247 }
6fe7ccc8 248
93a37866
A
249 unsigned attributesIgnored;
250 JSCell* specificValue;
81345200
A
251 PropertyOffset myOffset = structure->getConcurrently(
252 *profiledBlock->vm(), uid, attributesIgnored, specificValue);
93a37866
A
253 if (structure->isDictionary())
254 specificValue = 0;
6fe7ccc8 255
81345200
A
256 if (!isValidOffset(myOffset))
257 return GetByIdStatus(TakesSlowPath, true);
258
259 bool found = false;
260 for (unsigned variantIndex = 0; variantIndex < result.m_variants.size(); ++variantIndex) {
261 GetByIdVariant& variant = result.m_variants[variantIndex];
262 if (variant.m_chain)
263 continue;
264
265 if (variant.m_offset != myOffset)
266 continue;
267
268 found = true;
269 if (variant.m_structureSet.contains(structure))
270 break;
271
272 if (variant.m_specificValue != JSValue(specificValue))
273 variant.m_specificValue = JSValue();
274
275 variant.m_structureSet.add(structure);
6fe7ccc8
A
276 break;
277 }
93a37866 278
81345200
A
279 if (found)
280 continue;
281
282 if (!result.appendVariant(GetByIdVariant(StructureSet(structure), myOffset, specificValue)))
283 return GetByIdStatus(TakesSlowPath, true);
6fe7ccc8 284 }
6fe7ccc8 285
81345200 286 return result;
93a37866
A
287 }
288
289 case access_get_by_id_chain: {
81345200 290 if (!stubInfo->u.getByIdChain.isDirect)
93a37866 291 return GetByIdStatus(MakesCalls, true);
81345200
A
292 RefPtr<IntendedStructureChain> chain = adoptRef(new IntendedStructureChain(
293 profiledBlock,
294 stubInfo->u.getByIdChain.baseObjectStructure.get(),
295 stubInfo->u.getByIdChain.chain.get(),
296 stubInfo->u.getByIdChain.count));
297 if (result.computeForChain(profiledBlock, uid, chain))
298 return result;
299 return GetByIdStatus(TakesSlowPath, true);
93a37866
A
300 }
301
6fe7ccc8 302 default:
81345200 303 return GetByIdStatus(TakesSlowPath, true);
6fe7ccc8
A
304 }
305
81345200
A
306 RELEASE_ASSERT_NOT_REACHED();
307 return GetByIdStatus();
308}
6fe7ccc8 309#endif // ENABLE(JIT)
81345200
A
310
311GetByIdStatus GetByIdStatus::computeFor(
312 CodeBlock* profiledBlock, CodeBlock* dfgBlock, StubInfoMap& baselineMap,
313 StubInfoMap& dfgMap, CodeOrigin codeOrigin, StringImpl* uid)
314{
315#if ENABLE(DFG_JIT)
316 if (dfgBlock) {
317 GetByIdStatus result;
318 {
319 ConcurrentJITLocker locker(dfgBlock->m_lock);
320 result = computeForStubInfo(locker, dfgBlock, dfgMap.get(codeOrigin), uid);
321 }
322
323 if (result.takesSlowPath())
324 return result;
325
326 {
327 ConcurrentJITLocker locker(profiledBlock->m_lock);
328 if (hasExitSite(locker, profiledBlock, codeOrigin.bytecodeIndex, ExitFromFTL))
329 return GetByIdStatus(TakesSlowPath, true);
330 }
331
332 if (result.isSet())
333 return result;
334 }
335#else
336 UNUSED_PARAM(dfgBlock);
337 UNUSED_PARAM(dfgMap);
338#endif
339
340 return computeFor(profiledBlock, baselineMap, codeOrigin.bytecodeIndex, uid);
6fe7ccc8
A
341}
342
81345200 343GetByIdStatus GetByIdStatus::computeFor(VM& vm, Structure* structure, StringImpl* uid)
93a37866
A
344{
345 // For now we only handle the super simple self access case. We could handle the
346 // prototype case in the future.
347
81345200
A
348 if (!structure)
349 return GetByIdStatus(TakesSlowPath);
350
351 if (toUInt32FromStringImpl(uid) != PropertyName::NotAnIndex)
93a37866
A
352 return GetByIdStatus(TakesSlowPath);
353
81345200 354 if (structure->typeInfo().overridesGetOwnPropertySlot() && structure->typeInfo().type() != GlobalObjectType)
93a37866
A
355 return GetByIdStatus(TakesSlowPath);
356
357 if (!structure->propertyAccessesAreCacheable())
358 return GetByIdStatus(TakesSlowPath);
81345200 359
93a37866
A
360 unsigned attributes;
361 JSCell* specificValue;
81345200
A
362 PropertyOffset offset = structure->getConcurrently(vm, uid, attributes, specificValue);
363 if (!isValidOffset(offset))
93a37866
A
364 return GetByIdStatus(TakesSlowPath); // It's probably a prototype lookup. Give up on life for now, even though we could totally be way smarter about it.
365 if (attributes & Accessor)
366 return GetByIdStatus(MakesCalls);
367 if (structure->isDictionary())
368 specificValue = 0;
81345200
A
369 return GetByIdStatus(
370 Simple, false, GetByIdVariant(StructureSet(structure), offset, specificValue));
371}
372
373void GetByIdStatus::dump(PrintStream& out) const
374{
375 out.print("(");
376 switch (m_state) {
377 case NoInformation:
378 out.print("NoInformation");
379 break;
380 case Simple:
381 out.print("Simple");
382 break;
383 case TakesSlowPath:
384 out.print("TakesSlowPath");
385 break;
386 case MakesCalls:
387 out.print("MakesCalls");
388 break;
389 }
390 out.print(", ", listDump(m_variants), ", seenInJIT = ", m_wasSeenInJIT, ")");
93a37866
A
391}
392
6fe7ccc8
A
393} // namespace JSC
394