Structure::create should call didBecomePrototype()
authorkeith_miller@apple.com <keith_miller@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Tue, 25 Jun 2019 19:49:22 +0000 (19:49 +0000)
committerkeith_miller@apple.com <keith_miller@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Tue, 25 Jun 2019 19:49:22 +0000 (19:49 +0000)
https://bugs.webkit.org/show_bug.cgi?id=196315

Reviewed by Filip Pizlo.

Structure::create should also assert that the indexing type makes sense
for the prototype being used.

* runtime/JSObject.h:
* runtime/Structure.cpp:
(JSC::Structure::isValidPrototype):
(JSC::Structure::changePrototypeTransition):
* runtime/Structure.h:
(JSC::Structure::create): Deleted.
* runtime/StructureInlines.h:
(JSC::Structure::create):
(JSC::Structure::setPrototypeWithoutTransition):

git-svn-id: https://svn.webkit.org/repository/webkit/trunk@246801 268f45cc-cd09-0410-ab3c-d52691b4dbfc

Source/JavaScriptCore/ChangeLog
Source/JavaScriptCore/runtime/JSObject.h
Source/JavaScriptCore/runtime/Structure.cpp
Source/JavaScriptCore/runtime/Structure.h
Source/JavaScriptCore/runtime/StructureInlines.h

index aa65b11..59481f6 100644 (file)
@@ -1,3 +1,23 @@
+2019-06-25  Keith Miller  <keith_miller@apple.com>
+
+        Structure::create should call didBecomePrototype()
+        https://bugs.webkit.org/show_bug.cgi?id=196315
+
+        Reviewed by Filip Pizlo.
+
+        Structure::create should also assert that the indexing type makes sense
+        for the prototype being used.
+
+        * runtime/JSObject.h:
+        * runtime/Structure.cpp:
+        (JSC::Structure::isValidPrototype):
+        (JSC::Structure::changePrototypeTransition):
+        * runtime/Structure.h:
+        (JSC::Structure::create): Deleted.
+        * runtime/StructureInlines.h:
+        (JSC::Structure::create):
+        (JSC::Structure::setPrototypeWithoutTransition):
+
 2019-06-25  Joseph Pecoraro  <pecoraro@apple.com>
 
         Web Inspector: Implement console.timeLog
index e0b875a..e1b2185 100644 (file)
@@ -744,7 +744,7 @@ public:
     bool isSealed(VM& vm) { return structure(vm)->isSealed(vm); }
     bool isFrozen(VM& vm) { return structure(vm)->isFrozen(vm); }
 
-    bool anyObjectInChainMayInterceptIndexedAccesses(VM&) const;
+    JS_EXPORT_PRIVATE bool anyObjectInChainMayInterceptIndexedAccesses(VM&) const;
     JS_EXPORT_PRIVATE bool prototypeChainMayInterceptStoreTo(VM&, PropertyName);
     bool needsSlowPutIndexing(VM&) const;
 
index ff38bb9..293c464 100644 (file)
@@ -321,6 +321,11 @@ Structure* Structure::create(PolyProtoTag, VM& vm, JSGlobalObject* globalObject,
     return result;
 }
 
+bool Structure::isValidPrototype(JSValue prototype)
+{
+    return prototype.isNull() || (prototype.isObject() && prototype.getObject()->mayBePrototype());
+}
+
 void Structure::findStructuresAndMapForMaterialization(Vector<Structure*, 8>& structures, Structure*& structure, PropertyTable*& table)
 {
     ASSERT(structures.isEmpty());
@@ -544,7 +549,7 @@ Structure* Structure::removePropertyTransition(VM& vm, Structure* structure, Pro
 
 Structure* Structure::changePrototypeTransition(VM& vm, Structure* structure, JSValue prototype, DeferredStructureTransitionWatchpointFire& deferred)
 {
-    ASSERT(prototype.isObject() || prototype.isNull());
+    ASSERT(isValidPrototype(prototype));
 
     DeferGC deferGC(vm.heap);
     Structure* transition = create(vm, structure, &deferred);
index 4b0d031..c6a65e4 100644 (file)
@@ -138,11 +138,13 @@ public:
         return &vm.structureSpace;
     }
 
+    JS_EXPORT_PRIVATE static bool isValidPrototype(JSValue);
+
 protected:
     void finishCreation(VM& vm)
     {
         Base::finishCreation(vm);
-        ASSERT(m_prototype.get().isEmpty() || m_prototype.isObject() || m_prototype.isNull());
+        ASSERT(m_prototype.get().isEmpty() || isValidPrototype(m_prototype.get()));
     }
 
     void finishCreation(VM& vm, const Structure* previous)
@@ -786,16 +788,4 @@ private:
     uint32_t m_propertyHash;
 };
 
-// We deliberately put Structure::create here in Structure.h instead of StructureInlines.h, because
-// it is used everywhere. This is so we don't have to hunt down all the places where we would need
-// to #include StructureInlines.h otherwise.
-inline Structure* Structure::create(VM& vm, JSGlobalObject* globalObject, JSValue prototype, const TypeInfo& typeInfo, const ClassInfo* classInfo, IndexingType indexingType, unsigned inlineCapacity)
-{
-    ASSERT(vm.structureStructure);
-    ASSERT(classInfo);
-    Structure* structure = new (NotNull, allocateCell<Structure>(vm.heap)) Structure(vm, globalObject, prototype, typeInfo, classInfo, indexingType, inlineCapacity);
-    structure->finishCreation(vm);
-    return structure;
-}
-
 } // namespace JSC
index 4a30f37..e3fcaef 100644 (file)
 
 namespace JSC {
 
+inline Structure* Structure::create(VM& vm, JSGlobalObject* globalObject, JSValue prototype, const TypeInfo& typeInfo, const ClassInfo* classInfo, IndexingType indexingType, unsigned inlineCapacity)
+{
+    ASSERT(vm.structureStructure);
+    ASSERT(classInfo);
+    if (auto* object = prototype.getObject()) {
+        ASSERT(!object->anyObjectInChainMayInterceptIndexedAccesses(vm) || hasSlowPutArrayStorage(indexingType) || !hasIndexedProperties(indexingType));
+        object->didBecomePrototype();
+    }
+
+    Structure* structure = new (NotNull, allocateCell<Structure>(vm.heap)) Structure(vm, globalObject, prototype, typeInfo, classInfo, indexingType, inlineCapacity);
+    structure->finishCreation(vm);
+    return structure;
+}
+
 inline Structure* Structure::createStructure(VM& vm)
 {
     ASSERT(!vm.structureStructure);
@@ -493,6 +507,7 @@ inline PropertyOffset Structure::removePropertyWithoutTransition(VM&, PropertyNa
 
 ALWAYS_INLINE void Structure::setPrototypeWithoutTransition(VM& vm, JSValue prototype)
 {
+    ASSERT(isValidPrototype(prototype));
     m_prototype.set(vm, this, prototype);
 }