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/JSObject.cpp

    r222744 r222827  
    771771        if (isValidOffset(offset)) {
    772772            if (attributes & PropertyAttribute::ReadOnly) {
    773                 ASSERT(structure(vm)->prototypeChainMayInterceptStoreTo(vm, propertyName) || obj == this);
     773                ASSERT(this->prototypeChainMayInterceptStoreTo(vm, propertyName) || obj == this);
    774774                return typeError(exec, scope, slot.isStrictMode(), ASCIILiteral(ReadonlyPropertyWriteError));
    775775            }
     
    10171017    IndexingType oldType = indexingType();
    10181018    ASSERT_UNUSED(oldType, !hasIndexedProperties(oldType));
    1019     ASSERT(!structure()->needsSlowPutIndexing());
     1019    ASSERT(!needsSlowPutIndexing());
    10201020    ASSERT(!indexingShouldBeSparse());
    10211021    Structure* structure = this->structure(vm);
     
    11131113    Butterfly* newButterfly = createArrayStorageButterfly(vm, this, oldStructure, length, vectorLength, m_butterfly.getMayBeNull());
    11141114    ArrayStorage* result = newButterfly->arrayStorage();
    1115     Structure* newStructure = Structure::nonPropertyTransition(vm, oldStructure, oldStructure->suggestedArrayStorageTransition());
     1115    Structure* newStructure = Structure::nonPropertyTransition(vm, oldStructure, suggestedArrayStorageTransition());
    11161116    nukeStructureAndSetButterfly(vm, oldStructureID, newButterfly);
    11171117    setStructure(vm, newStructure);
     
    12081208ArrayStorage* JSObject::convertUndecidedToArrayStorage(VM& vm)
    12091209{
    1210     return convertUndecidedToArrayStorage(vm, structure(vm)->suggestedArrayStorageTransition());
     1210    return convertUndecidedToArrayStorage(vm, suggestedArrayStorageTransition());
    12111211}
    12121212
     
    12661266ArrayStorage* JSObject::convertInt32ToArrayStorage(VM& vm)
    12671267{
    1268     return convertInt32ToArrayStorage(vm, structure(vm)->suggestedArrayStorageTransition());
     1268    return convertInt32ToArrayStorage(vm, suggestedArrayStorageTransition());
    12691269}
    12701270
     
    13191319ArrayStorage* JSObject::convertDoubleToArrayStorage(VM& vm)
    13201320{
    1321     return convertDoubleToArrayStorage(vm, structure(vm)->suggestedArrayStorageTransition());
     1321    return convertDoubleToArrayStorage(vm, suggestedArrayStorageTransition());
    13221322}
    13231323
     
    13681368ArrayStorage* JSObject::convertContiguousToArrayStorage(VM& vm)
    13691369{
    1370     return convertContiguousToArrayStorage(vm, structure(vm)->suggestedArrayStorageTransition());
     1370    return convertContiguousToArrayStorage(vm, suggestedArrayStorageTransition());
    13711371}
    13721372
     
    14491449    switch (indexingType()) {
    14501450    case ALL_BLANK_INDEXING_TYPES:
    1451         if (UNLIKELY(indexingShouldBeSparse() || structure(vm)->needsSlowPutIndexing()))
     1451        if (UNLIKELY(indexingShouldBeSparse() || needsSlowPutIndexing()))
    14521452            return ContiguousJSValues();
    14531453        return createInitialInt32(vm, 0);
     
    14761476    switch (indexingType()) {
    14771477    case ALL_BLANK_INDEXING_TYPES:
    1478         if (UNLIKELY(indexingShouldBeSparse() || structure(vm)->needsSlowPutIndexing()))
     1478        if (UNLIKELY(indexingShouldBeSparse() || needsSlowPutIndexing()))
    14791479            return ContiguousDoubles();
    14801480        return createInitialDouble(vm, 0);
     
    15051505    switch (indexingType()) {
    15061506    case ALL_BLANK_INDEXING_TYPES:
    1507         if (UNLIKELY(indexingShouldBeSparse() || structure(vm)->needsSlowPutIndexing()))
     1507        if (UNLIKELY(indexingShouldBeSparse() || needsSlowPutIndexing()))
    15081508            return ContiguousJSValues();
    15091509        return createInitialContiguous(vm, 0);
     
    15421542    case ALL_UNDECIDED_INDEXING_TYPES:
    15431543        ASSERT(!indexingShouldBeSparse());
    1544         ASSERT(!structure(vm)->needsSlowPutIndexing());
     1544        ASSERT(!needsSlowPutIndexing());
    15451545        return convertUndecidedToArrayStorage(vm);
    15461546       
    15471547    case ALL_INT32_INDEXING_TYPES:
    15481548        ASSERT(!indexingShouldBeSparse());
    1549         ASSERT(!structure(vm)->needsSlowPutIndexing());
     1549        ASSERT(!needsSlowPutIndexing());
    15501550        return convertInt32ToArrayStorage(vm);
    15511551       
    15521552    case ALL_DOUBLE_INDEXING_TYPES:
    15531553        ASSERT(!indexingShouldBeSparse());
    1554         ASSERT(!structure(vm)->needsSlowPutIndexing());
     1554        ASSERT(!needsSlowPutIndexing());
    15551555        return convertDoubleToArrayStorage(vm);
    15561556       
    15571557    case ALL_CONTIGUOUS_INDEXING_TYPES:
    15581558        ASSERT(!indexingShouldBeSparse());
    1559         ASSERT(!structure(vm)->needsSlowPutIndexing());
     1559        ASSERT(!needsSlowPutIndexing());
    15601560        return convertContiguousToArrayStorage(vm);
    15611561       
     
    16351635        vm.prototypeMap.addPrototype(asObject(prototype));
    16361636   
    1637     Structure* newStructure = Structure::changePrototypeTransition(vm, structure(vm), prototype);
    1638     setStructure(vm, newStructure);
    1639    
    1640     if (!newStructure->anyObjectInChainMayInterceptIndexedAccesses())
     1637    if (structure(vm)->hasMonoProto()) {
     1638        Structure* newStructure = Structure::changePrototypeTransition(vm, structure(vm), prototype);
     1639        setStructure(vm, newStructure);
     1640    } else
     1641        putDirect(vm, structure(vm)->polyProtoOffset(), prototype);
     1642
     1643    if (!anyObjectInChainMayInterceptIndexedAccesses())
    16411644        return;
    16421645   
    16431646    if (vm.prototypeMap.isPrototype(this)) {
    1644         newStructure->globalObject()->haveABadTime(vm);
     1647        structure(vm)->globalObject()->haveABadTime(vm);
    16451648        return;
    16461649    }
     
    19531956    // Make sure that whatever default value methods there are on object's prototype chain are
    19541957    // being watched.
    1955     this->structure()->startWatchingInternalPropertiesIfNecessaryForEntireChain(vm);
     1958    for (const JSObject* object = this; object; object = object->structure(vm)->storedPrototypeObject(object))
     1959        object->structure(vm)->startWatchingInternalPropertiesIfNecessary(vm);
    19561960
    19571961    JSValue value;
     
    27282732                exec, i, value, shouldThrow, createArrayStorage(vm, 0, 0));
    27292733        }
    2730         if (structure(vm)->needsSlowPutIndexing()) {
     2734        if (needsSlowPutIndexing()) {
    27312735            // Convert the indexing type to the SlowPutArrayStorage and retry.
    27322736            createArrayStorage(vm, i + 1, getNewVectorLength(0, 0, 0, i + 1));
     
    28802884                exec, i, value, attributes, mode, createArrayStorage(vm, 0, 0));
    28812885        }
    2882         if (structure(vm)->needsSlowPutIndexing()) {
     2886        if (needsSlowPutIndexing()) {
    28832887            ArrayStorage* storage = createArrayStorage(vm, i + 1, getNewVectorLength(0, 0, 0, i + 1));
    28842888            storage->m_vector[i].set(vm, this, value);
     
    35603564    VM& vm = exec->vm();
    35613565    Structure* structure = object->structure(vm);
    3562     if (structure->holesMustForwardToPrototype(vm))
     3566    if (structure->holesMustForwardToPrototype(vm, object))
    35633567        return 0;
    35643568    switch (object->indexingType()) {
     
    36703674}
    36713675
     3676bool JSObject::anyObjectInChainMayInterceptIndexedAccesses() const
     3677{
     3678    VM& vm = *this->vm();
     3679    for (const JSObject* current = this; ;) {
     3680        if (current->structure(vm)->mayInterceptIndexedAccesses())
     3681            return true;
     3682       
     3683        JSValue prototype = current->getPrototypeDirect();
     3684        if (prototype.isNull())
     3685            return false;
     3686       
     3687        current = asObject(prototype);
     3688    }
     3689}
     3690
     3691bool JSObject::prototypeChainMayInterceptStoreTo(VM& vm, PropertyName propertyName)
     3692{
     3693    if (parseIndex(propertyName))
     3694        return anyObjectInChainMayInterceptIndexedAccesses();
     3695   
     3696    for (JSObject* current = this; ;) {
     3697        JSValue prototype = current->getPrototypeDirect();
     3698        if (prototype.isNull())
     3699            return false;
     3700       
     3701        current = asObject(prototype);
     3702       
     3703        unsigned attributes;
     3704        PropertyOffset offset = current->structure(vm)->get(vm, propertyName, attributes);
     3705        if (!JSC::isValidOffset(offset))
     3706            continue;
     3707       
     3708        if (attributes & (PropertyAttribute::ReadOnly | PropertyAttribute::Accessor))
     3709            return true;
     3710       
     3711        return false;
     3712    }
     3713}
     3714
     3715bool JSObject::needsSlowPutIndexing() const
     3716{
     3717    return anyObjectInChainMayInterceptIndexedAccesses() || globalObject()->isHavingABadTime();
     3718}
     3719
     3720NonPropertyTransition JSObject::suggestedArrayStorageTransition() const
     3721{
     3722    if (needsSlowPutIndexing())
     3723        return NonPropertyTransition::AllocateSlowPutArrayStorage;
     3724   
     3725    return NonPropertyTransition::AllocateArrayStorage;
     3726}
     3727
    36723728} // namespace JSC
Note: See TracChangeset for help on using the changeset viewer.