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 ICEvent()
83 {
84 }
85
86 ICEvent(Kind kind, const ClassInfo* classInfo, const Identifier propertyName)
87 : m_kind(kind)
88 , m_classInfo(classInfo)
89 , m_propertyName(propertyName)
90 {
91 }
92
93 ICEvent(WTF::HashTableDeletedValueType)
94 : m_kind(OperationGetById)
95 {
96 }
97
98 bool operator==(const ICEvent& other) const
99 {
100 return m_kind == other.m_kind
101 && m_classInfo == other.m_classInfo
102 && m_propertyName == other.m_propertyName;
103 }
104
105 bool operator!=(const ICEvent& other) const
106 {
107 return !(*this == other);
108 }
109
110 bool operator<(const ICEvent& other) const;
111 bool operator>(const ICEvent& other) const { return other < *this; }
112 bool operator<=(const ICEvent& other) const { return !(*this > other); }
113 bool operator>=(const ICEvent& other) const { return !(*this < other); }
114
115 explicit operator bool() const
116 {
117 return *this != ICEvent();
118 }
119
120 Kind kind() const { return m_kind; }
121 const ClassInfo* classInfo() const { return m_classInfo; }
122 const Identifier& propertyName() const { return m_propertyName; }
123
124 unsigned hash() const
125 {
126 return m_kind + WTF::PtrHash<const ClassInfo*>::hash(m_classInfo) + StringHash::hash(m_propertyName.string());
127 }
128
129 bool isHashTableDeletedValue() const
130 {
131 return *this == ICEvent(WTF::HashTableDeletedValue);
132 }
133
134 void dump(PrintStream&) const;
135
136 void log() const;
137
138private:
139
140 Kind m_kind { InvalidKind };
141 const ClassInfo* m_classInfo { nullptr };
142 Identifier m_propertyName;
143};
144
145struct ICEventHash {
146 static unsigned hash(const ICEvent& key) { return key.hash(); }
147 static bool equal(const ICEvent& a, const ICEvent& b) { return a == b; }
148 static const bool safeToCompareToEmptyOrDeleted = true;
149};
150
151} // namespace JSC
152
153namespace WTF {
154
155void printInternal(PrintStream&, JSC::ICEvent::Kind);
156
157template<typename T> struct DefaultHash;
158template<> struct DefaultHash<JSC::ICEvent> {
159 typedef JSC::ICEventHash Hash;
160};
161
162template<typename T> struct HashTraits;
163template<> struct HashTraits<JSC::ICEvent> : SimpleClassHashTraits<JSC::ICEvent> {
164 static const bool emptyValueIsZero = false;
165};
166
167} // namespace WTF
168
169namespace JSC {
170
171class ICStats {
172 WTF_MAKE_NONCOPYABLE(ICStats);
173 WTF_MAKE_FAST_ALLOCATED;
174public:
175 ICStats();
176 ~ICStats();
177
178 void add(const ICEvent& event);
179
180 static ICStats& instance();
181
182private:
183
184 Spectrum<ICEvent, uint64_t> m_spectrum;
185 RefPtr<Thread> m_thread;
186 Lock m_lock;
187 Condition m_condition;
188 bool m_shouldStop { false };
189
190 static Atomic<ICStats*> s_instance;
191};
192
193#define LOG_IC(arguments) do { \
194 if (Options::useICStats()) \
195 (ICEvent arguments).log(); \
196 } while (false)
197
198} // namespace JSC
199