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