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/StructureInlines.h

    r222473 r222827  
    5252}
    5353
    54 inline Structure* Structure::create(VM& vm, Structure* structure, DeferredStructureTransitionWatchpointFire* deferred)
     54inline Structure* Structure::create(VM& vm, Structure* previous, DeferredStructureTransitionWatchpointFire* deferred)
    5555{
    5656    ASSERT(vm.structureStructure);
    57     Structure* newStructure = new (NotNull, allocateCell<Structure>(vm.heap)) Structure(vm, structure, deferred);
    58     newStructure->finishCreation(vm);
     57    Structure* newStructure = new (NotNull, allocateCell<Structure>(vm.heap)) Structure(vm, previous, deferred);
     58    newStructure->finishCreation(vm, previous);
    5959    return newStructure;
    6060}
     
    6262inline JSObject* Structure::storedPrototypeObject() const
    6363{
     64    RELEASE_ASSERT(hasMonoProto());
    6465    JSValue value = m_prototype.get();
    6566    if (value.isNull())
     
    7071inline Structure* Structure::storedPrototypeStructure() const
    7172{
     73    RELEASE_ASSERT(hasMonoProto());
    7274    JSObject* object = storedPrototypeObject();
    7375    if (!object)
    7476        return nullptr;
    7577    return object->structure();
     78}
     79
     80ALWAYS_INLINE JSValue Structure::storedPrototype(const JSObject* object) const
     81{
     82    RELEASE_ASSERT(object->structure() == this);
     83    if (hasMonoProto())
     84        return storedPrototype();
     85    RELEASE_ASSERT(m_prototype.get().isInt32());
     86    PropertyOffset offset = m_prototype.get().asInt32();
     87    return object->getDirect(offset);
     88}
     89
     90ALWAYS_INLINE JSObject* Structure::storedPrototypeObject(const JSObject* object) const
     91{
     92    RELEASE_ASSERT(object->structure() == this);
     93    if (hasMonoProto())
     94        return storedPrototypeObject();
     95    JSValue proto = object->getDirect(polyProtoOffset());
     96    if (proto.isNull())
     97        return nullptr;
     98    return asObject(proto);
     99}
     100
     101ALWAYS_INLINE Structure* Structure::storedPrototypeStructure(const JSObject* object) const
     102{
     103    if (JSObject* proto = storedPrototypeObject(object))
     104        return proto->structure();
     105    return nullptr;
    76106}
    77107
     
    167197}
    168198
     199ALWAYS_INLINE JSValue prototypeForLookupPrimitiveImpl(JSGlobalObject* globalObject, const Structure* structure)
     200{
     201    ASSERT(!structure->isObject());
     202
     203    if (structure->typeInfo().type() == StringType)
     204        return globalObject->stringPrototype();
     205
     206    ASSERT(structure->typeInfo().type() == SymbolType);
     207    return globalObject->symbolPrototype();
     208
     209}
     210
    169211inline JSValue Structure::prototypeForLookup(JSGlobalObject* globalObject) const
    170212{
     213    RELEASE_ASSERT(hasMonoProto());
    171214    if (isObject())
    172         return m_prototype.get();
    173     if (typeInfo().type() == SymbolType)
    174         return globalObject->symbolPrototype();
    175 
    176     ASSERT(typeInfo().type() == StringType);
    177     return globalObject->stringPrototype();
    178 }
    179 
    180 inline JSValue Structure::prototypeForLookup(ExecState* exec) const
    181 {
    182     return prototypeForLookup(exec->lexicalGlobalObject());
    183 }
    184 
    185 inline StructureChain* Structure::prototypeChain(VM& vm, JSGlobalObject* globalObject) const
    186 {
     215        return storedPrototype();
     216    return prototypeForLookupPrimitiveImpl(globalObject, this);
     217}
     218
     219inline JSValue Structure::prototypeForLookup(JSGlobalObject* globalObject, JSCell* base) const
     220{
     221    RELEASE_ASSERT(base->structure() == this);
     222    if (isObject())
     223        return storedPrototype(asObject(base));
     224    return prototypeForLookupPrimitiveImpl(globalObject, this);
     225}
     226
     227inline StructureChain* Structure::prototypeChain(VM& vm, JSGlobalObject* globalObject, JSObject* base) const
     228{
     229    RELEASE_ASSERT(base->structure(vm) == this);
    187230    // We cache our prototype chain so our clients can share it.
    188     if (!isValid(globalObject, m_cachedPrototypeChain.get())) {
    189         JSValue prototype = prototypeForLookup(globalObject);
    190         m_cachedPrototypeChain.set(vm, this, StructureChain::create(vm, prototype.isNull() ? 0 : asObject(prototype)->structure()));
     231    if (!isValid(globalObject, m_cachedPrototypeChain.get(), base)) {
     232        JSValue prototype = prototypeForLookup(globalObject, base);
     233        m_cachedPrototypeChain.set(vm, this, StructureChain::create(vm, prototype.isNull() ? nullptr : asObject(prototype)));
    191234    }
    192235    return m_cachedPrototypeChain.get();
    193236}
    194237
    195 inline StructureChain* Structure::prototypeChain(ExecState* exec) const
    196 {
    197     return prototypeChain(exec->vm(), exec->lexicalGlobalObject());
    198 }
    199 
    200 inline bool Structure::isValid(JSGlobalObject* globalObject, StructureChain* cachedPrototypeChain) const
     238inline StructureChain* Structure::prototypeChain(ExecState* exec, JSObject* base) const
     239{
     240    return prototypeChain(exec->vm(), exec->lexicalGlobalObject(), base);
     241}
     242
     243inline bool Structure::isValid(JSGlobalObject* globalObject, StructureChain* cachedPrototypeChain, JSObject* base) const
    201244{
    202245    if (!cachedPrototypeChain)
    203246        return false;
    204247
    205     JSValue prototype = prototypeForLookup(globalObject);
     248    JSValue prototype = prototypeForLookup(globalObject, base);
    206249    WriteBarrier<Structure>* cachedStructure = cachedPrototypeChain->head();
    207250    while (*cachedStructure && !prototype.isNull()) {
     
    212255    }
    213256    return prototype.isNull() && !*cachedStructure;
    214 }
    215 
    216 inline bool Structure::isValid(ExecState* exec, StructureChain* cachedPrototypeChain) const
    217 {
    218     return isValid(exec->lexicalGlobalObject(), cachedPrototypeChain);
    219257}
    220258
     
    342380
    343381    PropertyOffset newOffset = table->nextOffset(m_inlineCapacity);
     382
     383    m_propertyHash = m_propertyHash ^ rep->existingSymbolAwareHash();
    344384   
    345385    PropertyOffset newLastOffset = m_offset;
     
    401441}
    402442
    403 inline void Structure::setPropertyTable(VM& vm, PropertyTable* table)
     443ALWAYS_INLINE void Structure::setPropertyTable(VM& vm, PropertyTable* table)
    404444{
    405445    m_propertyTableUnsafe.setMayBeNull(vm, this, table);
    406446}
     447
     448ALWAYS_INLINE bool Structure::shouldConvertToPolyProto(const Structure* a, const Structure* b)
     449{
     450    if (!a || !b)
     451        return false;
     452
     453    if (a == b)
     454        return false;
     455
     456    if (a->propertyHash() != b->propertyHash())
     457        return false;
     458
     459    // We only care about objects created via a constructor's to_this. These
     460    // all have Structures with rare data and a sharedPolyProtoWatchpoint.
     461    if (!a->hasRareData() || !b->hasRareData())
     462        return false;
     463
     464    // We only care about Structure's generated from functions that share
     465    // the same executable.
     466    const Box<InlineWatchpointSet>& aInlineWatchpointSet = a->rareData()->sharedPolyProtoWatchpoint();
     467    const Box<InlineWatchpointSet>& bInlineWatchpointSet = b->rareData()->sharedPolyProtoWatchpoint();
     468    if (aInlineWatchpointSet.get() != bInlineWatchpointSet.get() || !aInlineWatchpointSet)
     469        return false;
     470    ASSERT(aInlineWatchpointSet && bInlineWatchpointSet && aInlineWatchpointSet.get() == bInlineWatchpointSet.get());
     471
     472    if (a->hasPolyProto() || b->hasPolyProto())
     473        return false;
     474
     475    if (a->storedPrototype() == b->storedPrototype())
     476        return false;
     477
     478    VM& vm = *a->vm();
     479    JSObject* aObj = a->storedPrototypeObject();
     480    JSObject* bObj = b->storedPrototypeObject();
     481    while (aObj && bObj) {
     482        a = aObj->structure(vm);
     483        b = bObj->structure(vm);
     484
     485        if (a->propertyHash() != b->propertyHash())
     486            return false;
     487
     488        aObj = a->storedPrototypeObject(aObj);
     489        bObj = b->storedPrototypeObject(bObj);
     490    }
     491
     492    return !aObj && !bObj;
     493}
    407494   
    408495} // namespace JSC
Note: See TracChangeset for help on using the changeset viewer.