]> git.saurik.com Git - apple/javascriptcore.git/blame - runtime/Structure.h
JavaScriptCore-1218.34.tar.gz
[apple/javascriptcore.git] / runtime / Structure.h
CommitLineData
9dae56ea 1/*
93a37866 2 * Copyright (C) 2008, 2009, 2012, 2013 Apple Inc. All rights reserved.
9dae56ea
A
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 COMPUTER, 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 COMPUTER, 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#ifndef Structure_h
27#define Structure_h
28
6fe7ccc8 29#include "ClassInfo.h"
93a37866
A
30#include "IndexingType.h"
31#include "JSCJSValue.h"
14957cd0 32#include "JSCell.h"
9dae56ea 33#include "JSType.h"
93a37866 34#include "PropertyName.h"
f9bf01c6 35#include "PropertyNameArray.h"
93a37866 36#include "PropertyOffset.h"
f9bf01c6 37#include "Protect.h"
93a37866 38#include "StructureRareData.h"
9dae56ea 39#include "StructureTransitionTable.h"
f9bf01c6 40#include "JSTypeInfo.h"
93a37866 41#include "Watchpoint.h"
9dae56ea
A
42#include <wtf/PassRefPtr.h>
43#include <wtf/RefCounted.h>
93a37866 44#include <wtf/text/StringImpl.h>
9dae56ea 45
9dae56ea
A
46
47namespace JSC {
48
93a37866
A
49class LLIntOffsetsExtractor;
50class PropertyNameArray;
51class PropertyNameArrayData;
52class PropertyTable;
53class StructureChain;
54class SlotVisitor;
55class JSString;
56
57// The out-of-line property storage capacity to use when first allocating out-of-line
58// storage. Note that all objects start out without having any out-of-line storage;
59// this comes into play only on the first property store that exhausts inline storage.
60static const unsigned initialOutOfLineCapacity = 4;
61
62// The factor by which to grow out-of-line storage when it is exhausted, after the
63// initial allocation.
64static const unsigned outOfLineGrowthFactor = 2;
65
66class Structure : public JSCell {
67public:
68 friend class StructureTransitionTable;
9dae56ea 69
93a37866
A
70 typedef JSCell Base;
71
72 static Structure* create(VM&, JSGlobalObject*, JSValue prototype, const TypeInfo&, const ClassInfo*, IndexingType = NonArray, unsigned inlineCapacity = 0);
73
74protected:
75 void finishCreation(VM& vm)
76 {
77 Base::finishCreation(vm);
78 ASSERT(m_prototype);
79 ASSERT(m_prototype.isObject() || m_prototype.isNull());
80 }
9dae56ea 81
93a37866
A
82 void finishCreation(VM& vm, CreatingEarlyCellTag)
83 {
84 Base::finishCreation(vm, this, CreatingEarlyCell);
85 ASSERT(m_prototype);
86 ASSERT(m_prototype.isNull());
87 ASSERT(!vm.structureStructure);
88 }
6fe7ccc8 89
93a37866
A
90public:
91 static void dumpStatistics();
92
93 JS_EXPORT_PRIVATE static Structure* addPropertyTransition(VM&, Structure*, PropertyName, unsigned attributes, JSCell* specificValue, PropertyOffset&);
94 JS_EXPORT_PRIVATE static Structure* addPropertyTransitionToExistingStructure(Structure*, PropertyName, unsigned attributes, JSCell* specificValue, PropertyOffset&);
95 static Structure* removePropertyTransition(VM&, Structure*, PropertyName, PropertyOffset&);
96 JS_EXPORT_PRIVATE static Structure* changePrototypeTransition(VM&, Structure*, JSValue prototype);
97 JS_EXPORT_PRIVATE static Structure* despecifyFunctionTransition(VM&, Structure*, PropertyName);
98 static Structure* attributeChangeTransition(VM&, Structure*, PropertyName, unsigned attributes);
99 static Structure* toCacheableDictionaryTransition(VM&, Structure*);
100 static Structure* toUncacheableDictionaryTransition(VM&, Structure*);
101 static Structure* sealTransition(VM&, Structure*);
102 static Structure* freezeTransition(VM&, Structure*);
103 static Structure* preventExtensionsTransition(VM&, Structure*);
104 static Structure* nonPropertyTransition(VM&, Structure*, NonPropertyTransition);
105
106 bool isSealed(VM&);
107 bool isFrozen(VM&);
108 bool isExtensible() const { return !m_preventExtensions; }
109 bool didTransition() const { return m_didTransition; }
110 bool putWillGrowOutOfLineStorage();
111 JS_EXPORT_PRIVATE size_t suggestedNewOutOfLineStorageCapacity();
112
113 Structure* flattenDictionaryStructure(VM&, JSObject*);
114
115 static const bool needsDestruction = true;
116 static const bool hasImmortalStructure = true;
117 static void destroy(JSCell*);
118
119 // These should be used with caution.
120 JS_EXPORT_PRIVATE PropertyOffset addPropertyWithoutTransition(VM&, PropertyName, unsigned attributes, JSCell* specificValue);
121 PropertyOffset removePropertyWithoutTransition(VM&, PropertyName);
122 void setPrototypeWithoutTransition(VM& vm, JSValue prototype) { m_prototype.set(vm, this, prototype); }
6fe7ccc8 123
93a37866
A
124 bool isDictionary() const { return m_dictionaryKind != NoneDictionaryKind; }
125 bool isUncacheableDictionary() const { return m_dictionaryKind == UncachedDictionaryKind; }
9dae56ea 126
93a37866
A
127 bool propertyAccessesAreCacheable() { return m_dictionaryKind != UncachedDictionaryKind && !typeInfo().prohibitsPropertyCaching(); }
128
129 // Type accessors.
130 const TypeInfo& typeInfo() const { ASSERT(structure()->classInfo() == &s_info); return m_typeInfo; }
131 bool isObject() const { return typeInfo().isObject(); }
132
133 IndexingType indexingType() const { return m_indexingType & AllArrayTypes; }
134 IndexingType indexingTypeIncludingHistory() const { return m_indexingType; }
f9bf01c6 135
93a37866
A
136 bool mayInterceptIndexedAccesses() const
137 {
138 return !!(indexingTypeIncludingHistory() & MayHaveIndexedAccessors);
139 }
f9bf01c6 140
93a37866 141 bool anyObjectInChainMayInterceptIndexedAccesses() const;
6fe7ccc8 142
93a37866
A
143 bool needsSlowPutIndexing() const;
144 NonPropertyTransition suggestedArrayStorageTransition() const;
ba379fdc 145
93a37866
A
146 JSGlobalObject* globalObject() const { return m_globalObject.get(); }
147 void setGlobalObject(VM& vm, JSGlobalObject* globalObject) { m_globalObject.set(vm, this, globalObject); }
6fe7ccc8 148
93a37866
A
149 JSValue storedPrototype() const { return m_prototype.get(); }
150 JSValue prototypeForLookup(ExecState*) const;
151 JSValue prototypeForLookup(JSGlobalObject*) const;
152 JSValue prototypeForLookup(CodeBlock*) const;
153 StructureChain* prototypeChain(VM&, JSGlobalObject*) const;
154 StructureChain* prototypeChain(ExecState*) const;
155 static void visitChildren(JSCell*, SlotVisitor&);
156
157 // Will just the prototype chain intercept this property access?
158 bool prototypeChainMayInterceptStoreTo(VM&, PropertyName);
159
160 bool transitionDidInvolveSpecificValue() const { return !!m_specificValueInPrevious; }
161
162 Structure* previousID() const
163 {
164 ASSERT(structure()->classInfo() == &s_info);
165 if (typeInfo().structureHasRareData())
166 return rareData()->previousID();
167 return previous();
168 }
169 bool transitivelyTransitionedFrom(Structure* structureToFind);
9dae56ea 170
93a37866
A
171 unsigned outOfLineCapacity() const
172 {
173 ASSERT(checkOffsetConsistency());
174
175 unsigned outOfLineSize = this->outOfLineSize();
f9bf01c6 176
93a37866
A
177 if (!outOfLineSize)
178 return 0;
9dae56ea 179
93a37866
A
180 if (outOfLineSize <= initialOutOfLineCapacity)
181 return initialOutOfLineCapacity;
9dae56ea 182
93a37866
A
183 ASSERT(outOfLineSize > initialOutOfLineCapacity);
184 COMPILE_ASSERT(outOfLineGrowthFactor == 2, outOfLineGrowthFactor_is_two);
185 return WTF::roundUpToPowerOfTwo(outOfLineSize);
186 }
187 unsigned outOfLineSize() const
188 {
189 ASSERT(checkOffsetConsistency());
190 ASSERT(structure()->classInfo() == &s_info);
191
192 return numberOfOutOfLineSlotsForLastOffset(m_offset);
193 }
194 bool hasInlineStorage() const
195 {
196 return !!m_inlineCapacity;
197 }
198 unsigned inlineCapacity() const
199 {
200 return m_inlineCapacity;
201 }
202 unsigned inlineSize() const
203 {
204 return std::min<unsigned>(m_offset + 1, m_inlineCapacity);
205 }
206 unsigned totalStorageSize() const
207 {
208 return numberOfSlotsForLastOffset(m_offset, m_inlineCapacity);
209 }
210 unsigned totalStorageCapacity() const
211 {
212 ASSERT(structure()->classInfo() == &s_info);
213 return outOfLineCapacity() + inlineCapacity();
214 }
9dae56ea 215
93a37866
A
216 PropertyOffset firstValidOffset() const
217 {
218 if (hasInlineStorage())
219 return 0;
220 return firstOutOfLineOffset;
221 }
222 PropertyOffset lastValidOffset() const
223 {
224 return m_offset;
225 }
226 bool isValidOffset(PropertyOffset offset) const
227 {
228 return offset >= firstValidOffset()
229 && offset <= lastValidOffset();
230 }
9dae56ea 231
93a37866 232 bool masqueradesAsUndefined(JSGlobalObject* lexicalGlobalObject);
14957cd0 233
93a37866
A
234 PropertyOffset get(VM&, PropertyName);
235 PropertyOffset get(VM&, const WTF::String& name);
236 JS_EXPORT_PRIVATE PropertyOffset get(VM&, PropertyName, unsigned& attributes, JSCell*& specificValue);
9dae56ea 237
93a37866
A
238 bool hasGetterSetterProperties() const { return m_hasGetterSetterProperties; }
239 bool hasReadOnlyOrGetterSetterPropertiesExcludingProto() const { return m_hasReadOnlyOrGetterSetterPropertiesExcludingProto; }
240 void setHasGetterSetterProperties(bool is__proto__)
241 {
242 m_hasGetterSetterProperties = true;
243 if (!is__proto__)
244 m_hasReadOnlyOrGetterSetterPropertiesExcludingProto = true;
245 }
246 void setContainsReadOnlyProperties()
247 {
248 m_hasReadOnlyOrGetterSetterPropertiesExcludingProto = true;
249 }
f9bf01c6 250
93a37866
A
251 bool hasNonEnumerableProperties() const { return m_hasNonEnumerableProperties; }
252
253 bool isEmpty() const
254 {
255 ASSERT(checkOffsetConsistency());
256 return !JSC::isValidOffset(m_offset);
257 }
6fe7ccc8 258
93a37866
A
259 JS_EXPORT_PRIVATE void despecifyDictionaryFunction(VM&, PropertyName);
260 void disableSpecificFunctionTracking() { m_specificFunctionThrashCount = maxSpecificFunctionThrashCount; }
9dae56ea 261
93a37866
A
262 void setEnumerationCache(VM&, JSPropertyNameIterator* enumerationCache); // Defined in JSPropertyNameIterator.h.
263 JSPropertyNameIterator* enumerationCache(); // Defined in JSPropertyNameIterator.h.
264 void getPropertyNamesFromStructure(VM&, PropertyNameArray&, EnumerationMode);
9dae56ea 265
93a37866 266 JSString* objectToStringValue()
9dae56ea 267 {
93a37866
A
268 if (!typeInfo().structureHasRareData())
269 return 0;
270 return rareData()->objectToStringValue();
14957cd0 271 }
9dae56ea 272
93a37866 273 void setObjectToStringValue(VM& vm, const JSCell* owner, JSString* value)
6fe7ccc8 274 {
93a37866
A
275 if (!typeInfo().structureHasRareData())
276 allocateRareData(vm);
277 rareData()->setObjectToStringValue(vm, owner, value);
6fe7ccc8 278 }
93a37866
A
279
280 bool staticFunctionsReified()
14957cd0 281 {
93a37866 282 return m_staticFunctionReified;
14957cd0 283 }
9dae56ea 284
93a37866 285 void setStaticFunctionsReified()
14957cd0 286 {
93a37866 287 m_staticFunctionReified = true;
14957cd0 288 }
9dae56ea 289
93a37866
A
290 const ClassInfo* classInfo() const { return m_classInfo; }
291
292 static ptrdiff_t prototypeOffset()
14957cd0 293 {
93a37866 294 return OBJECT_OFFSETOF(Structure, m_prototype);
14957cd0 295 }
9dae56ea 296
93a37866 297 static ptrdiff_t globalObjectOffset()
14957cd0 298 {
93a37866 299 return OBJECT_OFFSETOF(Structure, m_globalObject);
14957cd0 300 }
9dae56ea 301
93a37866 302 static ptrdiff_t typeInfoFlagsOffset()
14957cd0 303 {
93a37866 304 return OBJECT_OFFSETOF(Structure, m_typeInfo) + TypeInfo::flagsOffset();
6fe7ccc8
A
305 }
306
93a37866
A
307 static ptrdiff_t typeInfoTypeOffset()
308 {
309 return OBJECT_OFFSETOF(Structure, m_typeInfo) + TypeInfo::typeOffset();
310 }
311
312 static ptrdiff_t classInfoOffset()
313 {
314 return OBJECT_OFFSETOF(Structure, m_classInfo);
315 }
316
317 static ptrdiff_t indexingTypeOffset()
6fe7ccc8 318 {
93a37866 319 return OBJECT_OFFSETOF(Structure, m_indexingType);
14957cd0 320 }
9dae56ea 321
93a37866
A
322 static Structure* createStructure(VM&);
323
324 bool transitionWatchpointSetHasBeenInvalidated() const
14957cd0 325 {
93a37866
A
326 return m_transitionWatchpointSet.hasBeenInvalidated();
327 }
6fe7ccc8 328
93a37866
A
329 bool transitionWatchpointSetIsStillValid() const
330 {
331 return m_transitionWatchpointSet.isStillValid();
332 }
6fe7ccc8 333
93a37866
A
334 void addTransitionWatchpoint(Watchpoint* watchpoint) const
335 {
336 ASSERT(transitionWatchpointSetIsStillValid());
337 m_transitionWatchpointSet.add(watchpoint);
14957cd0 338 }
93a37866
A
339
340 void notifyTransitionFromThisStructure() const
341 {
342 m_transitionWatchpointSet.notifyWrite();
343 }
344
345 static JS_EXPORTDATA const ClassInfo s_info;
346
347private:
348 friend class LLIntOffsetsExtractor;
9dae56ea 349
93a37866
A
350 JS_EXPORT_PRIVATE Structure(VM&, JSGlobalObject*, JSValue prototype, const TypeInfo&, const ClassInfo*, IndexingType, unsigned inlineCapacity);
351 Structure(VM&);
352 Structure(VM&, const Structure*);
353
354 static Structure* create(VM&, const Structure*);
355
356 typedef enum {
357 NoneDictionaryKind = 0,
358 CachedDictionaryKind = 1,
359 UncachedDictionaryKind = 2
360 } DictionaryKind;
361 static Structure* toDictionaryTransition(VM&, Structure*, DictionaryKind);
362
363 PropertyOffset putSpecificValue(VM&, PropertyName, unsigned attributes, JSCell* specificValue);
364 PropertyOffset remove(PropertyName);
365
366 void createPropertyMap(VM&, unsigned keyCount = 0);
367 void checkConsistency();
368
369 bool despecifyFunction(VM&, PropertyName);
370 void despecifyAllFunctions(VM&);
371
372 WriteBarrier<PropertyTable>& propertyTable();
373 PropertyTable* takePropertyTableOrCloneIfPinned(VM&, Structure* owner);
374 PropertyTable* copyPropertyTable(VM&, Structure* owner);
375 PropertyTable* copyPropertyTableForPinning(VM&, Structure* owner);
376 JS_EXPORT_PRIVATE void materializePropertyMap(VM&);
377 void materializePropertyMapIfNecessary(VM& vm)
14957cd0 378 {
93a37866
A
379 ASSERT(structure()->classInfo() == &s_info);
380 ASSERT(checkOffsetConsistency());
381 if (!propertyTable() && previousID())
382 materializePropertyMap(vm);
383 }
384 void materializePropertyMapIfNecessaryForPinning(VM& vm)
385 {
386 ASSERT(structure()->classInfo() == &s_info);
387 checkOffsetConsistency();
388 if (!propertyTable())
389 materializePropertyMap(vm);
9dae56ea
A
390 }
391
93a37866 392 void setPreviousID(VM& vm, Structure* transition, Structure* structure)
6fe7ccc8 393 {
93a37866
A
394 if (typeInfo().structureHasRareData())
395 rareData()->setPreviousID(vm, transition, structure);
396 else
397 m_previousOrRareData.set(vm, transition, structure);
6fe7ccc8
A
398 }
399
93a37866 400 void clearPreviousID()
6fe7ccc8 401 {
93a37866
A
402 if (typeInfo().structureHasRareData())
403 rareData()->clearPreviousID();
404 else
405 m_previousOrRareData.clear();
6fe7ccc8
A
406 }
407
93a37866 408 int transitionCount() const
6fe7ccc8 409 {
93a37866
A
410 // Since the number of transitions is always the same as m_offset, we keep the size of Structure down by not storing both.
411 return numberOfSlotsForLastOffset(m_offset, m_inlineCapacity);
6fe7ccc8
A
412 }
413
93a37866
A
414 bool isValid(JSGlobalObject*, StructureChain* cachedPrototypeChain) const;
415 bool isValid(ExecState*, StructureChain* cachedPrototypeChain) const;
416
417 void pin();
418
419 Structure* previous() const
420 {
421 ASSERT(!typeInfo().structureHasRareData());
422 return static_cast<Structure*>(m_previousOrRareData.get());
423 }
424
425 StructureRareData* rareData() const
426 {
427 ASSERT(typeInfo().structureHasRareData());
428 return static_cast<StructureRareData*>(m_previousOrRareData.get());
429 }
430
431 bool checkOffsetConsistency() const;
432
433 void allocateRareData(VM&);
434 void cloneRareDataFrom(VM&, const Structure*);
435
436 static const int s_maxTransitionLength = 64;
437
438 static const unsigned maxSpecificFunctionThrashCount = 3;
439
440 WriteBarrier<JSGlobalObject> m_globalObject;
441 WriteBarrier<Unknown> m_prototype;
442 mutable WriteBarrier<StructureChain> m_cachedPrototypeChain;
443
444 WriteBarrier<JSCell> m_previousOrRareData;
445
446 RefPtr<StringImpl> m_nameInPrevious;
447 WriteBarrier<JSCell> m_specificValueInPrevious;
448
449 const ClassInfo* m_classInfo;
450
451 StructureTransitionTable m_transitionTable;
452
453 // Should be accessed through propertyTable(). During GC, it may be set to 0 by another thread.
454 WriteBarrier<PropertyTable> m_propertyTableUnsafe;
455
456 mutable InlineWatchpointSet m_transitionWatchpointSet;
457
458 COMPILE_ASSERT(firstOutOfLineOffset < 256, firstOutOfLineOffset_fits);
459
460 // m_offset does not account for anonymous slots
461 PropertyOffset m_offset;
462
463 TypeInfo m_typeInfo;
464 IndexingType m_indexingType;
465
466 uint8_t m_inlineCapacity;
467 unsigned m_dictionaryKind : 2;
468 bool m_isPinnedPropertyTable : 1;
469 bool m_hasGetterSetterProperties : 1;
470 bool m_hasReadOnlyOrGetterSetterPropertiesExcludingProto : 1;
471 bool m_hasNonEnumerableProperties : 1;
472 unsigned m_attributesInPrevious : 14;
473 unsigned m_specificFunctionThrashCount : 2;
474 unsigned m_preventExtensions : 1;
475 unsigned m_didTransition : 1;
476 unsigned m_staticFunctionReified;
477};
478
9dae56ea
A
479} // namespace JSC
480
481#endif // Structure_h