Title: [140259] trunk/Source/_javascript_Core
Revision
140259
Author
[email protected]
Date
2013-01-19 13:47:45 -0800 (Sat, 19 Jan 2013)

Log Message

Track inheritance structures in a side table, instead of using a private
name in each prototype
https://bugs.webkit.org/show_bug.cgi?id=107378

Reviewed by Sam Weinig and Phil Pizlo.

This is a step toward object size inference.

Using a side table frees us to use a more complex key (a pair of
prototype and expected inline capacity).

It also avoids ruining inline caches for prototypes. (Adding a new private
name for a new inline capacity would change the prototype's structure,
possibly firing watchpoints, making inline caches go polymorphic, and
generally causing us to have a bad time.)

* CMakeLists.txt:
* GNUmakefile.list.am:
* _javascript_Core.vcproj/_javascript_Core/_javascript_Core.vcproj:
* _javascript_Core.xcodeproj/project.pbxproj:
* Target.pri: Buildage.

* runtime/ArrayPrototype.cpp:
(JSC::ArrayPrototype::finishCreation): Updated to use new side table API.

* runtime/JSFunction.cpp:
(JSC::JSFunction::cacheInheritorID): Updated to use new side table API.

(JSC::JSFunction::visitChildren): Fixed a long-standing bug where JSFunction
forgot to visit one of its data members (m_cachedInheritorID). This
wasn't a user-visible problem before because JSFunction would always
visit its .prototype property, which visited its m_cachedInheritorID.
But now, function.prototype only weakly owns function.m_cachedInheritorID.

* runtime/JSGlobalData.h:
(JSGlobalData): Added the map, taking care to make sure that its
destructor would run after the heap destructor.

* runtime/JSGlobalObject.cpp:
(JSC::JSGlobalObject::reset): Updated to use new side table API.

* runtime/JSObject.cpp:
(JSC::JSObject::notifyPresenceOfIndexedAccessors):
(JSC::JSObject::setPrototype):
* runtime/JSObject.h:
(JSObject): Updated to use new side table API, and removed lots of code
that used to manage the per-object private name.

* runtime/JSProxy.cpp:
(JSC::JSProxy::setTarget):
* runtime/ObjectConstructor.cpp:
(JSC::objectConstructorCreate):
* runtime/ObjectPrototype.cpp:
(JSC::ObjectPrototype::finishCreation): Updated to use new side table API.

* runtime/PrototypeMap.cpp: Added.
(JSC):
(JSC::PrototypeMap::addPrototype):
(JSC::PrototypeMap::emptyObjectStructureForPrototype):
* runtime/PrototypeMap.h: Added.
(PrototypeMap):
(JSC::PrototypeMap::isPrototype):
(JSC::PrototypeMap::clearEmptyObjectStructureForPrototype): New side table.
This is a simple weak map, mapping an object to the structure you should
use when inheriting from that object. (In future, inline capacity will
be a part of the mapping.)

I used two maps to preserve existing behavior that allowed us to speculate
about an object becoming a prototype, even if it wasn't one at the moment.
However, I suspect that behavior can be removed without harm.

* runtime/WeakGCMap.h:
(JSC::WeakGCMap::contains):
(WeakGCMap): I would rate myself a 6 / 10 in C++.

Modified Paths

Added Paths

Diff

Modified: trunk/Source/_javascript_Core/CMakeLists.txt (140258 => 140259)


--- trunk/Source/_javascript_Core/CMakeLists.txt	2013-01-19 21:11:31 UTC (rev 140258)
+++ trunk/Source/_javascript_Core/CMakeLists.txt	2013-01-19 21:47:45 UTC (rev 140259)
@@ -269,6 +269,7 @@
     runtime/PropertyDescriptor.cpp
     runtime/PropertyNameArray.cpp
     runtime/PropertySlot.cpp
+    runtime/PrototypeMap.cpp
     runtime/RegExp.cpp
     runtime/RegExpCache.cpp
     runtime/RegExpConstructor.cpp

Modified: trunk/Source/_javascript_Core/ChangeLog (140258 => 140259)


--- trunk/Source/_javascript_Core/ChangeLog	2013-01-19 21:11:31 UTC (rev 140258)
+++ trunk/Source/_javascript_Core/ChangeLog	2013-01-19 21:47:45 UTC (rev 140259)
@@ -1,3 +1,80 @@
+2013-01-19  Geoffrey Garen  <[email protected]>
+
+        Track inheritance structures in a side table, instead of using a private
+        name in each prototype
+        https://bugs.webkit.org/show_bug.cgi?id=107378
+
+        Reviewed by Sam Weinig and Phil Pizlo.
+
+        This is a step toward object size inference.
+
+        Using a side table frees us to use a more complex key (a pair of
+        prototype and expected inline capacity).
+
+        It also avoids ruining inline caches for prototypes. (Adding a new private
+        name for a new inline capacity would change the prototype's structure,
+        possibly firing watchpoints, making inline caches go polymorphic, and
+        generally causing us to have a bad time.)
+
+        * CMakeLists.txt:
+        * GNUmakefile.list.am:
+        * _javascript_Core.vcproj/_javascript_Core/_javascript_Core.vcproj:
+        * _javascript_Core.xcodeproj/project.pbxproj:
+        * Target.pri: Buildage.
+
+        * runtime/ArrayPrototype.cpp:
+        (JSC::ArrayPrototype::finishCreation): Updated to use new side table API.
+
+        * runtime/JSFunction.cpp:
+        (JSC::JSFunction::cacheInheritorID): Updated to use new side table API.
+
+        (JSC::JSFunction::visitChildren): Fixed a long-standing bug where JSFunction
+        forgot to visit one of its data members (m_cachedInheritorID). This
+        wasn't a user-visible problem before because JSFunction would always
+        visit its .prototype property, which visited its m_cachedInheritorID.
+        But now, function.prototype only weakly owns function.m_cachedInheritorID.
+
+        * runtime/JSGlobalData.h:
+        (JSGlobalData): Added the map, taking care to make sure that its
+        destructor would run after the heap destructor.
+
+        * runtime/JSGlobalObject.cpp:
+        (JSC::JSGlobalObject::reset): Updated to use new side table API.
+
+        * runtime/JSObject.cpp:
+        (JSC::JSObject::notifyPresenceOfIndexedAccessors):
+        (JSC::JSObject::setPrototype):
+        * runtime/JSObject.h:
+        (JSObject): Updated to use new side table API, and removed lots of code
+        that used to manage the per-object private name.
+
+        * runtime/JSProxy.cpp:
+        (JSC::JSProxy::setTarget):
+        * runtime/ObjectConstructor.cpp:
+        (JSC::objectConstructorCreate):
+        * runtime/ObjectPrototype.cpp:
+        (JSC::ObjectPrototype::finishCreation): Updated to use new side table API.
+
+        * runtime/PrototypeMap.cpp: Added.
+        (JSC):
+        (JSC::PrototypeMap::addPrototype):
+        (JSC::PrototypeMap::emptyObjectStructureForPrototype):
+        * runtime/PrototypeMap.h: Added.
+        (PrototypeMap):
+        (JSC::PrototypeMap::isPrototype):
+        (JSC::PrototypeMap::clearEmptyObjectStructureForPrototype): New side table.
+        This is a simple weak map, mapping an object to the structure you should
+        use when inheriting from that object. (In future, inline capacity will
+        be a part of the mapping.)
+
+        I used two maps to preserve existing behavior that allowed us to speculate
+        about an object becoming a prototype, even if it wasn't one at the moment.
+        However, I suspect that behavior can be removed without harm.
+
+        * runtime/WeakGCMap.h:
+        (JSC::WeakGCMap::contains):
+        (WeakGCMap): I would rate myself a 6 / 10 in C++.
+
 2013-01-18  Dan Bernstein  <[email protected]>
 
         Removed duplicate references to two headers in the project files.

Modified: trunk/Source/_javascript_Core/GNUmakefile.list.am (140258 => 140259)


--- trunk/Source/_javascript_Core/GNUmakefile.list.am	2013-01-19 21:11:31 UTC (rev 140258)
+++ trunk/Source/_javascript_Core/GNUmakefile.list.am	2013-01-19 21:47:45 UTC (rev 140259)
@@ -695,6 +695,8 @@
 	Source/_javascript_Core/runtime/PropertyOffset.h \
 	Source/_javascript_Core/runtime/PropertySlot.cpp \
 	Source/_javascript_Core/runtime/PropertySlot.h \
+	Source/_javascript_Core/runtime/PrototypeMap.cpp \
+	Source/_javascript_Core/runtime/PrototypeMap.h \
 	Source/_javascript_Core/runtime/PropertyStorage.h \
 	Source/_javascript_Core/runtime/Protect.h \
 	Source/_javascript_Core/runtime/PutDirectIndexMode.h \

Modified: trunk/Source/_javascript_Core/_javascript_Core.vcproj/_javascript_Core/_javascript_Core.vcproj (140258 => 140259)


--- trunk/Source/_javascript_Core/_javascript_Core.vcproj/_javascript_Core/_javascript_Core.vcproj	2013-01-19 21:11:31 UTC (rev 140258)
+++ trunk/Source/_javascript_Core/_javascript_Core.vcproj/_javascript_Core/_javascript_Core.vcproj	2013-01-19 21:47:45 UTC (rev 140259)
@@ -1174,6 +1174,14 @@
 				>
 			</File>
 			<File
+				RelativePath="..\..\runtime\PrototypeMap.cpp"
+				>
+			</File>
+			<File
+				RelativePath="..\..\runtime\PrototypeMap.h"
+				>
+			</File>
+			<File
 				RelativePath="..\..\runtime\PropertyStorage.h"
 				>
 			</File>

Modified: trunk/Source/_javascript_Core/_javascript_Core.xcodeproj/project.pbxproj (140258 => 140259)


--- trunk/Source/_javascript_Core/_javascript_Core.xcodeproj/project.pbxproj	2013-01-19 21:11:31 UTC (rev 140258)
+++ trunk/Source/_javascript_Core/_javascript_Core.xcodeproj/project.pbxproj	2013-01-19 21:47:45 UTC (rev 140259)
@@ -398,6 +398,8 @@
 		146AAB380B66A94400E55F16 /* JSStringRefCF.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 146AAB370B66A94400E55F16 /* JSStringRefCF.cpp */; };
 		146B16D812EB5B59001BEC1B /* ConservativeRoots.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 146B14DB12EB5B12001BEC1B /* ConservativeRoots.cpp */; };
 		146FE51211A710430087AE66 /* JITCall32_64.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 146FE51111A710430087AE66 /* JITCall32_64.cpp */; };
+		1474C33B16AA2D950062F01D /* PrototypeMap.h in Headers */ = {isa = PBXBuildFile; fileRef = 14D844A316AA2C7000A65AF0 /* PrototypeMap.h */; settings = {ATTRIBUTES = (Private, ); }; };
+		1474C33C16AA2D9B0062F01D /* PrototypeMap.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 14D844A216AA2C7000A65AF0 /* PrototypeMap.cpp */; };
 		1478297B1379E8A800A7C2A3 /* HandleTypes.h in Headers */ = {isa = PBXBuildFile; fileRef = 146FA5A81378F6B0003627A3 /* HandleTypes.h */; settings = {ATTRIBUTES = (Private, ); }; };
 		147B83AC0E6DB8C9004775A4 /* BatchedTransitionOptimizer.h in Headers */ = {isa = PBXBuildFile; fileRef = 147B83AA0E6DB8C9004775A4 /* BatchedTransitionOptimizer.h */; };
 		147B84630E6DE6B1004775A4 /* PutPropertySlot.h in Headers */ = {isa = PBXBuildFile; fileRef = 147B84620E6DE6B1004775A4 /* PutPropertySlot.h */; settings = {ATTRIBUTES = (Private, ); }; };
@@ -1277,6 +1279,8 @@
 		14D2F3D8139F4BE200491031 /* MarkedSpace.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = MarkedSpace.cpp; sourceTree = "<group>"; };
 		14D2F3D9139F4BE200491031 /* MarkedSpace.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MarkedSpace.h; sourceTree = "<group>"; };
 		14D792640DAA03FB001A9F05 /* JSStack.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = JSStack.h; sourceTree = "<group>"; };
+		14D844A216AA2C7000A65AF0 /* PrototypeMap.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = PrototypeMap.cpp; sourceTree = "<group>"; };
+		14D844A316AA2C7000A65AF0 /* PrototypeMap.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = PrototypeMap.h; sourceTree = "<group>"; };
 		14D857740A4696C80032146C /* testapi.js */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode._javascript_; name = testapi.js; path = API/tests/testapi.js; sourceTree = "<group>"; };
 		14DA818E0D99FD2000B0A4FB /* JSActivation.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = JSActivation.h; sourceTree = "<group>"; };
 		14DA818F0D99FD2000B0A4FB /* JSActivation.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = JSActivation.cpp; sourceTree = "<group>"; };
@@ -2321,7 +2325,6 @@
 				F692A85C0255597D01FF60F7 /* FunctionPrototype.cpp */,
 				F692A85D0255597D01FF60F7 /* FunctionPrototype.h */,
 				C2D58C3315912FEE0021A844 /* GCActivityCallback.cpp */,
-				C2D58C3315912FEE0021A844 /* GCActivityCallback.cpp */,
 				DDF7ABD211F60ED200108E36 /* GCActivityCallback.h */,
 				BC02E9B80E184545000F9297 /* GetterSetter.cpp */,
 				BC337BDE0E1AF0B80076918A /* GetterSetter.h */,
@@ -2439,6 +2442,8 @@
 				65621E6C089E859700760F35 /* PropertySlot.h */,
 				0FB7F39015ED8E3800F167B2 /* PropertyStorage.h */,
 				65C02FBB0637462A003E7EE6 /* Protect.h */,
+				14D844A216AA2C7000A65AF0 /* PrototypeMap.cpp */,
+				14D844A316AA2C7000A65AF0 /* PrototypeMap.h */,
 				0F0CD4C015F1A6040032F1C0 /* PutDirectIndexMode.h */,
 				147B84620E6DE6B1004775A4 /* PutPropertySlot.h */,
 				F692A87D0255597D01FF60F7 /* RegExp.cpp */,
@@ -2490,6 +2495,7 @@
 				14BFCE6810CDB1FC00364CCE /* WeakGCMap.h */,
 				1420BE7A10AA6DDB00F455D2 /* WeakRandom.h */,
 				A7DCB77912E3D90500911940 /* WriteBarrier.h */,
+				C2D58C3315912FEE0021A844 /* GCActivityCallback.cpp */,
 			);
 			path = runtime;
 			sourceTree = "<group>";
@@ -3270,6 +3276,7 @@
 				86704B8A12DBA33700A9FE7B /* YarrPattern.h in Headers */,
 				86704B4312DB8A8100A9FE7B /* YarrSyntaxChecker.h in Headers */,
 				0F9749711687ADE400A4FF6A /* JSCellInlines.h in Headers */,
+				1474C33B16AA2D950062F01D /* PrototypeMap.h in Headers */,
 			);
 			runOnlyForDeploymentPostprocessing = 0;
 		};
@@ -3897,6 +3904,7 @@
 				86704B8612DBA33700A9FE7B /* YarrJIT.cpp in Sources */,
 				86704B8912DBA33700A9FE7B /* YarrPattern.cpp in Sources */,
 				86704B4212DB8A8100A9FE7B /* YarrSyntaxChecker.cpp in Sources */,
+				1474C33C16AA2D9B0062F01D /* PrototypeMap.cpp in Sources */,
 			);
 			runOnlyForDeploymentPostprocessing = 0;
 		};

Modified: trunk/Source/_javascript_Core/Target.pri (140258 => 140259)


--- trunk/Source/_javascript_Core/Target.pri	2013-01-19 21:11:31 UTC (rev 140258)
+++ trunk/Source/_javascript_Core/Target.pri	2013-01-19 21:47:45 UTC (rev 140259)
@@ -287,6 +287,7 @@
     runtime/PropertyDescriptor.cpp \
     runtime/PropertyNameArray.cpp \
     runtime/PropertySlot.cpp \
+    runtime/PrototypeMap.cpp \
     runtime/RegExpConstructor.cpp \
     runtime/RegExpCachedResult.cpp \
     runtime/RegExpMatchesArray.cpp \

Modified: trunk/Source/_javascript_Core/runtime/ArrayPrototype.cpp (140258 => 140259)


--- trunk/Source/_javascript_Core/runtime/ArrayPrototype.cpp	2013-01-19 21:11:31 UTC (rev 140258)
+++ trunk/Source/_javascript_Core/runtime/ArrayPrototype.cpp	2013-01-19 21:47:45 UTC (rev 140259)
@@ -132,7 +132,7 @@
     JSGlobalData& globalData = globalObject->globalData();
     Base::finishCreation(globalData);
     ASSERT(inherits(&s_info));
-    notifyUsedAsPrototype(globalData);
+    globalData.prototypeMap.addPrototype(this);
 }
 
 bool ArrayPrototype::getOwnPropertySlot(JSCell* cell, ExecState* exec, PropertyName propertyName, PropertySlot& slot)

Modified: trunk/Source/_javascript_Core/runtime/JSFunction.cpp (140258 => 140259)


--- trunk/Source/_javascript_Core/runtime/JSFunction.cpp	2013-01-19 21:11:31 UTC (rev 140258)
+++ trunk/Source/_javascript_Core/runtime/JSFunction.cpp	2013-01-19 21:47:45 UTC (rev 140259)
@@ -108,11 +108,12 @@
 
 Structure* JSFunction::cacheInheritorID(ExecState* exec)
 {
-    JSValue prototype = get(exec, exec->globalData().propertyNames->prototype);
+    JSGlobalData& globalData = exec->globalData();
+    JSValue prototype = get(exec, globalData.propertyNames->prototype);
     if (prototype.isObject())
-        m_cachedInheritorID.set(exec->globalData(), this, asObject(prototype)->inheritorID(exec->globalData()));
+        m_cachedInheritorID.set(globalData, this, globalData.prototypeMap.emptyObjectStructureForPrototype(asObject(prototype)));
     else
-        m_cachedInheritorID.set(exec->globalData(), this, globalObject()->emptyObjectStructure());
+        m_cachedInheritorID.set(globalData, this, globalData.prototypeMap.emptyObjectStructureForPrototype(globalObject()->objectPrototype()));
     return m_cachedInheritorID.get();
 }
 
@@ -162,6 +163,7 @@
 
     visitor.append(&thisObject->m_scope);
     visitor.append(&thisObject->m_executable);
+    visitor.append(&thisObject->m_cachedInheritorID);
 }
 
 CallType JSFunction::getCallData(JSCell* cell, CallData& callData)

Modified: trunk/Source/_javascript_Core/runtime/JSGlobalData.h (140258 => 140259)


--- trunk/Source/_javascript_Core/runtime/JSGlobalData.h	2013-01-19 21:11:31 UTC (rev 140258)
+++ trunk/Source/_javascript_Core/runtime/JSGlobalData.h	2013-01-19 21:47:45 UTC (rev 140259)
@@ -42,6 +42,7 @@
 #include "NumericStrings.h"
 #include "ProfilerDatabase.h"
 #include "PrivateName.h"
+#include "PrototypeMap.h"
 #include "SmallStrings.h"
 #include "Strong.h"
 #include "Terminator.h"
@@ -286,7 +287,7 @@
         bool canUseRegExpJIT() { return false; } // interpreter only
 #endif
 
-        PrivateName m_inheritorIDKey;
+        PrototypeMap prototypeMap;
 
         OwnPtr<ParserArena> parserArena;
         OwnPtr<Keywords> keywords;

Modified: trunk/Source/_javascript_Core/runtime/JSGlobalObject.cpp (140258 => 140259)


--- trunk/Source/_javascript_Core/runtime/JSGlobalObject.cpp	2013-01-19 21:11:31 UTC (rev 140258)
+++ trunk/Source/_javascript_Core/runtime/JSGlobalObject.cpp	2013-01-19 21:47:45 UTC (rev 140259)
@@ -223,8 +223,8 @@
     m_strictEvalActivationStructure.set(exec->globalData(), this, StrictEvalActivation::createStructure(exec->globalData(), this, jsNull()));
     m_withScopeStructure.set(exec->globalData(), this, JSWithScope::createStructure(exec->globalData(), this, jsNull()));
 
-    m_emptyObjectStructure.set(exec->globalData(), this, m_objectPrototype->inheritorID(exec->globalData()));
-    m_nullPrototypeObjectStructure.set(exec->globalData(), this, createEmptyObjectStructure(exec->globalData(), this, jsNull()));
+    m_emptyObjectStructure.set(exec->globalData(), this, globalData().prototypeMap.emptyObjectStructureForPrototype(m_objectPrototype.get()));
+    m_nullPrototypeObjectStructure.set(exec->globalData(), this, JSFinalObject::createStructure(globalData(), this, jsNull()));
 
     m_callbackFunctionStructure.set(exec->globalData(), this, JSCallbackFunction::createStructure(exec->globalData(), this, m_functionPrototype.get()));
     m_argumentsStructure.set(exec->globalData(), this, Arguments::createStructure(exec->globalData(), this, m_objectPrototype.get()));

Modified: trunk/Source/_javascript_Core/runtime/JSObject.cpp (140258 => 140259)


--- trunk/Source/_javascript_Core/runtime/JSObject.cpp	2013-01-19 21:11:31 UTC (rev 140258)
+++ trunk/Source/_javascript_Core/runtime/JSObject.cpp	2013-01-19 21:47:45 UTC (rev 140259)
@@ -596,7 +596,7 @@
     
     setStructure(globalData, Structure::nonPropertyTransition(globalData, structure(), AddIndexedAccessors));
     
-    if (!mayBeUsedAsPrototype(globalData))
+    if (!globalData.prototypeMap.isPrototype(this))
         return;
     
     globalObject()->haveABadTime(globalData);
@@ -1149,7 +1149,7 @@
 {
     ASSERT(prototype);
     if (prototype.isObject())
-        asObject(prototype)->notifyUsedAsPrototype(globalData);
+        globalData.prototypeMap.addPrototype(asObject(prototype));
     
     Structure* newStructure = Structure::changePrototypeTransition(globalData, structure(), prototype);
     setStructure(globalData, newStructure);
@@ -1157,7 +1157,7 @@
     if (!newStructure->anyObjectInChainMayInterceptIndexedAccesses())
         return;
     
-    if (mayBeUsedAsPrototype(globalData)) {
+    if (globalData.prototypeMap.isPrototype(this)) {
         newStructure->globalObject()->haveABadTime(globalData);
         return;
     }
@@ -1187,28 +1187,6 @@
     return true;
 }
 
-void JSObject::resetInheritorID(JSGlobalData& globalData)
-{
-    PropertyOffset offset = structure()->get(globalData, globalData.m_inheritorIDKey);
-    if (!isValidOffset(offset))
-        return;
-    
-    putDirect(globalData, offset, jsUndefined());
-}
-
-Structure* JSObject::inheritorID(JSGlobalData& globalData)
-{
-    if (JSValue value = getDirect(globalData, globalData.m_inheritorIDKey)) {
-        if (value.isCell()) {
-            Structure* inheritorID = jsCast<Structure*>(value);
-            ASSERT(inheritorID->isEmpty());
-            return inheritorID;
-        }
-        ASSERT(value.isUndefined());
-    }
-    return createInheritorID(globalData);
-}
-
 bool JSObject::allowsAccessFrom(ExecState* exec)
 {
     JSGlobalObject* globalObject = this->globalObject();
@@ -1663,42 +1641,6 @@
         slot.setUndefined();
 }
 
-void JSObject::notifyUsedAsPrototype(JSGlobalData& globalData)
-{
-    PropertyOffset offset = structure()->get(globalData, globalData.m_inheritorIDKey);
-    if (isValidOffset(offset))
-        return;
-    
-    PutPropertySlot slot;
-    putDirectInternal<PutModeDefineOwnProperty>(globalData, globalData.m_inheritorIDKey, jsUndefined(), DontEnum, slot, 0);
-    
-    // Note that this method makes the somewhat odd decision to not check if this
-    // object currently has indexed accessors. We could do that check here, and if
-    // indexed accessors were found, we could tell the global object to have a bad
-    // time. But we avoid this, to allow the following to be always fast:
-    //
-    // 1) Create an object.
-    // 2) Give it a setter or read-only property that happens to have a numeric name.
-    // 3) Allocate objects that use this object as a prototype.
-    //
-    // This avoids anyone having a bad time. Even if the instance objects end up
-    // having indexed storage, the creation of indexed storage leads to a prototype
-    // chain walk that detects the presence of indexed setters and then does the
-    // right thing. As a result, having a bad time only happens if you add an
-    // indexed setter (or getter, or read-only field) to an object that is already
-    // used as a prototype.
-}
-
-Structure* JSObject::createInheritorID(JSGlobalData& globalData)
-{
-    Structure* inheritorID = createEmptyObjectStructure(globalData, globalObject(), this);
-    ASSERT(inheritorID->isEmpty());
-
-    PutPropertySlot slot;
-    putDirectInternal<PutModeDefineOwnProperty>(globalData, globalData.m_inheritorIDKey, inheritorID, DontEnum, slot, 0);
-    return inheritorID;
-}
-
 void JSObject::putIndexedDescriptor(ExecState* exec, SparseArrayEntry* entryInMap, PropertyDescriptor& descriptor, PropertyDescriptor& oldDescriptor)
 {
     if (descriptor.isDataDescriptor()) {

Modified: trunk/Source/_javascript_Core/runtime/JSObject.h (140258 => 140259)


--- trunk/Source/_javascript_Core/runtime/JSObject.h	2013-01-19 21:11:31 UTC (rev 140258)
+++ trunk/Source/_javascript_Core/runtime/JSObject.h	2013-01-19 21:47:45 UTC (rev 140259)
@@ -124,14 +124,6 @@
     void setPrototype(JSGlobalData&, JSValue prototype);
     bool setPrototypeWithCycleCheck(JSGlobalData&, JSValue prototype);
         
-    Structure* inheritorID(JSGlobalData&);
-    void notifyUsedAsPrototype(JSGlobalData&);
-        
-    bool mayBeUsedAsPrototype(JSGlobalData& globalData)
-    {
-        return isValidOffset(structure()->get(globalData, globalData.m_inheritorIDKey));
-    }
-        
     bool mayInterceptIndexedAccesses()
     {
         return structure()->mayInterceptIndexedAccesses();
@@ -718,8 +710,6 @@
     // To create derived types you likely want JSNonFinalObject, below.
     JSObject(JSGlobalData&, Structure*, Butterfly* = 0);
         
-    void resetInheritorID(JSGlobalData&);
-        
     void visitButterfly(SlotVisitor&, Butterfly*, size_t storageSize);
     void copyButterfly(CopyVisitor&, Butterfly*, size_t storageSize);
 
@@ -934,7 +924,6 @@
     JS_EXPORT_PRIVATE void fillGetterPropertySlot(PropertySlot&, PropertyOffset);
 
     const HashEntry* findPropertyHashEntry(ExecState*, PropertyName) const;
-    Structure* createInheritorID(JSGlobalData&);
         
     void putIndexedDescriptor(ExecState*, SparseArrayEntry*, PropertyDescriptor&, PropertyDescriptor& old);
         
@@ -1125,11 +1114,6 @@
     return result;
 }
 
-inline Structure* createEmptyObjectStructure(JSGlobalData& globalData, JSGlobalObject* globalObject, JSValue prototype)
-{
-    return JSFinalObject::createStructure(globalData, globalObject, prototype);
-}
-
 inline JSObject* asObject(JSCell* cell)
 {
     ASSERT(cell->isObject());

Modified: trunk/Source/_javascript_Core/runtime/JSProxy.cpp (140258 => 140259)


--- trunk/Source/_javascript_Core/runtime/JSProxy.cpp	2013-01-19 21:11:31 UTC (rev 140258)
+++ trunk/Source/_javascript_Core/runtime/JSProxy.cpp	2013-01-19 21:47:45 UTC (rev 140259)
@@ -52,7 +52,7 @@
     ASSERT_ARG(globalObject, globalObject);
     m_target.set(globalData, this, globalObject);
     setPrototype(globalData, globalObject->prototype());
-    resetInheritorID(globalData);
+    globalData.prototypeMap.clearEmptyObjectStructureForPrototype(this);
 }
 
 String JSProxy::className(const JSObject* object)

Modified: trunk/Source/_javascript_Core/runtime/ObjectConstructor.cpp (140258 => 140259)


--- trunk/Source/_javascript_Core/runtime/ObjectConstructor.cpp	2013-01-19 21:11:31 UTC (rev 140258)
+++ trunk/Source/_javascript_Core/runtime/ObjectConstructor.cpp	2013-01-19 21:47:45 UTC (rev 140259)
@@ -350,7 +350,9 @@
     if (!exec->argument(0).isObject() && !exec->argument(0).isNull())
         return throwVMError(exec, createTypeError(exec, ASCIILiteral("Object prototype may only be an Object or null.")));
     JSValue proto = exec->argument(0);
-    JSObject* newObject = proto.isObject() ? constructEmptyObject(exec, asObject(proto)->inheritorID(exec->globalData())) : constructEmptyObject(exec, exec->lexicalGlobalObject()->nullPrototypeObjectStructure());
+    JSObject* newObject = proto.isObject()
+        ? constructEmptyObject(exec, exec->globalData().prototypeMap.emptyObjectStructureForPrototype(asObject(proto)))
+        : constructEmptyObject(exec, exec->lexicalGlobalObject()->nullPrototypeObjectStructure());
     if (exec->argument(1).isUndefined())
         return JSValue::encode(newObject);
     if (!exec->argument(1).isObject())

Modified: trunk/Source/_javascript_Core/runtime/ObjectPrototype.cpp (140258 => 140259)


--- trunk/Source/_javascript_Core/runtime/ObjectPrototype.cpp	2013-01-19 21:11:31 UTC (rev 140258)
+++ trunk/Source/_javascript_Core/runtime/ObjectPrototype.cpp	2013-01-19 21:47:45 UTC (rev 140259)
@@ -73,7 +73,7 @@
 {
     Base::finishCreation(globalData);
     ASSERT(inherits(&s_info));
-    notifyUsedAsPrototype(globalData);
+    globalData.prototypeMap.addPrototype(this);
 }
 
 bool ObjectPrototype::getOwnPropertySlot(JSCell* cell, ExecState* exec, PropertyName propertyName, PropertySlot &slot)

Added: trunk/Source/_javascript_Core/runtime/PrototypeMap.cpp (0 => 140259)


--- trunk/Source/_javascript_Core/runtime/PrototypeMap.cpp	                        (rev 0)
+++ trunk/Source/_javascript_Core/runtime/PrototypeMap.cpp	2013-01-19 21:47:45 UTC (rev 140259)
@@ -0,0 +1,69 @@
+/*
+ * Copyright (C) 2013 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL APPLE INC. OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 
+ */
+
+#include "config.h"
+#include "PrototypeMap.h"
+
+#include "JSGlobalObject.h"
+#include "Operations.h"
+
+namespace JSC {
+
+void PrototypeMap::addPrototype(JSObject* object)
+{
+    m_prototypes.add(object, object);
+
+    // Note that this method makes the somewhat odd decision to not check if this
+    // object currently has indexed accessors. We could do that check here, and if
+    // indexed accessors were found, we could tell the global object to have a bad
+    // time. But we avoid this, to allow the following to be always fast:
+    //
+    // 1) Create an object.
+    // 2) Give it a setter or read-only property that happens to have a numeric name.
+    // 3) Allocate objects that use this object as a prototype.
+    //
+    // This avoids anyone having a bad time. Even if the instance objects end up
+    // having indexed storage, the creation of indexed storage leads to a prototype
+    // chain walk that detects the presence of indexed setters and then does the
+    // right thing. As a result, having a bad time only happens if you add an
+    // indexed setter (or getter, or read-only field) to an object that is already
+    // used as a prototype.
+}
+
+Structure* PrototypeMap::emptyObjectStructureForPrototype(JSObject* object)
+{
+    WeakGCMap<JSObject*, Structure>::AddResult addResult = m_structures.add(object, nullptr);
+    if (!addResult.isNewEntry) {
+        ASSERT(isPrototype(object));
+        return addResult.iterator->value.get();
+    }
+
+    addPrototype(object);
+    Structure* structure = JSFinalObject::createStructure(object->globalObject()->globalData(), object->globalObject(), object);
+    addResult.iterator->value = structure;
+    return structure;
+}
+
+} // namespace JSC

Added: trunk/Source/_javascript_Core/runtime/PrototypeMap.h (0 => 140259)


--- trunk/Source/_javascript_Core/runtime/PrototypeMap.h	                        (rev 0)
+++ trunk/Source/_javascript_Core/runtime/PrototypeMap.h	2013-01-19 21:47:45 UTC (rev 140259)
@@ -0,0 +1,60 @@
+/*
+ * Copyright (C) 2013 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL APPLE INC. OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 
+ */
+
+#ifndef PrototypeMap_h
+#define PrototypeMap_h
+
+#include "WeakGCMap.h"
+
+namespace JSC {
+
+class JSObject;
+class Structure;
+
+class PrototypeMap {
+public:
+    JS_EXPORT_PRIVATE Structure* emptyObjectStructureForPrototype(JSObject*);
+    void clearEmptyObjectStructureForPrototype(JSObject*);
+    void addPrototype(JSObject*);
+    bool isPrototype(JSObject*); // Returns a conservative estimate.
+
+private:
+    WeakGCMap<JSObject*, JSObject> m_prototypes;
+    WeakGCMap<JSObject*, Structure> m_structures;
+};
+
+inline bool PrototypeMap::isPrototype(JSObject* object)
+{
+    return m_prototypes.contains(object);
+}
+
+inline void PrototypeMap::clearEmptyObjectStructureForPrototype(JSObject* object)
+{
+    m_structures.remove(object);
+}
+
+} // namespace JSC
+
+#endif // PrototypeMap_h

Modified: trunk/Source/_javascript_Core/runtime/WeakGCMap.h (140258 => 140259)


--- trunk/Source/_javascript_Core/runtime/WeakGCMap.h	2013-01-19 21:11:31 UTC (rev 140258)
+++ trunk/Source/_javascript_Core/runtime/WeakGCMap.h	2013-01-19 21:47:45 UTC (rev 140259)
@@ -88,13 +88,13 @@
         return const_cast<Self*>(this)->find(key);
     }
 
-    template<typename T, typename HashTranslator> bool contains(const T& key) const
+    bool contains(const KeyType& key) const
     {
         return find(key) != end();
     }
 
 private:
-    static const int minGCThreshold;
+    static const int minGCThreshold = 3;
 
     void gcMap()
     {
@@ -121,7 +121,7 @@
 };
 
 template<typename KeyArg, typename RawMappedArg, typename HashArg, typename KeyTraitsArg>
-const int WeakGCMap<KeyArg, RawMappedArg, HashArg, KeyTraitsArg>::minGCThreshold = 3;
+const int WeakGCMap<KeyArg, RawMappedArg, HashArg, KeyTraitsArg>::minGCThreshold;
 
 } // namespace JSC
 
_______________________________________________
webkit-changes mailing list
[email protected]
http://lists.webkit.org/mailman/listinfo/webkit-changes

Reply via email to