Changeset 120172 in webkit for trunk/Source/JavaScriptCore/runtime/SymbolTable.h
- Timestamp:
- Jun 13, 2012, 1:20:39 AM (13 years ago)
- File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/Source/JavaScriptCore/runtime/SymbolTable.h
r109268 r120172 1 1 /* 2 * Copyright (C) 2007, 2008 Apple Inc. All rights reserved.2 * Copyright (C) 2007, 2008, 2012 Apple Inc. All rights reserved. 3 3 * 4 4 * Redistribution and use in source and binary forms, with or without … … 32 32 #include "JSObject.h" 33 33 #include "UString.h" 34 #include "Watchpoint.h" 34 35 #include <wtf/AlwaysInline.h> 35 36 #include <wtf/HashTraits.h> 36 37 37 38 namespace JSC { 39 40 class Watchpoint; 41 class WatchpointSet; 38 42 39 43 static ALWAYS_INLINE int missingSymbolMarker() { return std::numeric_limits<int>::max(); } … … 43 47 // four bits all set or all unset. 44 48 49 // In addition to implementing semantics-mandated variable attributes and 50 // implementation-mandated variable indexing, this class also implements 51 // watchpoints to be used for JIT optimizations. Because watchpoints are 52 // meant to be relatively rare, this class optimizes heavily for the case 53 // that they are not being used. To that end, this class uses the thin-fat 54 // idiom: either it is thin, in which case it contains an in-place encoded 55 // word that consists of attributes, the index, and a bit saying that it is 56 // thin; or it is fat, in which case it contains a pointer to a malloc'd 57 // data structure and a bit saying that it is fat. The malloc'd data 58 // structure will be malloced a second time upon copy, to preserve the 59 // property that in-place edits to SymbolTableEntry do not manifest in any 60 // copies. However, the malloc'd FatEntry data structure contains a ref- 61 // counted pointer to a shared WatchpointSet. Thus, in-place edits of the 62 // WatchpointSet will manifest in all copies. Here's a picture: 63 // 64 // SymbolTableEntry --> FatEntry --> WatchpointSet 65 // 66 // If you make a copy of a SymbolTableEntry, you will have: 67 // 68 // original: SymbolTableEntry --> FatEntry --> WatchpointSet 69 // copy: SymbolTableEntry --> FatEntry -----^ 70 45 71 struct SymbolTableEntry { 72 // Use the SymbolTableEntry::Fast class, either via implicit cast or by calling 73 // getFast(), when you (1) only care about isNull(), getIndex(), and isReadOnly(), 74 // and (2) you are in a hot path where you need to minimize the number of times 75 // that you branch on isFat() when getting the bits(). 76 class Fast { 77 public: 78 Fast() 79 : m_bits(0) 80 { 81 } 82 83 ALWAYS_INLINE Fast(const SymbolTableEntry& entry) 84 : m_bits(entry.bits()) 85 { 86 } 87 88 bool isNull() const 89 { 90 return !m_bits; 91 } 92 93 int getIndex() const 94 { 95 return static_cast<int>(m_bits >> FlagBits); 96 } 97 98 bool isReadOnly() const 99 { 100 return m_bits & ReadOnlyFlag; 101 } 102 103 unsigned getAttributes() const 104 { 105 unsigned attributes = 0; 106 if (m_bits & ReadOnlyFlag) 107 attributes |= ReadOnly; 108 if (m_bits & DontEnumFlag) 109 attributes |= DontEnum; 110 return attributes; 111 } 112 113 bool isFat() const 114 { 115 return m_bits & FatFlag; 116 } 117 118 private: 119 friend struct SymbolTableEntry; 120 intptr_t m_bits; 121 }; 122 46 123 SymbolTableEntry() 47 124 : m_bits(0) … … 50 127 51 128 SymbolTableEntry(int index) 129 : m_bits(0) 52 130 { 53 131 ASSERT(isValidIndex(index)); … … 56 134 57 135 SymbolTableEntry(int index, unsigned attributes) 136 : m_bits(0) 58 137 { 59 138 ASSERT(isValidIndex(index)); … … 61 140 } 62 141 142 ~SymbolTableEntry() 143 { 144 freeFatEntry(); 145 } 146 147 SymbolTableEntry(const SymbolTableEntry& other) 148 : m_bits(0) 149 { 150 *this = other; 151 } 152 153 SymbolTableEntry& operator=(const SymbolTableEntry& other) 154 { 155 if (UNLIKELY(other.isFat())) 156 return copySlow(other); 157 freeFatEntry(); 158 m_bits = other.m_bits; 159 return *this; 160 } 161 63 162 bool isNull() const 64 163 { 65 return ! m_bits;164 return !bits(); 66 165 } 67 166 68 167 int getIndex() const 69 168 { 70 return m_bits >> FlagBits; 71 } 72 169 return static_cast<int>(bits() >> FlagBits); 170 } 171 172 ALWAYS_INLINE Fast getFast() const 173 { 174 return Fast(*this); 175 } 176 177 ALWAYS_INLINE Fast getFast(bool& wasFat) const 178 { 179 Fast result; 180 wasFat = isFat(); 181 if (wasFat) 182 result.m_bits = fatEntry()->m_bits; 183 else 184 result.m_bits = m_bits; 185 return result; 186 } 187 73 188 unsigned getAttributes() const 74 189 { 75 unsigned attributes = 0; 76 if (m_bits & ReadOnlyFlag) 77 attributes |= ReadOnly; 78 if (m_bits & DontEnumFlag) 79 attributes |= DontEnum; 80 return attributes; 190 return getFast().getAttributes(); 81 191 } 82 192 … … 88 198 bool isReadOnly() const 89 199 { 90 return m_bits & ReadOnlyFlag; 91 } 92 200 return bits() & ReadOnlyFlag; 201 } 202 203 bool couldBeWatched(); 204 205 // Notify an opportunity to create a watchpoint for a variable. This is 206 // idempotent and fail-silent. It is idempotent in the sense that if 207 // a watchpoint set had already been created, then another one will not 208 // be created. Hence two calls to this method have the same effect as 209 // one call. It is also fail-silent, in the sense that if a watchpoint 210 // set had been created and had already been invalidated, then this will 211 // just return. This means that couldBeWatched() may return false even 212 // immediately after a call to attemptToWatch(). 213 void attemptToWatch(); 214 215 bool* addressOfIsWatched(); 216 217 void addWatchpoint(Watchpoint*); 218 219 WatchpointSet* watchpointSet() 220 { 221 return fatEntry()->m_watchpoints.get(); 222 } 223 224 ALWAYS_INLINE void notifyWrite() 225 { 226 if (LIKELY(!isFat())) 227 return; 228 notifyWriteSlow(); 229 } 230 93 231 private: 94 static const unsigned ReadOnlyFlag = 0x1; 95 static const unsigned DontEnumFlag = 0x2; 96 static const unsigned NotNullFlag = 0x4; 97 static const unsigned FlagBits = 3; 232 static const intptr_t FatFlag = 0x1; 233 static const intptr_t ReadOnlyFlag = 0x2; 234 static const intptr_t DontEnumFlag = 0x4; 235 static const intptr_t NotNullFlag = 0x8; 236 static const intptr_t FlagBits = 4; 237 238 class FatEntry { 239 WTF_MAKE_FAST_ALLOCATED; 240 public: 241 FatEntry(intptr_t bits) 242 : m_bits(bits | FatFlag) 243 { 244 } 245 246 intptr_t m_bits; // always has FatFlag set and exactly matches what the bits would have been if this wasn't fat. 247 248 RefPtr<WatchpointSet> m_watchpoints; 249 }; 250 251 SymbolTableEntry& copySlow(const SymbolTableEntry&); 252 JS_EXPORT_PRIVATE void notifyWriteSlow(); 253 254 bool isFat() const 255 { 256 return m_bits & FatFlag; 257 } 258 259 const FatEntry* fatEntry() const 260 { 261 ASSERT(isFat()); 262 return bitwise_cast<const FatEntry*>(m_bits & ~FatFlag); 263 } 264 265 FatEntry* fatEntry() 266 { 267 ASSERT(isFat()); 268 return bitwise_cast<FatEntry*>(m_bits & ~FatFlag); 269 } 270 271 FatEntry* inflate() 272 { 273 if (LIKELY(isFat())) 274 return fatEntry(); 275 return inflateSlow(); 276 } 277 278 FatEntry* inflateSlow(); 279 280 ALWAYS_INLINE intptr_t bits() const 281 { 282 if (isFat()) 283 return fatEntry()->m_bits; 284 return m_bits; 285 } 286 287 ALWAYS_INLINE intptr_t& bits() 288 { 289 if (isFat()) 290 return fatEntry()->m_bits; 291 return m_bits; 292 } 293 294 void freeFatEntry() 295 { 296 if (LIKELY(!isFat())) 297 return; 298 freeFatEntrySlow(); 299 } 300 301 void freeFatEntrySlow(); 98 302 99 303 void pack(int index, bool readOnly, bool dontEnum) 100 304 { 101 m_bits = (index << FlagBits) | NotNullFlag; 305 intptr_t& bitsRef = bits(); 306 bitsRef = (static_cast<intptr_t>(index) << FlagBits) | NotNullFlag; 102 307 if (readOnly) 103 m_bits|= ReadOnlyFlag;308 bitsRef |= ReadOnlyFlag; 104 309 if (dontEnum) 105 m_bits|= DontEnumFlag;310 bitsRef |= DontEnumFlag; 106 311 } 107 312 108 313 bool isValidIndex(int index) 109 314 { 110 return (( index << FlagBits) >> FlagBits) == index;111 } 112 113 int m_bits;315 return ((static_cast<intptr_t>(index) << FlagBits) >> FlagBits) == static_cast<intptr_t>(index); 316 } 317 318 intptr_t m_bits; 114 319 }; 115 320
Note:
See TracChangeset
for help on using the changeset viewer.