1/*
2 * Copyright (C) 2016-2019 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 "ClassInfo.h"
29#include "Identifier.h"
30#include <wtf/Condition.h>
31#include <wtf/FastMalloc.h>
32#include <wtf/Lock.h>
33#include <wtf/Noncopyable.h>
34#include <wtf/PrintStream.h>
35#include <wtf/Spectrum.h>
36
37namespace JSC {
38
39#define FOR_EACH_ICEVENT_KIND(macro) \
40 macro(InvalidKind) \
41 macro(GetByAddAccessCase) \
42 macro(GetByReplaceWithJump) \
43 macro(GetBySelfPatch) \
44 macro(InAddAccessCase) \
45 macro(InReplaceWithJump) \
46 macro(InstanceOfAddAccessCase) \
47 macro(InstanceOfReplaceWithJump) \
48 macro(OperationGetById) \
49 macro(OperationGetByIdGeneric) \
50 macro(OperationGetByIdBuildList) \
51 macro(OperationGetByIdOptimize) \
52 macro(OperationGetByValOptimize) \
53 macro(OperationGetByIdWithThisOptimize) \
54 macro(OperationGenericIn) \
55 macro(OperationInById) \
56 macro(OperationInByIdGeneric) \
57 macro(OperationInByIdOptimize) \
58 macro(OperationPutByIdStrict) \
59 macro(OperationPutByIdNonStrict) \
60 macro(OperationPutByIdDirectStrict) \
61 macro(OperationPutByIdDirectNonStrict) \
62 macro(OperationPutByIdStrictOptimize) \
63 macro(OperationPutByIdNonStrictOptimize) \
64 macro(OperationPutByIdDirectStrictOptimize) \
65 macro(OperationPutByIdDirectNonStrictOptimize) \
66 macro(OperationPutByIdStrictBuildList) \
67 macro(OperationPutByIdNonStrictBuildList) \
68 macro(OperationPutByIdDirectStrictBuildList) \
69 macro(OperationPutByIdDirectNonStrictBuildList) \
70 macro(PutByIdAddAccessCase) \
71 macro(PutByIdReplaceWithJump) \
72 macro(PutByIdSelfPatch) \
73 macro(InByIdSelfPatch)
74
75class ICEvent {
76public:
77 enum Kind {
78#define ICEVENT_KIND_DECLARATION(name) name,
79 FOR_EACH_ICEVENT_KIND(ICEVENT_KIND_DECLARATION)
80#undef ICEVENT_KIND_DECLARATION
81 };
82
83 enum PropertyLocation {
84 Unknown,
85 BaseObject,
86 ProtoLookup
87 };
88
89 ICEvent()
90 {
91 }
92
93 ICEvent(Kind kind, const ClassInfo* classInfo, const Identifier propertyName)
94 : m_kind(kind)
95 , m_classInfo(classInfo)
96 , m_propertyName(propertyName)
97 , m_propertyLocation(Unknown)
98 {
99 }
100
101 ICEvent(Kind kind, const ClassInfo* classInfo, const Identifier propertyName, bool isBaseProperty)
102 : m_kind(kind)
103 , m_classInfo(classInfo)
104 , m_propertyName(propertyName)
105 , m_propertyLocation(isBaseProperty ? BaseObject : ProtoLookup)
106 {
107 }
108
109 ICEvent(WTF::HashTableDeletedValueType)
110 : m_kind(OperationGetById)
111 {
112 }
113
114 bool operator==(const ICEvent& other) const
115 {
116 return m_kind == other.m_kind
117 && m_classInfo == other.m_classInfo
118 && m_propertyName == other.m_propertyName;
119 }
120
121 bool operator!=(const ICEvent& other) const
122 {
123 return !(*this == other);
124 }
125
126 bool operator<(const ICEvent& other) const;
127 bool operator>(const ICEvent& other) const { return other < *this; }
128 bool operator<=(const ICEvent& other) const { return !(*this > other); }
129 bool operator>=(const ICEvent& other) const { return !(*this < other); }
130
131 explicit operator bool() const
132 {
133 return *this != ICEvent();
134 }
135
136 Kind kind() const { return m_kind; }
137 const ClassInfo* classInfo() const { return m_classInfo; }
138 const Identifier& propertyName() const { return m_propertyName; }
139
140 unsigned hash() const
141 {
142 if (m_propertyName.isNull())
143 return m_kind + m_propertyLocation + WTF::PtrHash<const ClassInfo*>::hash(m_classInfo);
144 return m_kind + m_propertyLocation + WTF::PtrHash<const ClassInfo*>::hash(m_classInfo) + StringHash::hash(m_propertyName.string());
145 }
146
147 bool isHashTableDeletedValue() const
148 {
149 return *this == ICEvent(WTF::HashTableDeletedValue);
150 }
151
152 void dump(PrintStream&) const;
153
154 void log() const;
155
156private:
157
158 Kind m_kind { InvalidKind };
159 const ClassInfo* m_classInfo { nullptr };
160 Identifier m_propertyName;
161 PropertyLocation m_propertyLocation;
162};
163
164struct ICEventHash {
165 static unsigned hash(const ICEvent& key) { return key.hash(); }
166 static bool equal(const ICEvent& a, const ICEvent& b) { return a == b; }
167 static constexpr bool safeToCompareToEmptyOrDeleted = true;
168};
169
170} // namespace JSC
171
172namespace WTF {
173
174void printInternal(PrintStream&, JSC::ICEvent::Kind);
175
176template<typename T> struct DefaultHash;
177template<> struct DefaultHash<JSC::ICEvent> {
178 typedef JSC::ICEventHash Hash;
179};
180
181template<typename T> struct HashTraits;
182template<> struct HashTraits<JSC::ICEvent> : SimpleClassHashTraits<JSC::ICEvent> {
183 static constexpr bool emptyValueIsZero = false;
184};
185
186} // namespace WTF
187
188namespace JSC {
189
190class ICStats {
191 WTF_MAKE_NONCOPYABLE(ICStats);
192 WTF_MAKE_FAST_ALLOCATED;
193public:
194 ICStats();
195 ~ICStats();
196
197 void add(const ICEvent& event);
198
199 static ICStats& instance();
200
201private:
202
203 Spectrum<ICEvent, uint64_t> m_spectrum;
204 RefPtr<Thread> m_thread;
205 Lock m_lock;
206 Condition m_condition;
207 bool m_shouldStop { false };
208
209 static Atomic<ICStats*> s_instance;
210};
211
212#define LOG_IC(arguments) do { \
213 if (Options::useICStats()) \
214 (ICEvent arguments).log(); \
215 } while (false)
216
217} // namespace JSC
218