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