Ignore:
Timestamp:
Oct 3, 2017, 6:53:18 PM (8 years ago)
Author:
[email protected]
Message:

Implement polymorphic prototypes
https://bugs.webkit.org/show_bug.cgi?id=176391

Reviewed by Filip Pizlo.

JSTests:

  • microbenchmarks/poly-proto-access.js: Added.

(assert):
(foo.C):
(foo.C.prototype.get bar):
(foo):
(bar):

  • microbenchmarks/poly-proto-put-transition-speed.js: Added.

(assert):
(makePolyProtoObject.foo.C):
(makePolyProtoObject.foo):
(makePolyProtoObject):
(performSet):

  • microbenchmarks/poly-proto-setter-speed.js: Added.

(assert):
(makePolyProtoObject.foo.C):
(makePolyProtoObject.foo.C.prototype.set p):
(makePolyProtoObject.foo):
(makePolyProtoObject):
(performSet):

  • stress/constructor-with-return.js:

(i.tests.forEach.Constructor):
(i.tests.forEach):
(tests.forEach.Constructor): Deleted.
(tests.forEach): Deleted.

  • stress/dom-jit-with-poly-proto.js: Added.

(assert):
(makePolyProtoObject.foo.C):
(makePolyProtoObject.foo):
(makePolyProtoObject):
(validate):

  • stress/poly-proto-custom-value-and-accessor.js: Added.

(assert):
(makePolyProtoObject.foo.C):
(makePolyProtoObject.foo):
(makePolyProtoObject):
(items.forEach):
(set get for):

  • stress/poly-proto-intrinsic-getter-correctness.js: Added.

(assert):
(makePolyProtoObject.foo.C):
(makePolyProtoObject.foo):
(makePolyProtoObject):
(foo):

  • stress/poly-proto-miss.js: Added.

(makePolyProtoInstanceWithNullPrototype.foo.C):
(makePolyProtoInstanceWithNullPrototype.foo):
(makePolyProtoInstanceWithNullPrototype):
(assert):
(validate):

  • stress/poly-proto-op-in-caching.js: Added.

(assert):
(makePolyProtoObject.foo.C):
(makePolyProtoObject.foo):
(makePolyProtoObject):
(validate):
(validate2):

  • stress/poly-proto-put-transition.js: Added.

(assert):
(makePolyProtoObject.foo.C):
(makePolyProtoObject.foo):
(makePolyProtoObject):
(performSet):
(i.obj.proto.set p):

  • stress/poly-proto-set-prototype.js: Added.

(assert):
(let.alternateProto.get x):
(let.alternateProto2.get y):
(let.alternateProto2.get x):
(foo.C):
(foo):
(validate):

  • stress/poly-proto-setter.js: Added.

(assert):
(makePolyProtoObject.foo.C):
(makePolyProtoObject.foo.C.prototype.set p):
(makePolyProtoObject.foo.C.prototype.get p):
(makePolyProtoObject.foo):
(makePolyProtoObject):
(performSet):

  • stress/poly-proto-using-inheritance.js: Added.

(assert):
(foo.C):
(foo.C.prototype.get baz):
(foo):
(bar.C):
(bar):
(validate):

  • stress/primitive-poly-proto.js: Added.

(makePolyProtoInstance.foo.C):
(makePolyProtoInstance.foo):
(makePolyProtoInstance):
(assert):
(validate):

  • stress/prototype-is-not-js-object.js: Added.

(foo.bar):
(foo):
(assert):
(validate):

  • stress/try-get-by-id-poly-proto.js: Added.

(assert):
(makePolyProtoObject.foo.C):
(makePolyProtoObject.foo):
(makePolyProtoObject):
(tryGetByIdText):
(x.proto.get bar):
(validate):

  • typeProfiler/overflow.js:

Source/JavaScriptCore:

This patch changes JSC's object model with respect to where the prototype
of an object is stored. Previously, it was always stored as
a constant value inside Structure. So an object's structure used to
always tell you what its prototype is. Anytime an object changed
its prototype, it would do a structure transition. This enables
a large class of optimizations: just by doing a structure check,
we know what the prototype is.

However, this design falls down when you have many objects that
have the same shape, but only differ in what their prototype value
is. This arises in many JS programs. A simple, and probably common, example
is when the program has a constructor inside of a function:
`
function foo() {

class C {

constructor() { this.field1 = 42; ...; this.fieldN = 42; }
method1() { doStuffWith(this.field); }
method2() { doStuffWith(this.field); }

}
let c = new C;
do things with c;
}

repeatedly call foo() here.
`

Before this patch, in the above program, each time new C created an
object, it would create an object with a different structure. The
reason for this is that each time foo is called, there is a new
instance of C.prototype. However, each new C that was created
with have identical shape sans its prototype value. This would
cause all ICs that used c to quickly give up on any form of caching
because they would see too many structures and give up and permanently
divert control flow to the slow path.

This patch fixes this issue by expanding the notion of where the prototype
of an object is stored. There are now two notions of where the prototype
is stored. A Structure can now be in two modes:

  1. Mono proto mode. This is the same mode as we used to have. It means

the structure itself has a constant prototype value.

  1. Poly proto mode. This means the structure knows nothing about the

prototype value itself. Objects with this structure store their prototype
in normal object field storage. The structure will tell you the offset of
this prototype inside the object's storage. As of today, we only reserve
inline slots for the prototype field because poly proto only occurs
for JSFinalObject. However, this will be expanded to support out of line
offsets in a future patch when we extend poly proto to work when we inherit
from builtin types like Map and Array.

In this initial patch, we do poly proto style inline caching whenever
we see an object that is poly proto or if an object in its prototype lookup
chain is poly proto. Poly proto ICs work by verifying the lookup chain
at runtime. This essentially boils down to performing structure checks
up the prototype chain. In a future patch, we're going to extend object
property condition set to work with objects that don't have poly proto bases.

Initially, accesses that have poly proto access chains will always turn
into GetById/PutById in the DFG. In a future patch, I'm going to teach
the DFG how to inline certain accesses that have poly proto in the access
chain.

One of most interesting parts about this patch is how we decide when to go
poly proto. This patch uses a profiling based approach. An IC will inform
a watchpoint that it sees an opportunity when two Structure's are structurally
the same, sans the base object's prototype. This means that two structures
have equivalent shapes all the way up the prototype chain. To support fast
structural comparison, we compute a hash for a structure based on the properties
it has. We compute this hash as we add properties to the structure. This
computation is nearly free since we always add UniquedStringImpl*'s which
already have their hashes computed. To compare structural equivalence, we
just compare hash values all the way up the prototype chain. This means we
can get hash conflicts between two structures, but it's extremely rare. First,
it'll be rare for two structures to have the same hash. Secondly, we only
consider structures originating from the same executable.

How we set up this poly proto watchpoint is crucial to its design. When we create_this
an object originating from some executable, that executable will create a Box<InlineWatchpointSet>.
Each structure that originates from this executable will get a copy of that
Box<InlineWatchpointSet>. As that structure transitions to new structures,
they too will get a copy of that Box<InilneWatchpointSet>. Therefore, when
invalidating an arbitrary structure's poly proto watchpoint, we will know
the next time we create_this from that executable that it had been
invalidated, and that we should create an object with a poly proto
structure. We also use the pointer value of this Box<InlineWatchpointSet>
to determine if two structures originated from the same executable. This
pruning will severely limit the chances of getting a hash conflict in practice.

This patch is neutral on my MBP on traditional JS benchmarks like Octane/Kraken/Sunspider.
It may be a 1-2% ARES-6 progression.

This patch is between neutral and a 9x progression on the various tests
I added. Most of the microbenchmarks are progressed by at least 50%.

  • JavaScriptCore.xcodeproj/project.pbxproj:
  • Sources.txt:
  • builtins/BuiltinNames.cpp:
  • builtins/BuiltinNames.h:

(JSC::BuiltinNames::BuiltinNames):
(JSC::BuiltinNames::underscoreProtoPrivateName const):

  • bytecode/AccessCase.cpp:

(JSC::AccessCase::AccessCase):
(JSC::AccessCase::create):
(JSC::AccessCase::commit):
(JSC::AccessCase::guardedByStructureCheck const):
(JSC::AccessCase::canReplace const):
(JSC::AccessCase::dump const):
(JSC::AccessCase::visitWeak const):
(JSC::AccessCase::propagateTransitions const):
(JSC::AccessCase::generateWithGuard):
(JSC::AccessCase::generateImpl):

  • bytecode/AccessCase.h:

(JSC::AccessCase::usesPolyProto const):
(JSC::AccessCase::AccessCase):

  • bytecode/CodeBlock.cpp:

(JSC::CodeBlock::finishCreation):

  • bytecode/GetByIdStatus.cpp:

(JSC::GetByIdStatus::computeForStubInfoWithoutExitSiteFeedback):

  • bytecode/GetterSetterAccessCase.cpp:

(JSC::GetterSetterAccessCase::GetterSetterAccessCase):
(JSC::GetterSetterAccessCase::create):

  • bytecode/GetterSetterAccessCase.h:
  • bytecode/InternalFunctionAllocationProfile.h:

(JSC::InternalFunctionAllocationProfile::createAllocationStructureFromBase):

  • bytecode/IntrinsicGetterAccessCase.cpp:

(JSC::IntrinsicGetterAccessCase::IntrinsicGetterAccessCase):

  • bytecode/IntrinsicGetterAccessCase.h:
  • bytecode/ModuleNamespaceAccessCase.cpp:

(JSC::ModuleNamespaceAccessCase::ModuleNamespaceAccessCase):

  • bytecode/ObjectAllocationProfile.cpp: Added.

(JSC::ObjectAllocationProfile::initializeProfile):
(JSC::ObjectAllocationProfile::possibleDefaultPropertyCount):

  • bytecode/ObjectAllocationProfile.h:

(JSC::ObjectAllocationProfile::clear):
(JSC::ObjectAllocationProfile::initialize): Deleted.
(JSC::ObjectAllocationProfile::possibleDefaultPropertyCount): Deleted.

  • bytecode/ObjectPropertyConditionSet.cpp:
  • bytecode/PolyProtoAccessChain.cpp: Added.

(JSC::PolyProtoAccessChain::create):
(JSC::PolyProtoAccessChain::needImpurePropertyWatchpoint const):
(JSC::PolyProtoAccessChain::operator== const):
(JSC::PolyProtoAccessChain::dump const):

  • bytecode/PolyProtoAccessChain.h: Added.

(JSC::PolyProtoAccessChain::clone):
(JSC::PolyProtoAccessChain:: const):
(JSC::PolyProtoAccessChain::operator!= const):
(JSC::PolyProtoAccessChain::forEach const):

  • bytecode/PolymorphicAccess.cpp:

(JSC::PolymorphicAccess::addCases):
(JSC::PolymorphicAccess::regenerate):
(WTF::printInternal):

  • bytecode/PolymorphicAccess.h:

(JSC::AccessGenerationResult::shouldResetStub const):
(JSC::AccessGenerationState::AccessGenerationState):

  • bytecode/PropertyCondition.cpp:

(JSC::PropertyCondition::isStillValidAssumingImpurePropertyWatchpoint const):

  • bytecode/ProxyableAccessCase.cpp:

(JSC::ProxyableAccessCase::ProxyableAccessCase):
(JSC::ProxyableAccessCase::create):

  • bytecode/ProxyableAccessCase.h:
  • bytecode/PutByIdStatus.cpp:

(JSC::PutByIdStatus::computeForStubInfo):

  • bytecode/StructureStubInfo.cpp:

(JSC::StructureStubInfo::addAccessCase):

  • dfg/DFGByteCodeParser.cpp:

(JSC::DFG::ByteCodeParser::load):
(JSC::DFG::ByteCodeParser::parseBlock):

  • dfg/DFGGraph.cpp:

(JSC::DFG::Graph::canDoFastSpread):

  • dfg/DFGOperations.cpp:
  • dfg/DFGSpeculativeJIT.cpp:

(JSC::DFG::SpeculativeJIT::compileInstanceOfForObject):
(JSC::DFG::SpeculativeJIT::compileInstanceOf):

  • dfg/DFGSpeculativeJIT.h:
  • dfg/DFGSpeculativeJIT64.cpp:

(JSC::DFG::SpeculativeJIT::compile):

  • ftl/FTLLowerDFGToB3.cpp:

(JSC::FTL::DFG::LowerDFGToB3::compileInstanceOf):

  • jit/JITOpcodes.cpp:

(JSC::JIT::emit_op_instanceof):

  • jit/JITOpcodes32_64.cpp:

(JSC::JIT::emit_op_instanceof):

  • jit/Repatch.cpp:

(JSC::tryCacheGetByID):
(JSC::tryCachePutByID):
(JSC::tryRepatchIn):

  • jsc.cpp:

(WTF::DOMJITGetterBaseJSObject::DOMJITGetterBaseJSObject):
(WTF::DOMJITGetterBaseJSObject::createStructure):
(WTF::DOMJITGetterBaseJSObject::create):
(WTF::DOMJITGetterBaseJSObject::DOMJITAttribute::DOMJITAttribute):
(WTF::DOMJITGetterBaseJSObject::DOMJITAttribute::slowCall):
(WTF::DOMJITGetterBaseJSObject::DOMJITAttribute::callDOMGetter):
(WTF::DOMJITGetterBaseJSObject::customGetter):
(WTF::DOMJITGetterBaseJSObject::finishCreation):
(GlobalObject::finishCreation):
(functionCreateDOMJITGetterBaseJSObject):

  • llint/LLIntSlowPaths.cpp:

(JSC::LLInt::LLINT_SLOW_PATH_DECL):

  • runtime/ArrayPrototype.cpp:

(JSC::holesMustForwardToPrototype):
(JSC::fastJoin):
(JSC::arrayProtoFuncReverse):
(JSC::moveElements):

  • runtime/ClonedArguments.cpp:

(JSC::ClonedArguments::createEmpty):
(JSC::ClonedArguments::createWithInlineFrame):
(JSC::ClonedArguments::createWithMachineFrame):
(JSC::ClonedArguments::createByCopyingFrom):

  • runtime/CommonSlowPaths.cpp:

(JSC::SLOW_PATH_DECL):

  • runtime/FunctionExecutable.cpp:

(JSC::FunctionExecutable::visitChildren):

  • runtime/FunctionExecutable.h:
  • runtime/FunctionRareData.cpp:

(JSC::FunctionRareData::initializeObjectAllocationProfile):

  • runtime/FunctionRareData.h:
  • runtime/InternalFunction.cpp:

(JSC::InternalFunction::createSubclassStructureSlow):

  • runtime/JSArray.cpp:

(JSC::JSArray::fastSlice):
(JSC::JSArray::shiftCountWithArrayStorage):
(JSC::JSArray::shiftCountWithAnyIndexingType):
(JSC::JSArray::isIteratorProtocolFastAndNonObservable):

  • runtime/JSArrayInlines.h:

(JSC::JSArray::canFastCopy):

  • runtime/JSCJSValue.cpp:

(JSC::JSValue::dumpInContextAssumingStructure const):

  • runtime/JSFunction.cpp:

(JSC::JSFunction::prototypeForConstruction):
(JSC::JSFunction::allocateAndInitializeRareData):
(JSC::JSFunction::initializeRareData):
(JSC::JSFunction::getOwnPropertySlot):

  • runtime/JSFunction.h:
  • runtime/JSMap.cpp:

(JSC::JSMap::isIteratorProtocolFastAndNonObservable):
(JSC::JSMap::canCloneFastAndNonObservable):

  • runtime/JSObject.cpp:

(JSC::JSObject::putInlineSlow):
(JSC::JSObject::createInitialIndexedStorage):
(JSC::JSObject::createArrayStorage):
(JSC::JSObject::convertUndecidedToArrayStorage):
(JSC::JSObject::convertInt32ToArrayStorage):
(JSC::JSObject::convertDoubleToArrayStorage):
(JSC::JSObject::convertContiguousToArrayStorage):
(JSC::JSObject::ensureInt32Slow):
(JSC::JSObject::ensureDoubleSlow):
(JSC::JSObject::ensureContiguousSlow):
(JSC::JSObject::ensureArrayStorageSlow):
(JSC::JSObject::setPrototypeDirect):
(JSC::JSObject::ordinaryToPrimitive const):
(JSC::JSObject::putByIndexBeyondVectorLength):
(JSC::JSObject::putDirectIndexSlowOrBeyondVectorLength):
(JSC::JSObject::getEnumerableLength):
(JSC::JSObject::anyObjectInChainMayInterceptIndexedAccesses const):
(JSC::JSObject::prototypeChainMayInterceptStoreTo):
(JSC::JSObject::needsSlowPutIndexing const):
(JSC::JSObject::suggestedArrayStorageTransition const):

  • runtime/JSObject.h:

(JSC::JSObject::finishCreation):
(JSC::JSObject::getPrototypeDirect const):
(JSC::JSObject::getPropertySlot):

  • runtime/JSObjectInlines.h:

(JSC::JSObject::getPropertySlot):
(JSC::JSObject::getNonIndexPropertySlot):
(JSC::JSObject::putInlineForJSObject):

  • runtime/JSPropertyNameEnumerator.h:

(JSC::propertyNameEnumerator):

  • runtime/JSSet.cpp:

(JSC::JSSet::isIteratorProtocolFastAndNonObservable):
(JSC::JSSet::canCloneFastAndNonObservable):

  • runtime/LazyClassStructure.h:

(JSC::LazyClassStructure::prototypeConcurrently const): Deleted.

  • runtime/Operations.cpp:

(JSC::normalizePrototypeChain):

  • runtime/Operations.h:
  • runtime/Options.h:
  • runtime/PrototypeMap.cpp:

(JSC::PrototypeMap::createEmptyStructure):
(JSC::PrototypeMap::emptyStructureForPrototypeFromBaseStructure):
(JSC::PrototypeMap::emptyObjectStructureForPrototype):
(JSC::PrototypeMap::clearEmptyObjectStructureForPrototype):

  • runtime/PrototypeMap.h:
  • runtime/Structure.cpp:

(JSC::Structure::Structure):
(JSC::Structure::create):
(JSC::Structure::holesMustForwardToPrototype const):
(JSC::Structure::changePrototypeTransition):
(JSC::Structure::isCheapDuringGC):
(JSC::Structure::toStructureShape):
(JSC::Structure::dump const):
(JSC::Structure::canCachePropertyNameEnumerator const):
(JSC::Structure::anyObjectInChainMayInterceptIndexedAccesses const): Deleted.
(JSC::Structure::needsSlowPutIndexing const): Deleted.
(JSC::Structure::suggestedArrayStorageTransition const): Deleted.
(JSC::Structure::prototypeForLookup const): Deleted.
(JSC::Structure::prototypeChainMayInterceptStoreTo): Deleted.
(JSC::Structure::canUseForAllocationsOf): Deleted.

  • runtime/Structure.h:
  • runtime/StructureChain.h:
  • runtime/StructureInlines.h:

(JSC::Structure::create):
(JSC::Structure::storedPrototypeObject const):
(JSC::Structure::storedPrototypeStructure const):
(JSC::Structure::storedPrototype const):
(JSC::prototypeForLookupPrimitiveImpl):
(JSC::Structure::prototypeForLookup const):
(JSC::Structure::prototypeChain const):
(JSC::Structure::isValid const):
(JSC::Structure::add):
(JSC::Structure::setPropertyTable):
(JSC::Structure::shouldConvertToPolyProto):

  • runtime/StructureRareData.h:
  • runtime/TypeProfilerLog.cpp:

(JSC::TypeProfilerLog::processLogEntries):

  • runtime/TypeSet.cpp:

(JSC::TypeSet::addTypeInformation):

  • runtime/TypeSet.h:
  • runtime/WriteBarrier.h:

(JSC::WriteBarrierBase<Unknown>::isInt32 const):

Source/WTF:

  • wtf/Box.h:

(WTF::Box::operator bool const):
(WTF::Box::operator bool): Deleted.
Make Box movable. Also ensure its operator bool doesn't do an atomic increment.

  • wtf/RefPtr.h:

(WTF::RefPtr::operator bool const):
Add explicit operator bool() for RefPtr.

Tools:

  • Scripts/run-jsc-stress-tests:
File:
1 edited

Legend:

Unmodified
Added
Removed
  • trunk/Source/JavaScriptCore/runtime/Structure.cpp

    r222590 r222827  
    189189    , m_transitionWatchpointSet(IsWatched)
    190190    , m_offset(invalidOffset)
     191    , m_propertyHash(0)
    191192{
    192193    setDictionaryKind(NoneDictionaryKind);
     
    221222    , m_transitionWatchpointSet(IsWatched)
    222223    , m_offset(invalidOffset)
     224    , m_propertyHash(0)
    223225{
    224226    setDictionaryKind(NoneDictionaryKind);
     
    248250    , m_inlineCapacity(previous->m_inlineCapacity)
    249251    , m_bitField(0)
    250     , m_prototype(vm, this, previous->storedPrototype())
     252    , m_prototype(vm, this, previous->m_prototype.get())
    251253    , m_classInfo(previous->m_classInfo)
    252254    , m_transitionWatchpointSet(IsWatched)
    253255    , m_offset(invalidOffset)
     256    , m_propertyHash(previous->m_propertyHash)
    254257{
    255258    setDictionaryKind(previous->dictionaryKind());
     
    297300}
    298301
     302Structure* Structure::create(PolyProtoTag, VM& vm, JSGlobalObject* globalObject, JSObject* prototype, const TypeInfo& typeInfo, const ClassInfo* classInfo, IndexingType indexingType, unsigned inlineCapacity)
     303{
     304    Structure* result = create(vm, globalObject, prototype, typeInfo, classInfo, indexingType, inlineCapacity);
     305
     306    unsigned oldOutOfLineCapacity = result->outOfLineCapacity();
     307    result->addPropertyWithoutTransition(
     308        vm, vm.propertyNames->builtinNames().underscoreProtoPrivateName(), static_cast<unsigned>(PropertyAttribute::DontEnum),
     309        [&] (const GCSafeConcurrentJSLocker&, PropertyOffset offset, PropertyOffset newLastOffset) {
     310            RELEASE_ASSERT(Structure::outOfLineCapacity(newLastOffset) == oldOutOfLineCapacity);
     311            RELEASE_ASSERT(isInlineOffset(offset));
     312            result->m_prototype.set(vm, result, jsNumber(offset));
     313            result->setLastOffset(newLastOffset);
     314        });
     315
     316    return result;
     317}
     318
    299319void Structure::findStructuresAndMapForMaterialization(Vector<Structure*, 8>& structures, Structure*& structure, PropertyTable*& table)
    300320{
     
    400420}
    401421
    402 bool Structure::anyObjectInChainMayInterceptIndexedAccesses() const
    403 {
    404     for (const Structure* current = this; ;) {
    405         if (current->mayInterceptIndexedAccesses())
    406             return true;
    407        
    408         JSValue prototype = current->storedPrototype();
    409         if (prototype.isNull())
    410             return false;
    411        
    412         current = asObject(prototype)->structure();
    413     }
    414 }
    415 
    416 bool Structure::holesMustForwardToPrototype(VM& vm) const
    417 {
     422bool Structure::holesMustForwardToPrototype(VM& vm, JSObject* base) const
     423{
     424    ASSERT(base->structure(vm) == this);
     425
    418426    if (this->mayInterceptIndexedAccesses())
    419427        return true;
    420428
    421     JSValue prototype = this->storedPrototype();
     429    JSValue prototype = this->storedPrototype(base);
    422430    if (!prototype.isObject())
    423431        return false;
     
    428436        if (hasIndexedProperties(object->indexingType()) || structure.mayInterceptIndexedAccesses())
    429437            return true;
    430         prototype = structure.storedPrototype();
     438        prototype = structure.storedPrototype(object);
    431439        if (!prototype.isObject())
    432440            return false;
     
    436444    RELEASE_ASSERT_NOT_REACHED();
    437445    return false;
    438 }
    439 
    440 bool Structure::needsSlowPutIndexing() const
    441 {
    442     return anyObjectInChainMayInterceptIndexedAccesses()
    443         || globalObject()->isHavingABadTime();
    444 }
    445 
    446 NonPropertyTransition Structure::suggestedArrayStorageTransition() const
    447 {
    448     if (needsSlowPutIndexing())
    449         return NonPropertyTransition::AllocateSlowPutArrayStorage;
    450    
    451     return NonPropertyTransition::AllocateArrayStorage;
    452446}
    453447
     
    554548Structure* Structure::changePrototypeTransition(VM& vm, Structure* structure, JSValue prototype)
    555549{
     550    ASSERT(prototype.isObject() || prototype.isNull());
     551
    556552    DeferGC deferGC(vm.heap);
    557553    Structure* transition = create(vm, structure);
     
    10691065}
    10701066
    1071 JSValue Structure::prototypeForLookup(CodeBlock* codeBlock) const
    1072 {
    1073     return prototypeForLookup(codeBlock->globalObject());
    1074 }
    1075 
    10761067void Structure::visitChildren(JSCell* cell, SlotVisitor& visitor)
    10771068{
     
    11111102   
    11121103    return (!m_globalObject || Heap::isMarkedConcurrently(m_globalObject.get()))
    1113         && (!storedPrototypeObject() || Heap::isMarkedConcurrently(storedPrototypeObject()));
     1104        && (hasPolyProto() || !storedPrototypeObject() || Heap::isMarkedConcurrently(storedPrototypeObject()));
    11141105}
    11151106
     
    11231114}
    11241115
    1125 bool Structure::prototypeChainMayInterceptStoreTo(VM& vm, PropertyName propertyName)
    1126 {
    1127     if (parseIndex(propertyName))
    1128         return anyObjectInChainMayInterceptIndexedAccesses();
    1129    
    1130     for (Structure* current = this; ;) {
    1131         JSValue prototype = current->storedPrototype();
    1132         if (prototype.isNull())
    1133             return false;
    1134        
    1135         current = prototype.asCell()->structure(vm);
    1136        
    1137         unsigned attributes;
    1138         PropertyOffset offset = current->get(vm, propertyName, attributes);
    1139         if (!JSC::isValidOffset(offset))
    1140             continue;
    1141        
    1142         if (attributes & (PropertyAttribute::ReadOnly | PropertyAttribute::Accessor))
    1143             return true;
    1144        
    1145         return false;
    1146     }
    1147 }
    1148 
    1149 Ref<StructureShape> Structure::toStructureShape(JSValue value)
     1116Ref<StructureShape> Structure::toStructureShape(JSValue value, bool& sawPolyProtoStructure)
    11501117{
    11511118    Ref<StructureShape> baseShape = StructureShape::create();
     
    11531120    Structure* curStructure = this;
    11541121    JSValue curValue = value;
     1122    sawPolyProtoStructure = false;
    11551123    while (curStructure) {
     1124        sawPolyProtoStructure |= curStructure->hasPolyProto();
    11561125        curStructure->forEachPropertyConcurrently(
    11571126            [&] (const PropertyMapEntry& entry) -> bool {
    1158                 curShape->addProperty(*entry.key);
     1127                if (!PropertyName(entry.key).isPrivateName())
     1128                    curShape->addProperty(*entry.key);
    11591129                return true;
    11601130            });
     
    11701140        curShape->markAsFinal();
    11711141
    1172         if (curStructure->storedPrototypeStructure()) {
    1173             auto newShape = StructureShape::create();
    1174             curShape->setProto(newShape.copyRef());
    1175             curShape = WTFMove(newShape);
    1176             curValue = curStructure->storedPrototype();
    1177         }
    1178 
    1179         curStructure = curStructure->storedPrototypeStructure();
     1142        if (!curValue.isObject())
     1143            break;
     1144
     1145        JSObject* object = asObject(curValue);
     1146        JSObject* prototypeObject = object->structure()->storedPrototypeObject(object);
     1147        if (!prototypeObject)
     1148            break;
     1149
     1150        auto newShape = StructureShape::create();
     1151        curShape->setProto(newShape.copyRef());
     1152        curShape = WTFMove(newShape);
     1153        curValue = prototypeObject;
     1154        curStructure = prototypeObject->structure();
    11801155    }
    11811156   
    11821157    return baseShape;
    1183 }
    1184 
    1185 bool Structure::canUseForAllocationsOf(Structure* other)
    1186 {
    1187     return inlineCapacity() == other->inlineCapacity()
    1188         && storedPrototype() == other->storedPrototype()
    1189         && objectInitializationBlob() == other->objectInitializationBlob();
    11901158}
    11911159
     
    12041172    out.print("}, ", IndexingTypeDump(indexingType()));
    12051173   
    1206     if (m_prototype.get().isCell())
     1174    if (hasPolyProto())
     1175        out.print(", PolyProto offset:", polyProtoOffset());
     1176    else if (m_prototype.get().isCell())
    12071177        out.print(", Proto:", RawPointer(m_prototype.get().asCell()));
    12081178
     
    12891259        if (!structure->get())
    12901260            break;
    1291         if (structure->get()->isDictionary())
    1292             return false;
    1293         if (structure->get()->typeInfo().overridesGetPropertyNames())
     1261        if (structure->get()->isDictionary() || structure->get()->typeInfo().overridesGetPropertyNames())
    12941262            return false;
    12951263        structure++;
Note: See TracChangeset for help on using the changeset viewer.