source: webkit/trunk/JavaScriptCore/runtime/Structure.cpp@ 38444

Last change on this file since 38444 was 38440, checked in by Darin Adler, 17 years ago

JavaScriptCore:

2008-11-15 Darin Adler <Darin Adler>

Rubber stamped by Geoff Garen.

  • do the long-planned StructureID -> Structure rename
  • API/JSCallbackConstructor.cpp: (JSC::JSCallbackConstructor::JSCallbackConstructor):
  • API/JSCallbackConstructor.h: (JSC::JSCallbackConstructor::createStructure):
  • API/JSCallbackFunction.h: (JSC::JSCallbackFunction::createStructure):
  • API/JSCallbackObject.h: (JSC::JSCallbackObject::createStructure):
  • API/JSCallbackObjectFunctions.h: (JSC::::JSCallbackObject):
  • API/JSValueRef.cpp: (JSValueIsInstanceOfConstructor):
  • GNUmakefile.am:
  • JavaScriptCore.exp:
  • JavaScriptCore.pri:
  • JavaScriptCore.scons:
  • JavaScriptCore.vcproj/JavaScriptCore/JavaScriptCore.vcproj:
  • JavaScriptCore.xcodeproj/project.pbxproj:
  • JavaScriptCoreSources.bkl:
  • VM/CTI.cpp: (JSC::CTI::compileBinaryArithOp): (JSC::CTI::privateCompileMainPass): (JSC::CTI::privateCompileGetByIdSelf): (JSC::CTI::privateCompileGetByIdProto): (JSC::CTI::privateCompileGetByIdChain): (JSC::CTI::privateCompilePutByIdReplace): (JSC::transitionWillNeedStorageRealloc): (JSC::CTI::privateCompilePutByIdTransition): (JSC::CTI::patchGetByIdSelf): (JSC::CTI::patchPutByIdReplace):
  • VM/CTI.h: (JSC::CTI::compileGetByIdSelf): (JSC::CTI::compileGetByIdProto): (JSC::CTI::compileGetByIdChain): (JSC::CTI::compilePutByIdReplace): (JSC::CTI::compilePutByIdTransition):
  • VM/CodeBlock.cpp: (JSC::CodeBlock::printStructure): (JSC::CodeBlock::printStructures): (JSC::CodeBlock::dump): (JSC::CodeBlock::~CodeBlock): (JSC::CodeBlock::derefStructures): (JSC::CodeBlock::refStructures):
  • VM/CodeBlock.h:
  • VM/Instruction.h: (JSC::Instruction::Instruction): (JSC::Instruction::):
  • VM/Machine.cpp: (JSC::jsTypeStringForValue): (JSC::jsIsObjectType): (JSC::BytecodeInterpreter::resolveGlobal): (JSC::BytecodeInterpreter::BytecodeInterpreter): (JSC::cachePrototypeChain): (JSC::BytecodeInterpreter::tryCachePutByID): (JSC::BytecodeInterpreter::uncachePutByID): (JSC::BytecodeInterpreter::tryCacheGetByID): (JSC::BytecodeInterpreter::uncacheGetByID): (JSC::BytecodeInterpreter::privateExecute): (JSC::BytecodeInterpreter::tryCTICachePutByID): (JSC::BytecodeInterpreter::tryCTICacheGetByID): (JSC::BytecodeInterpreter::cti_op_instanceof): (JSC::BytecodeInterpreter::cti_op_construct_JSConstruct): (JSC::BytecodeInterpreter::cti_op_resolve_global): (JSC::BytecodeInterpreter::cti_op_is_undefined):
  • runtime/Arguments.h: (JSC::Arguments::createStructure):
  • runtime/ArrayConstructor.cpp: (JSC::ArrayConstructor::ArrayConstructor):
  • runtime/ArrayConstructor.h:
  • runtime/ArrayPrototype.cpp: (JSC::ArrayPrototype::ArrayPrototype):
  • runtime/ArrayPrototype.h:
  • runtime/BatchedTransitionOptimizer.h: (JSC::BatchedTransitionOptimizer::BatchedTransitionOptimizer): (JSC::BatchedTransitionOptimizer::~BatchedTransitionOptimizer):
  • runtime/BooleanConstructor.cpp: (JSC::BooleanConstructor::BooleanConstructor):
  • runtime/BooleanConstructor.h:
  • runtime/BooleanObject.cpp: (JSC::BooleanObject::BooleanObject):
  • runtime/BooleanObject.h:
  • runtime/BooleanPrototype.cpp: (JSC::BooleanPrototype::BooleanPrototype):
  • runtime/BooleanPrototype.h:
  • runtime/DateConstructor.cpp: (JSC::DateConstructor::DateConstructor):
  • runtime/DateConstructor.h:
  • runtime/DateInstance.cpp: (JSC::DateInstance::DateInstance):
  • runtime/DateInstance.h:
  • runtime/DatePrototype.cpp: (JSC::DatePrototype::DatePrototype):
  • runtime/DatePrototype.h: (JSC::DatePrototype::createStructure):
  • runtime/ErrorConstructor.cpp: (JSC::ErrorConstructor::ErrorConstructor):
  • runtime/ErrorConstructor.h:
  • runtime/ErrorInstance.cpp: (JSC::ErrorInstance::ErrorInstance):
  • runtime/ErrorInstance.h:
  • runtime/ErrorPrototype.cpp: (JSC::ErrorPrototype::ErrorPrototype):
  • runtime/ErrorPrototype.h:
  • runtime/FunctionConstructor.cpp: (JSC::FunctionConstructor::FunctionConstructor):
  • runtime/FunctionConstructor.h:
  • runtime/FunctionPrototype.cpp: (JSC::FunctionPrototype::FunctionPrototype): (JSC::FunctionPrototype::addFunctionProperties):
  • runtime/FunctionPrototype.h: (JSC::FunctionPrototype::createStructure):
  • runtime/GlobalEvalFunction.cpp: (JSC::GlobalEvalFunction::GlobalEvalFunction):
  • runtime/GlobalEvalFunction.h:
  • runtime/Identifier.h:
  • runtime/InternalFunction.cpp: (JSC::InternalFunction::InternalFunction):
  • runtime/InternalFunction.h: (JSC::InternalFunction::createStructure): (JSC::InternalFunction::InternalFunction):
  • runtime/JSActivation.cpp: (JSC::JSActivation::JSActivation):
  • runtime/JSActivation.h: (JSC::JSActivation::createStructure):
  • runtime/JSArray.cpp: (JSC::JSArray::JSArray):
  • runtime/JSArray.h: (JSC::JSArray::createStructure):
  • runtime/JSCell.h: (JSC::JSCell::JSCell): (JSC::JSCell::isObject): (JSC::JSCell::isString): (JSC::JSCell::structure): (JSC::JSValue::needsThisConversion):
  • runtime/JSFunction.cpp: (JSC::JSFunction::construct):
  • runtime/JSFunction.h: (JSC::JSFunction::JSFunction): (JSC::JSFunction::createStructure):
  • runtime/JSGlobalData.cpp: (JSC::JSGlobalData::JSGlobalData): (JSC::JSGlobalData::createLeaked):
  • runtime/JSGlobalData.h:
  • runtime/JSGlobalObject.cpp: (JSC::markIfNeeded): (JSC::JSGlobalObject::reset):
  • runtime/JSGlobalObject.h: (JSC::JSGlobalObject::JSGlobalObject): (JSC::JSGlobalObject::argumentsStructure): (JSC::JSGlobalObject::arrayStructure): (JSC::JSGlobalObject::booleanObjectStructure): (JSC::JSGlobalObject::callbackConstructorStructure): (JSC::JSGlobalObject::callbackFunctionStructure): (JSC::JSGlobalObject::callbackObjectStructure): (JSC::JSGlobalObject::dateStructure): (JSC::JSGlobalObject::emptyObjectStructure): (JSC::JSGlobalObject::errorStructure): (JSC::JSGlobalObject::functionStructure): (JSC::JSGlobalObject::numberObjectStructure): (JSC::JSGlobalObject::prototypeFunctionStructure): (JSC::JSGlobalObject::regExpMatchesArrayStructure): (JSC::JSGlobalObject::regExpStructure): (JSC::JSGlobalObject::stringObjectStructure): (JSC::JSGlobalObject::createStructure): (JSC::Structure::prototypeForLookup):
  • runtime/JSNotAnObject.h: (JSC::JSNotAnObject::createStructure):
  • runtime/JSNumberCell.h: (JSC::JSNumberCell::createStructure): (JSC::JSNumberCell::JSNumberCell):
  • runtime/JSObject.cpp: (JSC::JSObject::mark): (JSC::JSObject::put): (JSC::JSObject::deleteProperty): (JSC::JSObject::defineGetter): (JSC::JSObject::defineSetter): (JSC::JSObject::getPropertyAttributes): (JSC::JSObject::getPropertyNames): (JSC::JSObject::removeDirect): (JSC::JSObject::createInheritorID):
  • runtime/JSObject.h: (JSC::JSObject::getDirect): (JSC::JSObject::getDirectLocation): (JSC::JSObject::hasCustomProperties): (JSC::JSObject::hasGetterSetterProperties): (JSC::JSObject::createStructure): (JSC::JSObject::JSObject): (JSC::JSObject::~JSObject): (JSC::JSObject::prototype): (JSC::JSObject::setPrototype): (JSC::JSObject::setStructure): (JSC::JSObject::inheritorID): (JSC::JSObject::inlineGetOwnPropertySlot): (JSC::JSObject::getOwnPropertySlotForWrite): (JSC::JSCell::fastGetOwnPropertySlot): (JSC::JSObject::putDirect): (JSC::JSObject::putDirectWithoutTransition): (JSC::JSObject::transitionTo):
  • runtime/JSPropertyNameIterator.h: (JSC::JSPropertyNameIterator::next):
  • runtime/JSStaticScopeObject.h: (JSC::JSStaticScopeObject::JSStaticScopeObject): (JSC::JSStaticScopeObject::createStructure):
  • runtime/JSString.h: (JSC::JSString::JSString): (JSC::JSString::createStructure):
  • runtime/JSVariableObject.h: (JSC::JSVariableObject::JSVariableObject):
  • runtime/JSWrapperObject.h: (JSC::JSWrapperObject::JSWrapperObject):
  • runtime/MathObject.cpp: (JSC::MathObject::MathObject):
  • runtime/MathObject.h: (JSC::MathObject::createStructure):
  • runtime/NativeErrorConstructor.cpp: (JSC::NativeErrorConstructor::NativeErrorConstructor):
  • runtime/NativeErrorConstructor.h:
  • runtime/NativeErrorPrototype.cpp: (JSC::NativeErrorPrototype::NativeErrorPrototype):
  • runtime/NativeErrorPrototype.h:
  • runtime/NumberConstructor.cpp: (JSC::NumberConstructor::NumberConstructor):
  • runtime/NumberConstructor.h: (JSC::NumberConstructor::createStructure):
  • runtime/NumberObject.cpp: (JSC::NumberObject::NumberObject):
  • runtime/NumberObject.h:
  • runtime/NumberPrototype.cpp: (JSC::NumberPrototype::NumberPrototype):
  • runtime/NumberPrototype.h:
  • runtime/ObjectConstructor.cpp: (JSC::ObjectConstructor::ObjectConstructor):
  • runtime/ObjectConstructor.h:
  • runtime/ObjectPrototype.cpp: (JSC::ObjectPrototype::ObjectPrototype):
  • runtime/ObjectPrototype.h:
  • runtime/Operations.h: (JSC::equalSlowCaseInline):
  • runtime/PropertyNameArray.h: (JSC::PropertyNameArrayData::setCachedStructure): (JSC::PropertyNameArrayData::cachedStructure): (JSC::PropertyNameArrayData::setCachedPrototypeChain): (JSC::PropertyNameArrayData::cachedPrototypeChain): (JSC::PropertyNameArrayData::PropertyNameArrayData):
  • runtime/PrototypeFunction.cpp: (JSC::PrototypeFunction::PrototypeFunction):
  • runtime/PrototypeFunction.h:
  • runtime/RegExpConstructor.cpp: (JSC::RegExpConstructor::RegExpConstructor):
  • runtime/RegExpConstructor.h: (JSC::RegExpConstructor::createStructure):
  • runtime/RegExpObject.cpp: (JSC::RegExpObject::RegExpObject):
  • runtime/RegExpObject.h: (JSC::RegExpObject::createStructure):
  • runtime/RegExpPrototype.cpp: (JSC::RegExpPrototype::RegExpPrototype):
  • runtime/RegExpPrototype.h:
  • runtime/StringConstructor.cpp: (JSC::StringConstructor::StringConstructor):
  • runtime/StringConstructor.h:
  • runtime/StringObject.cpp: (JSC::StringObject::StringObject):
  • runtime/StringObject.h: (JSC::StringObject::createStructure):
  • runtime/StringObjectThatMasqueradesAsUndefined.h: (JSC::StringObjectThatMasqueradesAsUndefined::create): (JSC::StringObjectThatMasqueradesAsUndefined::StringObjectThatMasqueradesAsUndefined): (JSC::StringObjectThatMasqueradesAsUndefined::createStructure):
  • runtime/StringPrototype.cpp: (JSC::StringPrototype::StringPrototype):
  • runtime/StringPrototype.h:
  • runtime/Structure.cpp: Copied from JavaScriptCore/runtime/StructureID.cpp. (JSC::Structure::dumpStatistics): (JSC::Structure::Structure): (JSC::Structure::~Structure): (JSC::Structure::startIgnoringLeaks): (JSC::Structure::stopIgnoringLeaks): (JSC::Structure::materializePropertyMap): (JSC::Structure::getEnumerablePropertyNames): (JSC::Structure::clearEnumerationCache): (JSC::Structure::growPropertyStorageCapacity): (JSC::Structure::addPropertyTransitionToExistingStructure): (JSC::Structure::addPropertyTransition): (JSC::Structure::removePropertyTransition): (JSC::Structure::changePrototypeTransition): (JSC::Structure::getterSetterTransition): (JSC::Structure::toDictionaryTransition): (JSC::Structure::fromDictionaryTransition): (JSC::Structure::addPropertyWithoutTransition): (JSC::Structure::removePropertyWithoutTransition): (JSC::Structure::createCachedPrototypeChain): (JSC::Structure::checkConsistency): (JSC::Structure::copyPropertyTable): (JSC::Structure::get): (JSC::Structure::put): (JSC::Structure::remove): (JSC::Structure::insertIntoPropertyMapHashTable): (JSC::Structure::createPropertyMapHashTable): (JSC::Structure::expandPropertyMapHashTable): (JSC::Structure::rehashPropertyMapHashTable): (JSC::Structure::getEnumerablePropertyNamesInternal):
  • runtime/Structure.h: Copied from JavaScriptCore/runtime/StructureID.h. (JSC::Structure::create): (JSC::Structure::previousID): (JSC::Structure::setCachedPrototypeChain): (JSC::Structure::cachedPrototypeChain): (JSC::Structure::): (JSC::Structure::get):
  • runtime/StructureChain.cpp: Copied from JavaScriptCore/runtime/StructureIDChain.cpp. (JSC::StructureChain::StructureChain): (JSC::structureChainsAreEqual):
  • runtime/StructureChain.h: Copied from JavaScriptCore/runtime/StructureIDChain.h. (JSC::StructureChain::create): (JSC::StructureChain::head):
  • runtime/StructureID.cpp: Removed.
  • runtime/StructureID.h: Removed.
  • runtime/StructureIDChain.cpp: Removed.
  • runtime/StructureIDChain.h: Removed.
  • runtime/StructureIDTransitionTable.h: Removed.
  • runtime/StructureTransitionTable.h: Copied from JavaScriptCore/runtime/StructureIDTransitionTable.h.

JavaScriptGlue:

2008-11-15 Darin Adler <Darin Adler>

Rubber stamped by Geoff Garen.

  • do the long-planned StructureID -> Structure rename
  • JSRun.cpp: (JSGlueGlobalObject::JSGlueGlobalObject): (JSRun::JSRun):
  • JSRun.h: (JSGlueGlobalObject::userObjectStructure):
  • JSUtils.cpp: (getThreadGlobalObject):
  • UserObjectImp.cpp: (UserObjectImp::UserObjectImp):
  • UserObjectImp.h: (UserObjectImp::createStructure):

WebCore:

2008-11-15 Darin Adler <Darin Adler>

Rubber stamped by Geoff Garen.

  • do the long-planned StructureID -> Structure rename
  • ForwardingHeaders/runtime/Structure.h: Copied from WebCore/ForwardingHeaders/runtime/StructureID.h.
  • ForwardingHeaders/runtime/StructureID.h: Removed.
  • bindings/js/JSAudioConstructor.cpp: (WebCore::JSAudioConstructor::JSAudioConstructor):
  • bindings/js/JSDOMBinding.cpp: (WebCore::getCachedDOMStructure): (WebCore::cacheDOMStructure):
  • bindings/js/JSDOMBinding.h: (WebCore::DOMObject::DOMObject): (WebCore::getDOMStructure):
  • bindings/js/JSDOMGlobalObject.cpp: (WebCore::JSDOMGlobalObject::JSDOMGlobalObject):
  • bindings/js/JSDOMGlobalObject.h:
  • bindings/js/JSDOMWindowBase.cpp: (WebCore::JSDOMWindowBase::JSDOMWindowBase):
  • bindings/js/JSDOMWindowBase.h:
  • bindings/js/JSDOMWindowShell.cpp: (WebCore::JSDOMWindowShell::JSDOMWindowShell): (WebCore::JSDOMWindowShell::setWindow):
  • bindings/js/JSDOMWindowShell.h: (WebCore::JSDOMWindowShell::createStructure):
  • bindings/js/JSDedicatedWorkerConstructor.cpp: (WebCore::JSDedicatedWorkerConstructor::JSDedicatedWorkerConstructor):
  • bindings/js/JSHTMLAllCollection.h: (WebCore::JSHTMLAllCollection::JSHTMLAllCollection): (WebCore::JSHTMLAllCollection::createStructure):
  • bindings/js/JSImageConstructor.cpp: (WebCore::JSImageConstructor::JSImageConstructor):
  • bindings/js/JSInspectedObjectWrapper.cpp: (WebCore::JSInspectedObjectWrapper::wrap): (WebCore::JSInspectedObjectWrapper::JSInspectedObjectWrapper):
  • bindings/js/JSInspectedObjectWrapper.h:
  • bindings/js/JSInspectorCallbackWrapper.cpp: (WebCore::leakInspectorCallbackWrapperStructure): (WebCore::JSInspectorCallbackWrapper::wrap): (WebCore::JSInspectorCallbackWrapper::JSInspectorCallbackWrapper):
  • bindings/js/JSInspectorCallbackWrapper.h:
  • bindings/js/JSMessageChannelConstructor.cpp: (WebCore::JSMessageChannelConstructor::JSMessageChannelConstructor):
  • bindings/js/JSNamedNodesCollection.h: (WebCore::JSNamedNodesCollection::createStructure):
  • bindings/js/JSOptionConstructor.cpp: (WebCore::JSOptionConstructor::JSOptionConstructor):
  • bindings/js/JSQuarantinedObjectWrapper.cpp: (WebCore::JSQuarantinedObjectWrapper::JSQuarantinedObjectWrapper):
  • bindings/js/JSQuarantinedObjectWrapper.h: (WebCore::JSQuarantinedObjectWrapper::createStructure):
  • bindings/js/JSRGBColor.h: (WebCore::JSRGBColor::createStructure):
  • bindings/js/JSWorkerContext.cpp: (WebCore::createJSWorkerContextStructure): (WebCore::JSWorkerContext::JSWorkerContext): (WebCore::JSWorkerContext::createPrototype):
  • bindings/js/JSWorkerContext.h: (WebCore::JSWorkerContext::createStructure): (WebCore::JSWorkerContextPrototype::JSWorkerContextPrototype): (WebCore::JSWorkerContextPrototype::createStructure):
  • bindings/js/JSXMLHttpRequestConstructor.cpp: (WebCore::JSXMLHttpRequestConstructor::JSXMLHttpRequestConstructor):
  • bindings/js/JSXSLTProcessorConstructor.cpp: (WebCore::JSXSLTProcessorConstructor::JSXSLTProcessorConstructor):
  • bindings/scripts/CodeGeneratorJS.pm:
  • bridge/objc/objc_runtime.h: (JSC::Bindings::ObjcFallbackObjectImp::createStructure):
  • bridge/qt/qt_runtime.cpp: (JSC::Bindings::QtConnectionObject::execute):
  • bridge/qt/qt_runtime.h: (JSC::Bindings::QtRuntimeMethod::createStructure):
  • bridge/runtime_array.h: (JSC::RuntimeArray::createStructure):
  • bridge/runtime_method.h: (JSC::RuntimeMethod::createStructure):
  • bridge/runtime_object.cpp: (JSC::RuntimeObjectImp::RuntimeObjectImp):
  • bridge/runtime_object.h: (JSC::RuntimeObjectImp::createStructure):

WebKitTools:

2008-11-15 Darin Adler <Darin Adler>

Rubber stamped by Geoff Garen.

  • do the long-planned StructureID -> Structure rename
  • Scripts/check-for-global-initializers: Update name of StructureID.o.
  • Scripts/do-webcore-rename: Renaming script that I used.
File size: 33.3 KB
Line 
1/*
2 * Copyright (C) 2008 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 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#include "config.h"
27#include "Structure.h"
28
29#include "Identifier.h"
30#include "JSObject.h"
31#include "PropertyNameArray.h"
32#include "StructureChain.h"
33#include "Lookup.h"
34#include <wtf/RefCountedLeakCounter.h>
35#include <wtf/RefPtr.h>
36
37#if ENABLE(JSC_MULTIPLE_THREADS)
38#include <wtf/Threading.h>
39#endif
40
41#define DUMP_STRUCTURE_ID_STATISTICS 0
42
43#ifndef NDEBUG
44#define DO_PROPERTYMAP_CONSTENCY_CHECK 0
45#else
46#define DO_PROPERTYMAP_CONSTENCY_CHECK 0
47#endif
48
49using namespace std;
50using WTF::doubleHash;
51
52namespace JSC {
53
54// Choose a number for the following so that most property maps are smaller,
55// but it's not going to blow out the stack to allocate this number of pointers.
56static const int smallMapThreshold = 1024;
57
58// The point at which the function call overhead of the qsort implementation
59// becomes small compared to the inefficiency of insertion sort.
60static const unsigned tinyMapThreshold = 20;
61
62static const unsigned newTableSize = 16;
63
64#ifndef NDEBUG
65static WTF::RefCountedLeakCounter structureCounter("Structure");
66
67#if ENABLE(JSC_MULTIPLE_THREADS)
68static Mutex ignoreSetMutex;
69#endif
70
71static bool shouldIgnoreLeaks;
72static HashSet<Structure*> ignoreSet;
73#endif
74
75#if DUMP_STRUCTURE_ID_STATISTICS
76static HashSet<Structure*> liveStructureSet;
77#endif
78
79void Structure::dumpStatistics()
80{
81#if DUMP_STRUCTURE_ID_STATISTICS
82 unsigned numberLeaf = 0;
83 unsigned numberUsingSingleSlot = 0;
84 unsigned numberSingletons = 0;
85 unsigned numberWithPropertyMaps = 0;
86 unsigned totalPropertyMapsSize = 0;
87
88 HashSet<Structure*>::const_iterator end = liveStructureSet.end();
89 for (HashSet<Structure*>::const_iterator it = liveStructureSet.begin(); it != end; ++it) {
90 Structure* structure = *it;
91 if (structure->m_usingSingleTransitionSlot) {
92 if (!structure->m_transitions.singleTransition)
93 ++numberLeaf;
94 else
95 ++numberUsingSingleSlot;
96
97 if (!structure->m_previous && !structure->m_transitions.singleTransition)
98 ++numberSingletons;
99 }
100
101 if (structure->m_propertyTable) {
102 ++numberWithPropertyMaps;
103 totalPropertyMapsSize += PropertyMapHashTable::allocationSize(structure->m_propertyTable->size);
104 }
105 }
106
107 printf("Number of live Structures: %d\n", liveStructureSet.size());
108 printf("Number of Structures using the single item optimization for transition map: %d\n", numberUsingSingleSlot);
109 printf("Number of Structures that are leaf nodes: %d\n", numberLeaf);
110 printf("Number of Structures that singletons: %d\n", numberSingletons);
111 printf("Number of Structures with PropertyMaps: %d\n", numberWithPropertyMaps);
112
113 printf("Size of a single Structures: %d\n", static_cast<unsigned>(sizeof(Structure)));
114 printf("Size of sum of all property maps: %d\n", totalPropertyMapsSize);
115 printf("Size of average of all property maps: %f\n", static_cast<double>(totalPropertyMapsSize) / static_cast<double>(liveStructureSet.size()));
116#else
117 printf("Dumping Structure statistics is not enabled.\n");
118#endif
119}
120
121Structure::Structure(JSValue* prototype, const TypeInfo& typeInfo)
122 : m_typeInfo(typeInfo)
123 , m_prototype(prototype)
124 , m_cachedPrototypeChain(0)
125 , m_previous(0)
126 , m_nameInPrevious(0)
127 , m_transitionCount(0)
128 , m_propertyTable(0)
129 , m_propertyStorageCapacity(JSObject::inlineStorageCapacity)
130 , m_offset(WTF::notFound)
131 , m_isDictionary(false)
132 , m_isPinnedPropertyTable(false)
133 , m_hasGetterSetterProperties(false)
134 , m_usingSingleTransitionSlot(true)
135 , m_attributesInPrevious(0)
136{
137 ASSERT(m_prototype);
138 ASSERT(m_prototype->isObject() || m_prototype->isNull());
139
140 m_transitions.singleTransition = 0;
141
142#ifndef NDEBUG
143#if ENABLE(JSC_MULTIPLE_THREADS)
144 MutexLocker protect(ignoreSetMutex);
145#endif
146 if (shouldIgnoreLeaks)
147 ignoreSet.add(this);
148 else
149 structureCounter.increment();
150#endif
151
152#if DUMP_STRUCTURE_ID_STATISTICS
153 liveStructureSet.add(this);
154#endif
155}
156
157Structure::~Structure()
158{
159 if (m_previous) {
160 if (m_previous->m_usingSingleTransitionSlot) {
161 m_previous->m_transitions.singleTransition = 0;
162 } else {
163 ASSERT(m_previous->m_transitions.table->contains(make_pair(m_nameInPrevious, m_attributesInPrevious)));
164 m_previous->m_transitions.table->remove(make_pair(m_nameInPrevious, m_attributesInPrevious));
165 }
166 }
167
168 if (m_cachedPropertyNameArrayData)
169 m_cachedPropertyNameArrayData->setCachedStructure(0);
170
171 if (!m_usingSingleTransitionSlot)
172 delete m_transitions.table;
173
174 if (m_propertyTable) {
175 unsigned entryCount = m_propertyTable->keyCount + m_propertyTable->deletedSentinelCount;
176 for (unsigned i = 1; i <= entryCount; i++) {
177 if (UString::Rep* key = m_propertyTable->entries()[i].key)
178 key->deref();
179 }
180 fastFree(m_propertyTable);
181 }
182
183#ifndef NDEBUG
184#if ENABLE(JSC_MULTIPLE_THREADS)
185 MutexLocker protect(ignoreSetMutex);
186#endif
187 HashSet<Structure*>::iterator it = ignoreSet.find(this);
188 if (it != ignoreSet.end())
189 ignoreSet.remove(it);
190 else
191 structureCounter.decrement();
192#endif
193
194#if DUMP_STRUCTURE_ID_STATISTICS
195 liveStructureSet.remove(this);
196#endif
197}
198
199void Structure::startIgnoringLeaks()
200{
201#ifndef NDEBUG
202 shouldIgnoreLeaks = true;
203#endif
204}
205
206void Structure::stopIgnoringLeaks()
207{
208#ifndef NDEBUG
209 shouldIgnoreLeaks = false;
210#endif
211}
212
213static bool isPowerOf2(unsigned v)
214{
215 // Taken from http://www.cs.utk.edu/~vose/c-stuff/bithacks.html
216
217 return !(v & (v - 1)) && v;
218}
219
220static unsigned nextPowerOf2(unsigned v)
221{
222 // Taken from http://www.cs.utk.edu/~vose/c-stuff/bithacks.html
223 // Devised by Sean Anderson, Sepember 14, 2001
224
225 v--;
226 v |= v >> 1;
227 v |= v >> 2;
228 v |= v >> 4;
229 v |= v >> 8;
230 v |= v >> 16;
231 v++;
232
233 return v;
234}
235
236static unsigned sizeForKeyCount(size_t keyCount)
237{
238 if (keyCount == WTF::notFound)
239 return newTableSize;
240
241 if (keyCount < 8)
242 return newTableSize;
243
244 if (isPowerOf2(keyCount))
245 return keyCount * 4;
246
247 return nextPowerOf2(keyCount) * 2;
248}
249
250void Structure::materializePropertyMap()
251{
252 ASSERT(!m_propertyTable);
253
254 Vector<Structure*, 8> structures;
255 structures.append(this);
256
257 Structure* structure = this;
258
259 // Search for the last Structure with a property table.
260 while ((structure = structure->previousID())) {
261 if (structure->m_isPinnedPropertyTable) {
262 ASSERT(structure->m_propertyTable);
263 ASSERT(!structure->m_previous);
264
265 m_propertyTable = structure->copyPropertyTable();
266 break;
267 }
268
269 structures.append(structure);
270 }
271
272 if (!m_propertyTable)
273 createPropertyMapHashTable(sizeForKeyCount(m_offset + 1));
274 else {
275 if (sizeForKeyCount(m_offset + 1) > m_propertyTable->size)
276 rehashPropertyMapHashTable(sizeForKeyCount(m_offset + 1)); // This could be made more efficient by combining with the copy above.
277 }
278
279 for (ptrdiff_t i = structures.size() - 2; i >= 0; --i) {
280 structure = structures[i];
281 structure->m_nameInPrevious->ref();
282 PropertyMapEntry entry(structure->m_nameInPrevious, structure->m_offset, structure->m_attributesInPrevious, ++m_propertyTable->lastIndexUsed);
283 insertIntoPropertyMapHashTable(entry);
284 }
285}
286
287void Structure::getEnumerablePropertyNames(ExecState* exec, PropertyNameArray& propertyNames, JSObject* baseObject)
288{
289 bool shouldCache = propertyNames.cacheable() && !(propertyNames.size() || m_isDictionary);
290
291 if (shouldCache) {
292 if (m_cachedPropertyNameArrayData) {
293 if (structureChainsAreEqual(m_cachedPropertyNameArrayData->cachedPrototypeChain(), cachedPrototypeChain())) {
294 propertyNames.setData(m_cachedPropertyNameArrayData);
295 return;
296 }
297 }
298 propertyNames.setCacheable(false);
299 }
300
301 getEnumerablePropertyNamesInternal(propertyNames);
302
303 // Add properties from the static hashtables of properties
304 for (const ClassInfo* info = baseObject->classInfo(); info; info = info->parentClass) {
305 const HashTable* table = info->propHashTable(exec);
306 if (!table)
307 continue;
308 table->initializeIfNeeded(exec);
309 ASSERT(table->table);
310 int hashSizeMask = table->hashSizeMask;
311 const HashEntry* entry = table->table;
312 for (int i = 0; i <= hashSizeMask; ++i, ++entry) {
313 if (entry->key() && !(entry->attributes() & DontEnum))
314 propertyNames.add(entry->key());
315 }
316 }
317
318 if (m_prototype->isObject())
319 asObject(m_prototype)->getPropertyNames(exec, propertyNames);
320
321 if (shouldCache) {
322 if (m_cachedPropertyNameArrayData)
323 m_cachedPropertyNameArrayData->setCachedStructure(0);
324
325 m_cachedPropertyNameArrayData = propertyNames.data();
326
327 StructureChain* chain = cachedPrototypeChain();
328 if (!chain)
329 chain = createCachedPrototypeChain();
330 m_cachedPropertyNameArrayData->setCachedPrototypeChain(chain);
331 m_cachedPropertyNameArrayData->setCachedStructure(this);
332 }
333}
334
335void Structure::clearEnumerationCache()
336{
337 if (m_cachedPropertyNameArrayData)
338 m_cachedPropertyNameArrayData->setCachedStructure(0);
339 m_cachedPropertyNameArrayData.clear();
340}
341
342void Structure::growPropertyStorageCapacity()
343{
344 if (m_propertyStorageCapacity == JSObject::inlineStorageCapacity)
345 m_propertyStorageCapacity = JSObject::nonInlineBaseStorageCapacity;
346 else
347 m_propertyStorageCapacity *= 2;
348}
349
350PassRefPtr<Structure> Structure::addPropertyTransitionToExistingStructure(Structure* structure, const Identifier& propertyName, unsigned attributes, size_t& offset)
351{
352 ASSERT(!structure->m_isDictionary);
353 ASSERT(structure->typeInfo().type() == ObjectType);
354
355 if (structure->m_usingSingleTransitionSlot) {
356 Structure* existingTransition = structure->m_transitions.singleTransition;
357 if (existingTransition && existingTransition->m_nameInPrevious == propertyName.ustring().rep() && existingTransition->m_attributesInPrevious == attributes) {
358 offset = structure->m_transitions.singleTransition->m_offset;
359 ASSERT(offset != WTF::notFound);
360 return existingTransition;
361 }
362 } else {
363 if (Structure* existingTransition = structure->m_transitions.table->get(make_pair(propertyName.ustring().rep(), attributes))) {
364 offset = existingTransition->m_offset;
365 ASSERT(offset != WTF::notFound);
366 return existingTransition;
367 }
368 }
369
370 return 0;
371}
372
373PassRefPtr<Structure> Structure::addPropertyTransition(Structure* structure, const Identifier& propertyName, unsigned attributes, size_t& offset)
374{
375 ASSERT(!structure->m_isDictionary);
376 ASSERT(structure->typeInfo().type() == ObjectType);
377 ASSERT(structure->m_deletedOffsets.isEmpty());
378 ASSERT(!Structure::addPropertyTransitionToExistingStructure(structure, propertyName, attributes, offset));
379
380 if (structure->m_transitionCount > s_maxTransitionLength) {
381 RefPtr<Structure> transition = toDictionaryTransition(structure);
382 offset = transition->put(propertyName, attributes);
383 if (transition->propertyStorageSize() > transition->propertyStorageCapacity())
384 transition->growPropertyStorageCapacity();
385 return transition.release();
386 }
387
388 RefPtr<Structure> transition = create(structure->m_prototype, structure->typeInfo());
389 transition->m_cachedPrototypeChain = structure->m_cachedPrototypeChain;
390 transition->m_previous = structure;
391 transition->m_nameInPrevious = propertyName.ustring().rep();
392 transition->m_attributesInPrevious = attributes;
393 transition->m_transitionCount = structure->m_transitionCount + 1;
394 transition->m_propertyStorageCapacity = structure->m_propertyStorageCapacity;
395 transition->m_hasGetterSetterProperties = structure->m_hasGetterSetterProperties;
396
397 if (structure->m_propertyTable) {
398 if (structure->m_isPinnedPropertyTable)
399 transition->m_propertyTable = structure->copyPropertyTable();
400 else {
401 transition->m_propertyTable = structure->m_propertyTable;
402 structure->m_propertyTable = 0;
403 }
404 } else {
405 if (structure->m_previous)
406 transition->materializePropertyMap();
407 else
408 transition->createPropertyMapHashTable();
409 }
410
411 offset = transition->put(propertyName, attributes);
412 if (transition->propertyStorageSize() > transition->propertyStorageCapacity())
413 transition->growPropertyStorageCapacity();
414
415 transition->m_offset = offset;
416
417 if (structure->m_usingSingleTransitionSlot) {
418 if (!structure->m_transitions.singleTransition) {
419 structure->m_transitions.singleTransition = transition.get();
420 return transition.release();
421 }
422
423 Structure* existingTransition = structure->m_transitions.singleTransition;
424 structure->m_usingSingleTransitionSlot = false;
425 StructureTransitionTable* transitionTable = new StructureTransitionTable;
426 structure->m_transitions.table = transitionTable;
427 transitionTable->add(make_pair(existingTransition->m_nameInPrevious, existingTransition->m_attributesInPrevious), existingTransition);
428 }
429 structure->m_transitions.table->add(make_pair(propertyName.ustring().rep(), attributes), transition.get());
430 return transition.release();
431}
432
433PassRefPtr<Structure> Structure::removePropertyTransition(Structure* structure, const Identifier& propertyName, size_t& offset)
434{
435 ASSERT(!structure->m_isDictionary);
436
437 RefPtr<Structure> transition = toDictionaryTransition(structure);
438
439 offset = transition->remove(propertyName);
440
441 return transition.release();
442}
443
444PassRefPtr<Structure> Structure::changePrototypeTransition(Structure* structure, JSValue* prototype)
445{
446 RefPtr<Structure> transition = create(prototype, structure->typeInfo());
447
448 transition->m_transitionCount = structure->m_transitionCount + 1;
449 transition->m_deletedOffsets = structure->m_deletedOffsets;
450 transition->m_propertyStorageCapacity = structure->m_propertyStorageCapacity;
451 transition->m_hasGetterSetterProperties = structure->m_hasGetterSetterProperties;
452
453 // Don't set m_offset, as one can not transition to this.
454
455 structure->materializePropertyMapIfNecessary();
456 transition->m_propertyTable = structure->copyPropertyTable();
457 transition->m_isPinnedPropertyTable = true;
458
459 return transition.release();
460}
461
462PassRefPtr<Structure> Structure::getterSetterTransition(Structure* structure)
463{
464 RefPtr<Structure> transition = create(structure->storedPrototype(), structure->typeInfo());
465 transition->m_transitionCount = structure->m_transitionCount + 1;
466 transition->m_deletedOffsets = structure->m_deletedOffsets;
467 transition->m_propertyStorageCapacity = structure->m_propertyStorageCapacity;
468 transition->m_hasGetterSetterProperties = transition->m_hasGetterSetterProperties;
469
470 // Don't set m_offset, as one can not transition to this.
471
472 structure->materializePropertyMapIfNecessary();
473 transition->m_propertyTable = structure->copyPropertyTable();
474 transition->m_isPinnedPropertyTable = true;
475
476 return transition.release();
477}
478
479PassRefPtr<Structure> Structure::toDictionaryTransition(Structure* structure)
480{
481 ASSERT(!structure->m_isDictionary);
482
483 RefPtr<Structure> transition = create(structure->m_prototype, structure->typeInfo());
484 transition->m_isDictionary = true;
485 transition->m_deletedOffsets = structure->m_deletedOffsets;
486 transition->m_propertyStorageCapacity = structure->m_propertyStorageCapacity;
487 transition->m_hasGetterSetterProperties = structure->m_hasGetterSetterProperties;
488
489 structure->materializePropertyMapIfNecessary();
490 transition->m_propertyTable = structure->copyPropertyTable();
491 transition->m_isPinnedPropertyTable = true;
492
493 return transition.release();
494}
495
496PassRefPtr<Structure> Structure::fromDictionaryTransition(Structure* structure)
497{
498 ASSERT(structure->m_isDictionary);
499
500 // Since dictionary Structures are not shared, and no opcodes specialize
501 // for them, we don't need to allocate a new Structure when transitioning
502 // to non-dictionary status.
503
504 // FIMXE: We can make this more efficient by canonicalizing the Structure (draining the
505 // deleted offsets vector) before transitioning from dictionary.
506 if (structure->m_deletedOffsets.isEmpty())
507 structure->m_isDictionary = false;
508
509 return structure;
510}
511
512size_t Structure::addPropertyWithoutTransition(const Identifier& propertyName, unsigned attributes)
513{
514 ASSERT(!m_transitions.singleTransition);
515
516 materializePropertyMapIfNecessary();
517
518 m_isPinnedPropertyTable = true;
519 size_t offset = put(propertyName, attributes);
520 if (propertyStorageSize() > propertyStorageCapacity())
521 growPropertyStorageCapacity();
522 clearEnumerationCache();
523 return offset;
524}
525
526size_t Structure::removePropertyWithoutTransition(const Identifier& propertyName)
527{
528 ASSERT(!m_transitions.singleTransition);
529 ASSERT(m_isDictionary);
530
531 materializePropertyMapIfNecessary();
532
533 m_isPinnedPropertyTable = true;
534 size_t offset = remove(propertyName);
535 clearEnumerationCache();
536 return offset;
537}
538
539StructureChain* Structure::createCachedPrototypeChain()
540{
541 ASSERT(typeInfo().type() == ObjectType);
542 ASSERT(!m_cachedPrototypeChain);
543
544 JSValue* prototype = storedPrototype();
545 if (JSImmediate::isImmediate(prototype))
546 return 0;
547
548 RefPtr<StructureChain> chain = StructureChain::create(asObject(prototype)->structure());
549 setCachedPrototypeChain(chain.release());
550 return cachedPrototypeChain();
551}
552
553#if DUMP_PROPERTYMAP_STATS
554
555static int numProbes;
556static int numCollisions;
557static int numRehashes;
558static int numRemoves;
559
560struct PropertyMapStatisticsExitLogger {
561 ~PropertyMapStatisticsExitLogger();
562};
563
564static PropertyMapStatisticsExitLogger logger;
565
566PropertyMapStatisticsExitLogger::~PropertyMapStatisticsExitLogger()
567{
568 printf("\nJSC::PropertyMap statistics\n\n");
569 printf("%d probes\n", numProbes);
570 printf("%d collisions (%.1f%%)\n", numCollisions, 100.0 * numCollisions / numProbes);
571 printf("%d rehashes\n", numRehashes);
572 printf("%d removes\n", numRemoves);
573}
574
575#endif
576
577static const unsigned deletedSentinelIndex = 1;
578
579#if !DO_PROPERTYMAP_CONSTENCY_CHECK
580
581inline void Structure::checkConsistency()
582{
583}
584
585#endif
586
587PropertyMapHashTable* Structure::copyPropertyTable()
588{
589 if (!m_propertyTable)
590 return 0;
591
592 size_t tableSize = PropertyMapHashTable::allocationSize(m_propertyTable->size);
593 PropertyMapHashTable* newTable = static_cast<PropertyMapHashTable*>(fastMalloc(tableSize));
594 memcpy(newTable, m_propertyTable, tableSize);
595
596 unsigned entryCount = m_propertyTable->keyCount + m_propertyTable->deletedSentinelCount;
597 for (unsigned i = 1; i <= entryCount; ++i) {
598 if (UString::Rep* key = newTable->entries()[i].key)
599 key->ref();
600 }
601
602 return newTable;
603}
604
605size_t Structure::get(const Identifier& propertyName, unsigned& attributes)
606{
607 ASSERT(!propertyName.isNull());
608
609 materializePropertyMapIfNecessary();
610 if (!m_propertyTable)
611 return WTF::notFound;
612
613 UString::Rep* rep = propertyName._ustring.rep();
614
615 unsigned i = rep->computedHash();
616
617#if DUMP_PROPERTYMAP_STATS
618 ++numProbes;
619#endif
620
621 unsigned entryIndex = m_propertyTable->entryIndices[i & m_propertyTable->sizeMask];
622 if (entryIndex == emptyEntryIndex)
623 return WTF::notFound;
624
625 if (rep == m_propertyTable->entries()[entryIndex - 1].key) {
626 attributes = m_propertyTable->entries()[entryIndex - 1].attributes;
627 return m_propertyTable->entries()[entryIndex - 1].offset;
628 }
629
630#if DUMP_PROPERTYMAP_STATS
631 ++numCollisions;
632#endif
633
634 unsigned k = 1 | doubleHash(rep->computedHash());
635
636 while (1) {
637 i += k;
638
639#if DUMP_PROPERTYMAP_STATS
640 ++numRehashes;
641#endif
642
643 entryIndex = m_propertyTable->entryIndices[i & m_propertyTable->sizeMask];
644 if (entryIndex == emptyEntryIndex)
645 return WTF::notFound;
646
647 if (rep == m_propertyTable->entries()[entryIndex - 1].key) {
648 attributes = m_propertyTable->entries()[entryIndex - 1].attributes;
649 return m_propertyTable->entries()[entryIndex - 1].offset;
650 }
651 }
652}
653
654size_t Structure::put(const Identifier& propertyName, unsigned attributes)
655{
656 ASSERT(!propertyName.isNull());
657 ASSERT(get(propertyName) == WTF::notFound);
658
659 checkConsistency();
660
661 UString::Rep* rep = propertyName._ustring.rep();
662
663 if (!m_propertyTable)
664 createPropertyMapHashTable();
665
666 // FIXME: Consider a fast case for tables with no deleted sentinels.
667
668 unsigned i = rep->computedHash();
669 unsigned k = 0;
670 bool foundDeletedElement = false;
671 unsigned deletedElementIndex = 0; // initialize to make the compiler happy
672
673#if DUMP_PROPERTYMAP_STATS
674 ++numProbes;
675#endif
676
677 while (1) {
678 unsigned entryIndex = m_propertyTable->entryIndices[i & m_propertyTable->sizeMask];
679 if (entryIndex == emptyEntryIndex)
680 break;
681
682 if (entryIndex == deletedSentinelIndex) {
683 // If we find a deleted-element sentinel, remember it for use later.
684 if (!foundDeletedElement) {
685 foundDeletedElement = true;
686 deletedElementIndex = i;
687 }
688 }
689
690 if (k == 0) {
691 k = 1 | doubleHash(rep->computedHash());
692#if DUMP_PROPERTYMAP_STATS
693 ++numCollisions;
694#endif
695 }
696
697 i += k;
698
699#if DUMP_PROPERTYMAP_STATS
700 ++numRehashes;
701#endif
702 }
703
704 // Figure out which entry to use.
705 unsigned entryIndex = m_propertyTable->keyCount + m_propertyTable->deletedSentinelCount + 2;
706 if (foundDeletedElement) {
707 i = deletedElementIndex;
708 --m_propertyTable->deletedSentinelCount;
709
710 // Since we're not making the table bigger, we can't use the entry one past
711 // the end that we were planning on using, so search backwards for the empty
712 // slot that we can use. We know it will be there because we did at least one
713 // deletion in the past that left an entry empty.
714 while (m_propertyTable->entries()[--entryIndex - 1].key) { }
715 }
716
717 // Create a new hash table entry.
718 m_propertyTable->entryIndices[i & m_propertyTable->sizeMask] = entryIndex;
719
720 // Create a new hash table entry.
721 rep->ref();
722 m_propertyTable->entries()[entryIndex - 1].key = rep;
723 m_propertyTable->entries()[entryIndex - 1].attributes = attributes;
724 m_propertyTable->entries()[entryIndex - 1].index = ++m_propertyTable->lastIndexUsed;
725
726 unsigned newOffset;
727 if (!m_deletedOffsets.isEmpty()) {
728 newOffset = m_deletedOffsets.last();
729 m_deletedOffsets.removeLast();
730 } else
731 newOffset = m_propertyTable->keyCount;
732 m_propertyTable->entries()[entryIndex - 1].offset = newOffset;
733
734 ++m_propertyTable->keyCount;
735
736 if ((m_propertyTable->keyCount + m_propertyTable->deletedSentinelCount) * 2 >= m_propertyTable->size)
737 expandPropertyMapHashTable();
738
739 checkConsistency();
740 return newOffset;
741}
742
743size_t Structure::remove(const Identifier& propertyName)
744{
745 ASSERT(!propertyName.isNull());
746
747 checkConsistency();
748
749 UString::Rep* rep = propertyName._ustring.rep();
750
751 if (!m_propertyTable)
752 return WTF::notFound;
753
754#if DUMP_PROPERTYMAP_STATS
755 ++numProbes;
756 ++numRemoves;
757#endif
758
759 // Find the thing to remove.
760 unsigned i = rep->computedHash();
761 unsigned k = 0;
762 unsigned entryIndex;
763 UString::Rep* key = 0;
764 while (1) {
765 entryIndex = m_propertyTable->entryIndices[i & m_propertyTable->sizeMask];
766 if (entryIndex == emptyEntryIndex)
767 return WTF::notFound;
768
769 key = m_propertyTable->entries()[entryIndex - 1].key;
770 if (rep == key)
771 break;
772
773 if (k == 0) {
774 k = 1 | doubleHash(rep->computedHash());
775#if DUMP_PROPERTYMAP_STATS
776 ++numCollisions;
777#endif
778 }
779
780 i += k;
781
782#if DUMP_PROPERTYMAP_STATS
783 ++numRehashes;
784#endif
785 }
786
787 // Replace this one element with the deleted sentinel. Also clear out
788 // the entry so we can iterate all the entries as needed.
789 m_propertyTable->entryIndices[i & m_propertyTable->sizeMask] = deletedSentinelIndex;
790
791 size_t offset = m_propertyTable->entries()[entryIndex - 1].offset;
792
793 key->deref();
794 m_propertyTable->entries()[entryIndex - 1].key = 0;
795 m_propertyTable->entries()[entryIndex - 1].attributes = 0;
796 m_propertyTable->entries()[entryIndex - 1].offset = 0;
797 m_deletedOffsets.append(offset);
798
799 ASSERT(m_propertyTable->keyCount >= 1);
800 --m_propertyTable->keyCount;
801 ++m_propertyTable->deletedSentinelCount;
802
803 if (m_propertyTable->deletedSentinelCount * 4 >= m_propertyTable->size)
804 rehashPropertyMapHashTable();
805
806 checkConsistency();
807 return offset;
808}
809
810void Structure::insertIntoPropertyMapHashTable(const PropertyMapEntry& entry)
811{
812 ASSERT(m_propertyTable);
813
814 unsigned i = entry.key->computedHash();
815 unsigned k = 0;
816
817#if DUMP_PROPERTYMAP_STATS
818 ++numProbes;
819#endif
820
821 while (1) {
822 unsigned entryIndex = m_propertyTable->entryIndices[i & m_propertyTable->sizeMask];
823 if (entryIndex == emptyEntryIndex)
824 break;
825
826 if (k == 0) {
827 k = 1 | doubleHash(entry.key->computedHash());
828#if DUMP_PROPERTYMAP_STATS
829 ++numCollisions;
830#endif
831 }
832
833 i += k;
834
835#if DUMP_PROPERTYMAP_STATS
836 ++numRehashes;
837#endif
838 }
839
840 unsigned entryIndex = m_propertyTable->keyCount + 2;
841 m_propertyTable->entryIndices[i & m_propertyTable->sizeMask] = entryIndex;
842 m_propertyTable->entries()[entryIndex - 1] = entry;
843
844 ++m_propertyTable->keyCount;
845}
846
847void Structure::createPropertyMapHashTable()
848{
849 ASSERT(sizeForKeyCount(7) == newTableSize);
850 createPropertyMapHashTable(newTableSize);
851}
852
853void Structure::createPropertyMapHashTable(unsigned newTableSize)
854{
855 ASSERT(!m_propertyTable);
856 ASSERT(isPowerOf2(newTableSize));
857
858 checkConsistency();
859
860 m_propertyTable = static_cast<PropertyMapHashTable*>(fastZeroedMalloc(PropertyMapHashTable::allocationSize(newTableSize)));
861 m_propertyTable->size = newTableSize;
862 m_propertyTable->sizeMask = newTableSize - 1;
863
864 checkConsistency();
865}
866
867void Structure::expandPropertyMapHashTable()
868{
869 ASSERT(m_propertyTable);
870 rehashPropertyMapHashTable(m_propertyTable->size * 2);
871}
872
873void Structure::rehashPropertyMapHashTable()
874{
875 ASSERT(m_propertyTable);
876 ASSERT(m_propertyTable->size);
877 rehashPropertyMapHashTable(m_propertyTable->size);
878}
879
880void Structure::rehashPropertyMapHashTable(unsigned newTableSize)
881{
882 ASSERT(m_propertyTable);
883 ASSERT(isPowerOf2(newTableSize));
884
885 checkConsistency();
886
887 PropertyMapHashTable* oldTable = m_propertyTable;
888
889 m_propertyTable = static_cast<PropertyMapHashTable*>(fastZeroedMalloc(PropertyMapHashTable::allocationSize(newTableSize)));
890 m_propertyTable->size = newTableSize;
891 m_propertyTable->sizeMask = newTableSize - 1;
892
893 unsigned lastIndexUsed = 0;
894 unsigned entryCount = oldTable->keyCount + oldTable->deletedSentinelCount;
895 for (unsigned i = 1; i <= entryCount; ++i) {
896 if (oldTable->entries()[i].key) {
897 lastIndexUsed = max(oldTable->entries()[i].index, lastIndexUsed);
898 insertIntoPropertyMapHashTable(oldTable->entries()[i]);
899 }
900 }
901 m_propertyTable->lastIndexUsed = lastIndexUsed;
902
903 fastFree(oldTable);
904
905 checkConsistency();
906}
907
908static int comparePropertyMapEntryIndices(const void* a, const void* b)
909{
910 unsigned ia = static_cast<PropertyMapEntry* const*>(a)[0]->index;
911 unsigned ib = static_cast<PropertyMapEntry* const*>(b)[0]->index;
912 if (ia < ib)
913 return -1;
914 if (ia > ib)
915 return +1;
916 return 0;
917}
918
919void Structure::getEnumerablePropertyNamesInternal(PropertyNameArray& propertyNames)
920{
921 materializePropertyMapIfNecessary();
922 if (!m_propertyTable)
923 return;
924
925 if (m_propertyTable->keyCount < tinyMapThreshold) {
926 PropertyMapEntry* a[tinyMapThreshold];
927 int i = 0;
928 unsigned entryCount = m_propertyTable->keyCount + m_propertyTable->deletedSentinelCount;
929 for (unsigned k = 1; k <= entryCount; k++) {
930 if (m_propertyTable->entries()[k].key && !(m_propertyTable->entries()[k].attributes & DontEnum)) {
931 PropertyMapEntry* value = &m_propertyTable->entries()[k];
932 int j;
933 for (j = i - 1; j >= 0 && a[j]->index > value->index; --j)
934 a[j + 1] = a[j];
935 a[j + 1] = value;
936 ++i;
937 }
938 }
939 if (!propertyNames.size()) {
940 for (int k = 0; k < i; ++k)
941 propertyNames.addKnownUnique(a[k]->key);
942 } else {
943 for (int k = 0; k < i; ++k)
944 propertyNames.add(a[k]->key);
945 }
946
947 return;
948 }
949
950 // Allocate a buffer to use to sort the keys.
951 Vector<PropertyMapEntry*, smallMapThreshold> sortedEnumerables(m_propertyTable->keyCount);
952
953 // Get pointers to the enumerable entries in the buffer.
954 PropertyMapEntry** p = sortedEnumerables.data();
955 unsigned entryCount = m_propertyTable->keyCount + m_propertyTable->deletedSentinelCount;
956 for (unsigned i = 1; i <= entryCount; i++) {
957 if (m_propertyTable->entries()[i].key && !(m_propertyTable->entries()[i].attributes & DontEnum))
958 *p++ = &m_propertyTable->entries()[i];
959 }
960
961 size_t enumerableCount = p - sortedEnumerables.data();
962 // Sort the entries by index.
963 qsort(sortedEnumerables.data(), enumerableCount, sizeof(PropertyMapEntry*), comparePropertyMapEntryIndices);
964 sortedEnumerables.resize(enumerableCount);
965
966 // Put the keys of the sorted entries into the list.
967 if (!propertyNames.size()) {
968 for (size_t i = 0; i < sortedEnumerables.size(); ++i)
969 propertyNames.addKnownUnique(sortedEnumerables[i]->key);
970 } else {
971 for (size_t i = 0; i < sortedEnumerables.size(); ++i)
972 propertyNames.add(sortedEnumerables[i]->key);
973 }
974}
975
976#if DO_PROPERTYMAP_CONSTENCY_CHECK
977
978void Structure::checkConsistency()
979{
980 if (!m_propertyTable)
981 return;
982
983 ASSERT(m_propertyTable->size >= newTableSize);
984 ASSERT(m_propertyTable->sizeMask);
985 ASSERT(m_propertyTable->size == m_propertyTable->sizeMask + 1);
986 ASSERT(!(m_propertyTable->size & m_propertyTable->sizeMask));
987
988 ASSERT(m_propertyTable->keyCount <= m_propertyTable->size / 2);
989 ASSERT(m_propertyTable->deletedSentinelCount <= m_propertyTable->size / 4);
990
991 ASSERT(m_propertyTable->keyCount + m_propertyTable->deletedSentinelCount <= m_propertyTable->size / 2);
992
993 unsigned indexCount = 0;
994 unsigned deletedIndexCount = 0;
995 for (unsigned a = 0; a != m_propertyTable->size; ++a) {
996 unsigned entryIndex = m_propertyTable->entryIndices[a];
997 if (entryIndex == emptyEntryIndex)
998 continue;
999 if (entryIndex == deletedSentinelIndex) {
1000 ++deletedIndexCount;
1001 continue;
1002 }
1003 ASSERT(entryIndex > deletedSentinelIndex);
1004 ASSERT(entryIndex - 1 <= m_propertyTable->keyCount + m_propertyTable->deletedSentinelCount);
1005 ++indexCount;
1006
1007 for (unsigned b = a + 1; b != m_propertyTable->size; ++b)
1008 ASSERT(m_propertyTable->entryIndices[b] != entryIndex);
1009 }
1010 ASSERT(indexCount == m_propertyTable->keyCount);
1011 ASSERT(deletedIndexCount == m_propertyTable->deletedSentinelCount);
1012
1013 ASSERT(m_propertyTable->entries()[0].key == 0);
1014
1015 unsigned nonEmptyEntryCount = 0;
1016 for (unsigned c = 1; c <= m_propertyTable->keyCount + m_propertyTable->deletedSentinelCount; ++c) {
1017 UString::Rep* rep = m_propertyTable->entries()[c].key;
1018 if (!rep)
1019 continue;
1020 ++nonEmptyEntryCount;
1021 unsigned i = rep->computedHash();
1022 unsigned k = 0;
1023 unsigned entryIndex;
1024 while (1) {
1025 entryIndex = m_propertyTable->entryIndices[i & m_propertyTable->sizeMask];
1026 ASSERT(entryIndex != emptyEntryIndex);
1027 if (rep == m_propertyTable->entries()[entryIndex - 1].key)
1028 break;
1029 if (k == 0)
1030 k = 1 | doubleHash(rep->computedHash());
1031 i += k;
1032 }
1033 ASSERT(entryIndex == c + 1);
1034 }
1035
1036 ASSERT(nonEmptyEntryCount == m_propertyTable->keyCount);
1037}
1038
1039#endif // DO_PROPERTYMAP_CONSTENCY_CHECK
1040
1041} // namespace JSC
Note: See TracBrowser for help on using the repository browser.