Don't prevent CreateThis being folded to NewObject when the structure is poly proto
authorsbarati@apple.com <sbarati@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Fri, 4 May 2018 04:33:53 +0000 (04:33 +0000)
committersbarati@apple.com <sbarati@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Fri, 4 May 2018 04:33:53 +0000 (04:33 +0000)
https://bugs.webkit.org/show_bug.cgi?id=185177

Reviewed by Filip Pizlo.

JSTests:

* microbenchmarks/construct-poly-proto-object.js: Added.
(foo.A):
(foo):
* stress/allocation-sinking-new-object-with-poly-proto.js: Added.
(foo.A):
(foo):
(makePolyProto):
(bar):
(baz):

Source/JavaScriptCore:

This patch teaches the DFG/FTL how to constant fold CreateThis with
a known poly proto Structure to NewObject. We do it by emitting a NewObject
followed by a PutByOffset for the prototype value.

We make it so that ObjectAllocationProfile holds the prototype value.
This is sound because JSFunction clears that profile when its 'prototype'
field changes.

This patch also renames underscoreProtoPrivateName to polyProtoName since
that name was nonsensical: it was only used for poly proto.

This is a 2x speedup on the get_callee_polymorphic microbenchmark. I had
regressed that benchmark when I first introduced poly proto.

* builtins/BuiltinNames.cpp:
* builtins/BuiltinNames.h:
(JSC::BuiltinNames::BuiltinNames):
(JSC::BuiltinNames::polyProtoName const):
(JSC::BuiltinNames::underscoreProtoPrivateName const): Deleted.
* bytecode/ObjectAllocationProfile.h:
(JSC::ObjectAllocationProfile::prototype):
(JSC::ObjectAllocationProfile::clear):
(JSC::ObjectAllocationProfile::visitAggregate):
* bytecode/ObjectAllocationProfileInlines.h:
(JSC::ObjectAllocationProfile::initializeProfile):
* dfg/DFGAbstractInterpreterInlines.h:
(JSC::DFG::AbstractInterpreter<AbstractStateType>::executeEffects):
* dfg/DFGByteCodeParser.cpp:
(JSC::DFG::ByteCodeParser::parseBlock):
* dfg/DFGConstantFoldingPhase.cpp:
(JSC::DFG::ConstantFoldingPhase::foldConstants):
* dfg/DFGOperations.cpp:
* runtime/CommonSlowPaths.cpp:
(JSC::SLOW_PATH_DECL):
* runtime/FunctionRareData.h:
* runtime/Structure.cpp:
(JSC::Structure::create):

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

15 files changed:
JSTests/ChangeLog
JSTests/microbenchmarks/construct-poly-proto-object.js [new file with mode: 0644]
JSTests/stress/allocation-sinking-new-object-with-poly-proto.js [new file with mode: 0644]
Source/JavaScriptCore/ChangeLog
Source/JavaScriptCore/builtins/BuiltinNames.cpp
Source/JavaScriptCore/builtins/BuiltinNames.h
Source/JavaScriptCore/bytecode/ObjectAllocationProfile.h
Source/JavaScriptCore/bytecode/ObjectAllocationProfileInlines.h
Source/JavaScriptCore/dfg/DFGAbstractInterpreterInlines.h
Source/JavaScriptCore/dfg/DFGByteCodeParser.cpp
Source/JavaScriptCore/dfg/DFGConstantFoldingPhase.cpp
Source/JavaScriptCore/dfg/DFGOperations.cpp
Source/JavaScriptCore/runtime/CommonSlowPaths.cpp
Source/JavaScriptCore/runtime/FunctionRareData.h
Source/JavaScriptCore/runtime/Structure.cpp

index 515e213..80d1a15 100644 (file)
@@ -1,3 +1,20 @@
+2018-05-03  Saam Barati  <sbarati@apple.com>
+
+        Don't prevent CreateThis being folded to NewObject when the structure is poly proto
+        https://bugs.webkit.org/show_bug.cgi?id=185177
+
+        Reviewed by Filip Pizlo.
+
+        * microbenchmarks/construct-poly-proto-object.js: Added.
+        (foo.A):
+        (foo):
+        * stress/allocation-sinking-new-object-with-poly-proto.js: Added.
+        (foo.A):
+        (foo):
+        (makePolyProto):
+        (bar):
+        (baz):
+
 2018-05-03  Michael Saboff  <msaboff@apple.com>
 
         OSR entry pruning of Program Bytecodes doesn't take into account try/catch
diff --git a/JSTests/microbenchmarks/construct-poly-proto-object.js b/JSTests/microbenchmarks/construct-poly-proto-object.js
new file mode 100644 (file)
index 0000000..8a6a1da
--- /dev/null
@@ -0,0 +1,21 @@
+function foo() {
+    class A {
+        constructor() {
+            this.x = 25;
+            this.y = 30;
+        }
+    };
+    return A;
+}
+let A = foo();
+let B = foo();
+noInline(A);
+noInline(B);
+
+for (let i = 0; i < 400000; ++i) {
+    let b = !!(i % 2);
+    if (b)
+        new A;
+    else
+        new B;
+}
diff --git a/JSTests/stress/allocation-sinking-new-object-with-poly-proto.js b/JSTests/stress/allocation-sinking-new-object-with-poly-proto.js
new file mode 100644 (file)
index 0000000..eea3040
--- /dev/null
@@ -0,0 +1,53 @@
+function foo() {
+    class A {
+        constructor() {
+        }
+    };
+    return A;
+}
+let A = foo();
+let B = foo();
+
+function makePolyProto(o) {
+    return o.x;
+}
+noInline(makePolyProto);
+
+for (let i = 0; i < 1000; ++i) {
+    makePolyProto(i % 2 ? new A : new B);
+}
+
+function bar(b) {
+    let o = new A;
+    if (b) {
+        if (isFinalTier())
+            OSRExit();
+        return o;
+    }
+}
+noInline(bar);
+
+function baz(b) {
+    let o = new A;
+    if (b)
+        return o;
+}
+noInline(baz);
+
+for (let i = 0; i < 100000; ++i) {
+    let b = i % 10 === 0;
+    let r = bar(b);
+    if (b) {
+        if (r.__proto__ !== A.prototype)
+            throw new Error("Bad!");
+    }
+}
+
+for (let i = 0; i < 100000; ++i) {
+    let b = i % 10 === 0;
+    let r = baz(b);
+    if (b) {
+        if (r.__proto__ !== A.prototype)
+            throw new Error("Bad!");
+    }
+}
index 9d22ef4..45eea66 100644 (file)
@@ -1,3 +1,48 @@
+2018-05-03  Saam Barati  <sbarati@apple.com>
+
+        Don't prevent CreateThis being folded to NewObject when the structure is poly proto
+        https://bugs.webkit.org/show_bug.cgi?id=185177
+
+        Reviewed by Filip Pizlo.
+
+        This patch teaches the DFG/FTL how to constant fold CreateThis with
+        a known poly proto Structure to NewObject. We do it by emitting a NewObject
+        followed by a PutByOffset for the prototype value.
+        
+        We make it so that ObjectAllocationProfile holds the prototype value.
+        This is sound because JSFunction clears that profile when its 'prototype'
+        field changes.
+        
+        This patch also renames underscoreProtoPrivateName to polyProtoName since
+        that name was nonsensical: it was only used for poly proto.
+        
+        This is a 2x speedup on the get_callee_polymorphic microbenchmark. I had
+        regressed that benchmark when I first introduced poly proto.
+
+        * builtins/BuiltinNames.cpp:
+        * builtins/BuiltinNames.h:
+        (JSC::BuiltinNames::BuiltinNames):
+        (JSC::BuiltinNames::polyProtoName const):
+        (JSC::BuiltinNames::underscoreProtoPrivateName const): Deleted.
+        * bytecode/ObjectAllocationProfile.h:
+        (JSC::ObjectAllocationProfile::prototype):
+        (JSC::ObjectAllocationProfile::clear):
+        (JSC::ObjectAllocationProfile::visitAggregate):
+        * bytecode/ObjectAllocationProfileInlines.h:
+        (JSC::ObjectAllocationProfile::initializeProfile):
+        * dfg/DFGAbstractInterpreterInlines.h:
+        (JSC::DFG::AbstractInterpreter<AbstractStateType>::executeEffects):
+        * dfg/DFGByteCodeParser.cpp:
+        (JSC::DFG::ByteCodeParser::parseBlock):
+        * dfg/DFGConstantFoldingPhase.cpp:
+        (JSC::DFG::ConstantFoldingPhase::foldConstants):
+        * dfg/DFGOperations.cpp:
+        * runtime/CommonSlowPaths.cpp:
+        (JSC::SLOW_PATH_DECL):
+        * runtime/FunctionRareData.h:
+        * runtime/Structure.cpp:
+        (JSC::Structure::create):
+
 2018-05-03  Michael Saboff  <msaboff@apple.com>
 
         OSR entry pruning of Program Bytecodes doesn't take into account try/catch
index 065d845..f52e9b8 100644 (file)
@@ -44,7 +44,7 @@ JSC_COMMON_PRIVATE_IDENTIFIERS_EACH_PROPERTY_NAME(INITIALIZE_BUILTIN_PRIVATE_NAM
 #undef INITIALIZE_BUILTIN_PRIVATE_NAMES
 
 SymbolImpl::StaticSymbolImpl dollarVMPrivateName { "PrivateSymbol.$vm", SymbolImpl::s_flagIsPrivate };
-SymbolImpl::StaticSymbolImpl underscoreProtoPrivateName { "PrivateSymbol.__proto__", SymbolImpl::s_flagIsPrivate };
+SymbolImpl::StaticSymbolImpl polyProtoPrivateName { "PrivateSymbol.PolyProto", SymbolImpl::s_flagIsPrivate };
 
 } // namespace Symbols
 } // namespace JSC
index d583b58..d4f364a 100644 (file)
@@ -204,7 +204,7 @@ JSC_COMMON_PRIVATE_IDENTIFIERS_EACH_PROPERTY_NAME(DECLARE_BUILTIN_PRIVATE_NAMES)
 #undef DECLARE_BUILTIN_PRIVATE_NAMES
 
 extern SymbolImpl::StaticSymbolImpl dollarVMPrivateName;
-extern SymbolImpl::StaticSymbolImpl underscoreProtoPrivateName;
+extern SymbolImpl::StaticSymbolImpl polyProtoPrivateName;
 }
 
 #define INITIALIZE_PRIVATE_TO_PUBLIC_ENTRY(name) m_privateToPublicMap.add(m_##name##PrivateName.impl(), &m_##name);
@@ -229,7 +229,7 @@ public:
         JSC_COMMON_PRIVATE_IDENTIFIERS_EACH_WELL_KNOWN_SYMBOL(INITIALIZE_BUILTIN_SYMBOLS)
         , m_dollarVMName(Identifier::fromString(vm, "$vm"))
         , m_dollarVMPrivateName(Identifier::fromUid(vm, &static_cast<SymbolImpl&>(Symbols::dollarVMPrivateName)))
-        , m_underscoreProtoPrivateName(Identifier::fromUid(vm, &static_cast<SymbolImpl&>(Symbols::underscoreProtoPrivateName)))
+        , m_polyProtoPrivateName(Identifier::fromUid(vm, &static_cast<SymbolImpl&>(Symbols::polyProtoPrivateName)))
     {
         JSC_FOREACH_BUILTIN_FUNCTION_NAME(INITIALIZE_PRIVATE_TO_PUBLIC_ENTRY)
         JSC_COMMON_PRIVATE_IDENTIFIERS_EACH_PROPERTY_NAME(INITIALIZE_PRIVATE_TO_PUBLIC_ENTRY)
@@ -238,8 +238,6 @@ public:
         JSC_COMMON_PRIVATE_IDENTIFIERS_EACH_WELL_KNOWN_SYMBOL(INITIALIZE_SYMBOL_PUBLIC_TO_PRIVATE_ENTRY)
         m_privateToPublicMap.add(m_dollarVMPrivateName.impl(), &m_dollarVMName);
         m_publicToPrivateMap.add(m_dollarVMName.impl(), &m_dollarVMPrivateName);
-        m_privateToPublicMap.add(m_underscoreProtoPrivateName.impl(), &commonIdentifiers->underscoreProto);
-        m_publicToPrivateMap.add(commonIdentifiers->underscoreProto.impl(), &m_underscoreProtoPrivateName);
     }
 
     const Identifier* lookUpPrivateName(const Identifier&) const;
@@ -252,7 +250,7 @@ public:
     JSC_COMMON_PRIVATE_IDENTIFIERS_EACH_WELL_KNOWN_SYMBOL(DECLARE_BUILTIN_SYMBOL_ACCESSOR)
     const JSC::Identifier& dollarVMPublicName() const { return m_dollarVMName; }
     const JSC::Identifier& dollarVMPrivateName() const { return m_dollarVMPrivateName; }
-    const JSC::Identifier& underscoreProtoPrivateName() const { return m_underscoreProtoPrivateName; }
+    const JSC::Identifier& polyProtoName() const { return m_polyProtoPrivateName; }
 
 private:
     Identifier m_emptyIdentifier;
@@ -261,7 +259,7 @@ private:
     JSC_COMMON_PRIVATE_IDENTIFIERS_EACH_WELL_KNOWN_SYMBOL(DECLARE_BUILTIN_SYMBOLS)
     const JSC::Identifier m_dollarVMName;
     const JSC::Identifier m_dollarVMPrivateName;
-    const JSC::Identifier m_underscoreProtoPrivateName;
+    const JSC::Identifier m_polyProtoPrivateName;
     typedef HashMap<RefPtr<UniquedStringImpl>, const Identifier*, IdentifierRepHash> BuiltinNamesMap;
     BuiltinNamesMap m_publicToPrivateMap;
     BuiltinNamesMap m_privateToPublicMap;
index 6177191..a70753a 100644 (file)
@@ -58,12 +58,20 @@ public:
         WTF::loadLoadFence();
         return structure;
     }
+    JSObject* prototype()
+    {
+        JSObject* prototype = m_prototype.get();
+        WTF::loadLoadFence();
+        return prototype;
+    }
     unsigned inlineCapacity() { return m_inlineCapacity; }
 
+
     void clear()
     {
         m_allocator = Allocator();
         m_structure.clear();
+        m_prototype.clear();
         m_inlineCapacity = 0;
         ASSERT(isNull());
     }
@@ -71,6 +79,7 @@ public:
     void visitAggregate(SlotVisitor& visitor)
     {
         visitor.append(m_structure);
+        visitor.append(m_prototype);
     }
 
 private:
@@ -78,6 +87,7 @@ private:
 
     Allocator m_allocator; // Precomputed to make things easier for generated code.
     WriteBarrier<Structure> m_structure;
+    WriteBarrier<JSObject> m_prototype;
     unsigned m_inlineCapacity;
 };
 
index 5337929..553ac51 100644 (file)
@@ -35,11 +35,12 @@ ALWAYS_INLINE void ObjectAllocationProfile::initializeProfile(VM& vm, JSGlobalOb
 {
     ASSERT(!m_allocator);
     ASSERT(!m_structure);
+    ASSERT(!m_prototype);
     ASSERT(!m_inlineCapacity);
 
-    // FIXME: When going poly proto, we should make an allocator and teach
-    // create_this' fast path how to allocate a poly proto object.
-    // https://bugs.webkit.org/show_bug.cgi?id=177517
+    // FIXME: Teach create_this's fast path how to allocate poly
+    // proto objects: https://bugs.webkit.org/show_bug.cgi?id=177517
+
     bool isPolyProto = false;
     FunctionExecutable* executable = nullptr;
     if (constructor) {
@@ -55,6 +56,7 @@ ALWAYS_INLINE void ObjectAllocationProfile::initializeProfile(VM& vm, JSGlobalOb
             RELEASE_ASSERT(structure->typeInfo().type() == FinalObjectType);
             m_allocator = Allocator();
             m_structure.set(vm, owner, structure);
+            m_prototype.set(vm, owner, prototype);
             m_inlineCapacity = structure->inlineCapacity();
             return;
         }
@@ -132,10 +134,11 @@ ALWAYS_INLINE void ObjectAllocationProfile::initializeProfile(VM& vm, JSGlobalOb
         m_allocator = allocator;
     }
 
-    // Ensure that if another thread sees the structure, it will see it properly created
+    // Ensure that if another thread sees the structure and prototype, it will see it properly created.
     WTF::storeStoreFence();
 
     m_structure.set(vm, owner, structure);
+    m_prototype.set(vm, owner, prototype);
     m_inlineCapacity = inlineCapacity;
 }
 
index ed6b32c..a57dc74 100644 (file)
@@ -2318,16 +2318,12 @@ bool AbstractInterpreter<AbstractStateType>::executeEffects(unsigned clobberLimi
             if (auto* function = jsDynamicCast<JSFunction*>(m_vm, base)) {
                 if (FunctionRareData* rareData = function->rareData()) {
                     if (Structure* structure = rareData->objectAllocationStructure()) {
-                        // FIXME: we should be able to allocate a poly proto object here:
-                        // https://bugs.webkit.org/show_bug.cgi?id=177517
-                        if (structure->hasMonoProto()) {
-                            m_graph.freeze(rareData);
-                            m_graph.watchpoints().addLazily(rareData->allocationProfileWatchpointSet());
-                            m_state.setFoundConstants(true);
-                            didFoldClobberWorld();
-                            forNode(node).set(m_graph, structure);
-                            break;
-                        }
+                        m_graph.freeze(rareData);
+                        m_graph.watchpoints().addLazily(rareData->allocationProfileWatchpointSet());
+                        m_state.setFoundConstants(true);
+                        didFoldClobberWorld();
+                        forNode(node).set(m_graph, structure);
+                        break;
                     }
                 }
             }
index 527e732..84a784c 100644 (file)
@@ -31,6 +31,7 @@
 #include "ArithProfile.h"
 #include "ArrayConstructor.h"
 #include "BasicBlockLocation.h"
+#include "BuiltinNames.h"
 #include "BytecodeStructs.h"
 #include "CallLinkStatus.h"
 #include "CodeBlock.h"
@@ -4485,15 +4486,29 @@ void ByteCodeParser::parseBlock(unsigned limit)
             bool alreadyEmitted = false;
             if (function) {
                 if (FunctionRareData* rareData = function->rareData()) {
-                    if (Structure* structure = rareData->objectAllocationStructure()) {
-                        // FIXME: we should be able to allocate a poly proto object here:
-                        // https://bugs.webkit.org/show_bug.cgi?id=177517
-                        if (structure->hasMonoProto()) {
+                    if (rareData->allocationProfileWatchpointSet().isStillValid()) {
+                        Structure* structure = rareData->objectAllocationStructure();
+                        JSObject* prototype = rareData->objectAllocationPrototype();
+                        if (structure
+                            && (structure->hasMonoProto() || prototype)
+                            && rareData->allocationProfileWatchpointSet().isStillValid()) {
+
                             m_graph.freeze(rareData);
                             m_graph.watchpoints().addLazily(rareData->allocationProfileWatchpointSet());
                             // The callee is still live up to this point.
                             addToGraph(Phantom, callee);
-                            set(VirtualRegister(bytecode.dst()), addToGraph(NewObject, OpInfo(m_graph.registerStructure(structure))));
+                            Node* object = addToGraph(NewObject, OpInfo(m_graph.registerStructure(structure)));
+                            if (structure->hasPolyProto()) {
+                                StorageAccessData* data = m_graph.m_storageAccessData.add();
+                                data->offset = knownPolyProtoOffset;
+                                data->identifierNumber = m_graph.identifiers().ensure(m_graph.m_vm.propertyNames->builtinNames().polyProtoName().impl());
+                                InferredType::Descriptor inferredType = InferredType::Top;
+                                data->inferredType = inferredType;
+                                m_graph.registerInferredType(inferredType);
+                                ASSERT(isInlineOffset(knownPolyProtoOffset));
+                                addToGraph(PutByOffset, OpInfo(data), object, object, weakJSConstant(prototype));
+                            }
+                            set(VirtualRegister(bytecode.dst()), object);
                             alreadyEmitted = true;
                         }
                     }
index e9a1b54..6adb362 100644 (file)
@@ -28,6 +28,7 @@
 
 #if ENABLE(DFG_JIT)
 
+#include "BuiltinNames.h"
 #include "DFGAbstractInterpreterInlines.h"
 #include "DFGArgumentsUtilities.h"
 #include "DFGBasicBlockInlines.h"
@@ -643,15 +644,37 @@ private:
                 if (JSValue base = m_state.forNode(node->child1()).m_value) {
                     if (auto* function = jsDynamicCast<JSFunction*>(m_graph.m_vm, base)) {
                         if (FunctionRareData* rareData = function->rareData()) {
-                            if (Structure* structure = rareData->objectAllocationStructure()) {
-                                // FIXME: we should be able to allocate a poly proto object here:
-                                // https://bugs.webkit.org/show_bug.cgi?id=177517
-                                if (structure->hasMonoProto()) {
+                            if (rareData->allocationProfileWatchpointSet().isStillValid()) {
+                                Structure* structure = rareData->objectAllocationStructure();
+                                JSObject* prototype = rareData->objectAllocationPrototype();
+                                if (structure
+                                    && (structure->hasMonoProto() || prototype)
+                                    && rareData->allocationProfileWatchpointSet().isStillValid()) {
+
                                     m_graph.freeze(rareData);
                                     m_graph.watchpoints().addLazily(rareData->allocationProfileWatchpointSet());
                                     node->convertToNewObject(m_graph.registerStructure(structure));
+
+                                    if (structure->hasPolyProto()) {
+                                        StorageAccessData* data = m_graph.m_storageAccessData.add();
+                                        data->offset = knownPolyProtoOffset;
+                                        data->identifierNumber = m_graph.identifiers().ensure(m_graph.m_vm.propertyNames->builtinNames().polyProtoName().impl());
+                                        InferredType::Descriptor inferredType = InferredType::Top;
+                                        data->inferredType = inferredType;
+                                        m_graph.registerInferredType(inferredType);
+
+                                        NodeOrigin origin = node->origin.withInvalidExit();
+                                        Node* prototypeNode = m_insertionSet.insertConstant(
+                                            indexInBlock + 1, origin, m_graph.freeze(prototype));
+
+                                        ASSERT(isInlineOffset(knownPolyProtoOffset));
+                                        m_insertionSet.insertNode(
+                                            indexInBlock + 1, SpecNone, PutByOffset, origin, OpInfo(data),
+                                            Edge(node, KnownCellUse), Edge(node, KnownCellUse), Edge(prototypeNode, UntypedUse));
+                                    }
                                     changed = true;
                                     break;
+
                                 }
                             }
                         }
index e79d585..4f9813c 100644 (file)
@@ -250,10 +250,12 @@ JSCell* JIT_OPERATION operationCreateThis(ExecState* exec, JSObject* constructor
     if (constructor->type() == JSFunctionType && jsCast<JSFunction*>(constructor)->canUseAllocationProfile()) {
         auto rareData = jsCast<JSFunction*>(constructor)->ensureRareDataAndAllocationProfile(exec, inlineCapacity);
         RETURN_IF_EXCEPTION(scope, nullptr);
-        Structure* structure = rareData->objectAllocationProfile()->structure();
+        ObjectAllocationProfile* allocationProfile = rareData->objectAllocationProfile();
+        Structure* structure = allocationProfile->structure();
         JSObject* result = constructEmptyObject(exec, structure);
         if (structure->hasPolyProto()) {
-            JSObject* prototype = jsCast<JSFunction*>(constructor)->prototypeForConstruction(vm, exec);
+            JSObject* prototype = allocationProfile->prototype();
+            ASSERT(prototype == jsCast<JSFunction*>(constructor)->prototypeForConstruction(vm, exec));
             result->putDirect(vm, knownPolyProtoOffset, prototype);
             prototype->didBecomePrototype();
             ASSERT_WITH_MESSAGE(!hasIndexedProperties(result->indexingType()), "We rely on JSFinalObject not starting out with an indexing type otherwise we would potentially need to convert to slow put storage");
index e6c1a44..a550fc0 100644 (file)
@@ -224,10 +224,12 @@ SLOW_PATH_DECL(slow_path_create_this)
             cachedCallee.setWithoutWriteBarrier(JSCell::seenMultipleCalleeObjects());
 
         size_t inlineCapacity = bytecode.inlineCapacity();
-        Structure* structure = constructor->ensureRareDataAndAllocationProfile(exec, inlineCapacity)->objectAllocationProfile()->structure();
+        ObjectAllocationProfile* allocationProfile = constructor->ensureRareDataAndAllocationProfile(exec, inlineCapacity)->objectAllocationProfile();
+        Structure* structure = allocationProfile->structure();
         result = constructEmptyObject(exec, structure);
         if (structure->hasPolyProto()) {
-            JSObject* prototype = constructor->prototypeForConstruction(vm, exec);
+            JSObject* prototype = allocationProfile->prototype();
+            ASSERT(prototype == constructor->prototypeForConstruction(vm, exec));
             result->putDirect(vm, knownPolyProtoOffset, prototype);
             prototype->didBecomePrototype();
             ASSERT_WITH_MESSAGE(!hasIndexedProperties(result->indexingType()), "We rely on JSFinalObject not starting out with an indexing type otherwise we would potentially need to convert to slow put storage");
index b36f7e9..2c54eed 100644 (file)
@@ -71,6 +71,7 @@ public:
     }
 
     Structure* objectAllocationStructure() { return m_objectAllocationProfile.structure(); }
+    JSObject* objectAllocationPrototype() { return m_objectAllocationProfile.prototype(); }
 
     InlineWatchpointSet& allocationProfileWatchpointSet()
     {
index 3467386..720aff7 100644 (file)
@@ -306,7 +306,7 @@ Structure* Structure::create(PolyProtoTag, VM& vm, JSGlobalObject* globalObject,
 
     unsigned oldOutOfLineCapacity = result->outOfLineCapacity();
     result->addPropertyWithoutTransition(
-        vm, vm.propertyNames->builtinNames().underscoreProtoPrivateName(), static_cast<unsigned>(PropertyAttribute::DontEnum),
+        vm, vm.propertyNames->builtinNames().polyProtoName(), static_cast<unsigned>(PropertyAttribute::DontEnum),
         [&] (const GCSafeConcurrentJSLocker&, PropertyOffset offset, PropertyOffset newLastOffset) {
             RELEASE_ASSERT(Structure::outOfLineCapacity(newLastOffset) == oldOutOfLineCapacity);
             RELEASE_ASSERT(offset == knownPolyProtoOffset);