1/*
2 * Copyright (C) 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#include "config.h"
27#include "InstanceOfStatus.h"
28
29#include "ICStatusUtils.h"
30#include "InstanceOfAccessCase.h"
31#include "JSCInlines.h"
32#include "PolymorphicAccess.h"
33#include "StructureStubInfo.h"
34
35namespace JSC {
36
37void InstanceOfStatus::appendVariant(const InstanceOfVariant& variant)
38{
39 appendICStatusVariant(m_variants, variant);
40}
41
42InstanceOfStatus InstanceOfStatus::computeFor(
43 CodeBlock* codeBlock, ICStatusMap& infoMap, unsigned bytecodeIndex)
44{
45 ConcurrentJSLocker locker(codeBlock->m_lock);
46
47 InstanceOfStatus result;
48#if ENABLE(DFG_JIT)
49 result = computeForStubInfo(locker, infoMap.get(CodeOrigin(bytecodeIndex)).stubInfo);
50
51 if (!result.takesSlowPath()) {
52 UnlinkedCodeBlock* unlinkedCodeBlock = codeBlock->unlinkedCodeBlock();
53 ConcurrentJSLocker locker(unlinkedCodeBlock->m_lock);
54 // We also check for BadType here in case this is "primitive instanceof Foo".
55 if (unlinkedCodeBlock->hasExitSite(locker, DFG::FrequentExitSite(bytecodeIndex, BadCache))
56 || unlinkedCodeBlock->hasExitSite(locker, DFG::FrequentExitSite(bytecodeIndex, BadConstantCache))
57 || unlinkedCodeBlock->hasExitSite(locker, DFG::FrequentExitSite(bytecodeIndex, BadType)))
58 return TakesSlowPath;
59 }
60#else
61 UNUSED_PARAM(infoMap);
62 UNUSED_PARAM(bytecodeIndex);
63#endif
64
65 return result;
66}
67
68#if ENABLE(DFG_JIT)
69InstanceOfStatus InstanceOfStatus::computeForStubInfo(const ConcurrentJSLocker&, StructureStubInfo* stubInfo)
70{
71 // FIXME: We wouldn't have to bail for nonCell if we taught MatchStructure how to handle non
72 // cells. If we fixed that then we wouldn't be able to use summary();
73 // https://bugs.webkit.org/show_bug.cgi?id=185784
74 StubInfoSummary summary = StructureStubInfo::summary(stubInfo);
75 if (!isInlineable(summary))
76 return InstanceOfStatus(summary);
77
78 if (stubInfo->cacheType != CacheType::Stub)
79 return TakesSlowPath; // This is conservative. It could be that we have no information.
80
81 PolymorphicAccess* list = stubInfo->u.stub;
82 InstanceOfStatus result;
83 for (unsigned listIndex = 0; listIndex < list->size(); ++listIndex) {
84 const AccessCase& access = list->at(listIndex);
85
86 if (access.type() == AccessCase::InstanceOfGeneric)
87 return TakesSlowPath;
88
89 if (!access.conditionSet().structuresEnsureValidity())
90 return TakesSlowPath;
91
92 result.appendVariant(InstanceOfVariant(
93 access.structure(),
94 access.conditionSet(),
95 access.as<InstanceOfAccessCase>().prototype(),
96 access.type() == AccessCase::InstanceOfHit));
97 }
98
99 return result;
100}
101#endif // ENABLE(DFG_JIT)
102
103JSObject* InstanceOfStatus::commonPrototype() const
104{
105 JSObject* prototype = nullptr;
106 for (const InstanceOfVariant& variant : m_variants) {
107 if (!prototype) {
108 prototype = variant.prototype();
109 continue;
110 }
111 if (prototype != variant.prototype())
112 return nullptr;
113 }
114 return prototype;
115}
116
117void InstanceOfStatus::filter(const StructureSet& structureSet)
118{
119 if (m_state != Simple)
120 return;
121 filterICStatusVariants(m_variants, structureSet);
122 if (m_variants.isEmpty())
123 m_state = NoInformation;
124}
125
126} // namespace JSC
127
128