Ignore:
Timestamp:
Sep 12, 2012, 9:18:52 PM (13 years ago)
Author:
[email protected]
Message:

JSC should have property butterflies
https://bugs.webkit.org/show_bug.cgi?id=91933

Reviewed by Geoffrey Garen.

Source/JavaScriptCore:

This changes the JSC object model. Previously, all objects had fast lookup for
named properties. Integer indexed properties were only fast if you used a
JSArray. With this change, all objects have fast indexed properties. This is
accomplished without any space overhead by using a bidirectional object layout,
aka butterflies. Each JSObject has a m_butterfly pointer where previously it
had a m_outOfLineStorage pointer. To the left of the location pointed to by
m_butterfly, we place all named out-of-line properties. To the right, we place
all indexed properties along with indexing meta-data. Though, some indexing
meta-data is placed in the 8-byte word immediately left of the pointed-to
location; this is in anticipation of the indexing meta-data being small enough
in the common case that m_butterfly always points to the first indexed
property.

This is performance neutral, except on tests that use indexed properties on
plain objects, where the speed-up is in excess of an order of magnitude.

One notable aspect of what this change brings is that it allows indexing
storage to morph over time. Currently this is only used to allow all non-array
objects to start out without any indexed storage. But it could be used for
some kinds of array type inference in the future.

  • API/JSCallbackObject.h:

(JSCallbackObject):

  • API/JSCallbackObjectFunctions.h:

(JSC::::getOwnPropertySlotByIndex):
(JSC):
(JSC::::getOwnNonIndexPropertyNames):

  • API/JSObjectRef.cpp:
  • CMakeLists.txt:
  • GNUmakefile.list.am:
  • JavaScriptCore.vcproj/JavaScriptCore/JavaScriptCore.def:
  • JavaScriptCore.vcproj/JavaScriptCore/JavaScriptCore.vcproj:
  • JavaScriptCore.xcodeproj/project.pbxproj:
  • Target.pri:
  • bytecode/ArrayProfile.h:

(JSC):
(JSC::arrayModeFromStructure):

  • bytecompiler/BytecodeGenerator.cpp:

(JSC::BytecodeGenerator::emitDirectPutById):

  • dfg/DFGAbstractState.cpp:

(JSC::DFG::AbstractState::execute):

  • dfg/DFGAdjacencyList.h:

(JSC::DFG::AdjacencyList::AdjacencyList):
(AdjacencyList):

  • dfg/DFGArrayMode.cpp:

(JSC::DFG::fromObserved):
(JSC::DFG::modeAlreadyChecked):
(JSC::DFG::modeToString):

  • dfg/DFGArrayMode.h:

(DFG):
(JSC::DFG::modeUsesButterfly):
(JSC::DFG::modeIsJSArray):
(JSC::DFG::isInBoundsAccess):
(JSC::DFG::modeSupportsLength):

  • dfg/DFGByteCodeParser.cpp:

(JSC::DFG::ByteCodeParser::handleGetByOffset):
(JSC::DFG::ByteCodeParser::parseBlock):

  • dfg/DFGCSEPhase.cpp:

(JSC::DFG::CSEPhase::getPropertyStorageLoadElimination):
(JSC::DFG::CSEPhase::performNodeCSE):

  • dfg/DFGFixupPhase.cpp:

(JSC::DFG::FixupPhase::fixupNode):
(JSC::DFG::FixupPhase::addNode):
(FixupPhase):
(JSC::DFG::FixupPhase::checkArray):

  • dfg/DFGGraph.h:

(JSC::DFG::Graph::byValIsPure):

  • dfg/DFGNode.h:

(JSC::DFG::Node::Node):
(Node):

  • dfg/DFGNodeType.h:

(DFG):

  • dfg/DFGOperations.cpp:

(JSC::DFG::putByVal):

  • dfg/DFGOperations.h:
  • dfg/DFGPredictionPropagationPhase.cpp:

(JSC::DFG::PredictionPropagationPhase::propagate):

  • dfg/DFGRepatch.cpp:

(JSC::DFG::generateProtoChainAccessStub):
(JSC::DFG::tryCacheGetByID):
(JSC::DFG::tryBuildGetByIDList):
(JSC::DFG::emitPutReplaceStub):
(JSC::DFG::emitPutTransitionStub):
(JSC::DFG::tryBuildPutByIdList):

  • dfg/DFGSpeculativeJIT.cpp:

(JSC::DFG::SpeculativeJIT::checkArray):
(JSC::DFG::SpeculativeJIT::compileGetIndexedPropertyStorage):
(JSC::DFG::SpeculativeJIT::compileGetArrayLength):
(JSC::DFG::SpeculativeJIT::compileAllocatePropertyStorage):
(JSC::DFG::SpeculativeJIT::compileReallocatePropertyStorage):

  • dfg/DFGSpeculativeJIT.h:

(JSC::DFG::SpeculativeJIT::callOperation):
(JSC::DFG::SpeculativeJIT::emitAllocateBasicJSObject):

  • dfg/DFGSpeculativeJIT32_64.cpp:

(JSC::DFG::SpeculativeJIT::cachedGetById):
(JSC::DFG::SpeculativeJIT::cachedPutById):
(JSC::DFG::SpeculativeJIT::compile):

  • dfg/DFGSpeculativeJIT64.cpp:

(JSC::DFG::SpeculativeJIT::cachedGetById):
(JSC::DFG::SpeculativeJIT::cachedPutById):
(JSC::DFG::SpeculativeJIT::compile):

  • dfg/DFGStructureCheckHoistingPhase.cpp:

(JSC::DFG::StructureCheckHoistingPhase::run):

  • heap/CopiedSpace.h:

(CopiedSpace):

  • jit/JIT.h:
  • jit/JITInlineMethods.h:

(JSC::JIT::emitAllocateBasicJSObject):
(JSC::JIT::emitAllocateBasicStorage):
(JSC::JIT::emitAllocateJSArray):

  • jit/JITOpcodes.cpp:

(JSC::JIT::emit_op_new_array):
(JSC::JIT::emitSlow_op_new_array):

  • jit/JITPropertyAccess.cpp:

(JSC::JIT::emit_op_get_by_val):
(JSC::JIT::compileGetDirectOffset):
(JSC::JIT::emit_op_put_by_val):
(JSC::JIT::compileGetByIdHotPath):
(JSC::JIT::emit_op_put_by_id):
(JSC::JIT::compilePutDirectOffset):
(JSC::JIT::privateCompilePatchGetArrayLength):

  • jit/JITPropertyAccess32_64.cpp:

(JSC::JIT::emit_op_get_by_val):
(JSC::JIT::emit_op_put_by_val):
(JSC::JIT::compileGetByIdHotPath):
(JSC::JIT::emit_op_put_by_id):
(JSC::JIT::compilePutDirectOffset):
(JSC::JIT::compileGetDirectOffset):
(JSC::JIT::privateCompilePatchGetArrayLength):

  • jit/JITStubs.cpp:

(JSC::DEFINE_STUB_FUNCTION):

  • jsc.cpp:
  • llint/LLIntSlowPaths.cpp:

(JSC::LLInt::LLINT_SLOW_PATH_DECL):

  • llint/LowLevelInterpreter.asm:
  • llint/LowLevelInterpreter32_64.asm:
  • llint/LowLevelInterpreter64.asm:
  • runtime/Arguments.cpp:

(JSC::Arguments::deletePropertyByIndex):
(JSC::Arguments::defineOwnProperty):

  • runtime/ArrayConstructor.cpp:
  • runtime/ArrayConventions.h: Added.

(JSC):
(JSC::isDenseEnoughForVector):
(JSC::indexingHeaderForArray):
(JSC::baseIndexingHeaderForArray):

  • runtime/ArrayPrototype.cpp:

(JSC::ArrayPrototype::create):
(JSC):
(JSC::ArrayPrototype::ArrayPrototype):
(JSC::arrayProtoFuncToString):
(JSC::arrayProtoFuncJoin):
(JSC::arrayProtoFuncSort):
(JSC::arrayProtoFuncFilter):
(JSC::arrayProtoFuncMap):
(JSC::arrayProtoFuncEvery):
(JSC::arrayProtoFuncForEach):
(JSC::arrayProtoFuncSome):
(JSC::arrayProtoFuncReduce):
(JSC::arrayProtoFuncReduceRight):

  • runtime/ArrayPrototype.h:

(ArrayPrototype):
(JSC::ArrayPrototype::createStructure):

  • runtime/ArrayStorage.h: Added.

(JSC):
(ArrayStorage):
(JSC::ArrayStorage::ArrayStorage):
(JSC::ArrayStorage::from):
(JSC::ArrayStorage::butterfly):
(JSC::ArrayStorage::indexingHeader):
(JSC::ArrayStorage::length):
(JSC::ArrayStorage::setLength):
(JSC::ArrayStorage::vectorLength):
(JSC::ArrayStorage::setVectorLength):
(JSC::ArrayStorage::copyHeaderFromDuringGC):
(JSC::ArrayStorage::inSparseMode):
(JSC::ArrayStorage::lengthOffset):
(JSC::ArrayStorage::vectorLengthOffset):
(JSC::ArrayStorage::numValuesInVectorOffset):
(JSC::ArrayStorage::vectorOffset):
(JSC::ArrayStorage::indexBiasOffset):
(JSC::ArrayStorage::sparseMapOffset):
(JSC::ArrayStorage::sizeFor):

  • runtime/Butterfly.h: Added.

(JSC):
(Butterfly):
(JSC::Butterfly::Butterfly):
(JSC::Butterfly::totalSize):
(JSC::Butterfly::fromBase):
(JSC::Butterfly::offsetOfIndexingHeader):
(JSC::Butterfly::offsetOfPublicLength):
(JSC::Butterfly::offsetOfVectorLength):
(JSC::Butterfly::indexingHeader):
(JSC::Butterfly::propertyStorage):
(JSC::Butterfly::indexingPayload):
(JSC::Butterfly::arrayStorage):
(JSC::Butterfly::offsetOfPropertyStorage):
(JSC::Butterfly::indexOfPropertyStorage):
(JSC::Butterfly::base):

  • runtime/ButterflyInlineMethods.h: Added.

(JSC):
(JSC::Butterfly::createUninitialized):
(JSC::Butterfly::create):
(JSC::Butterfly::createUninitializedDuringCollection):
(JSC::Butterfly::base):
(JSC::Butterfly::growPropertyStorage):
(JSC::Butterfly::growArrayRight):
(JSC::Butterfly::resizeArray):
(JSC::Butterfly::unshift):
(JSC::Butterfly::shift):

  • runtime/ClassInfo.h:

(MethodTable):
(JSC):

  • runtime/IndexingHeader.h: Added.

(JSC):
(IndexingHeader):
(JSC::IndexingHeader::offsetOfIndexingHeader):
(JSC::IndexingHeader::offsetOfPublicLength):
(JSC::IndexingHeader::offsetOfVectorLength):
(JSC::IndexingHeader::IndexingHeader):
(JSC::IndexingHeader::vectorLength):
(JSC::IndexingHeader::setVectorLength):
(JSC::IndexingHeader::publicLength):
(JSC::IndexingHeader::setPublicLength):
(JSC::IndexingHeader::from):
(JSC::IndexingHeader::fromEndOf):
(JSC::IndexingHeader::propertyStorage):
(JSC::IndexingHeader::arrayStorage):
(JSC::IndexingHeader::butterfly):

  • runtime/IndexingHeaderInlineMethods.h: Added.

(JSC):
(JSC::IndexingHeader::preCapacity):
(JSC::IndexingHeader::indexingPayloadSizeInBytes):

  • runtime/IndexingType.h: Added.

(JSC):
(JSC::hasIndexingHeader):

  • runtime/JSActivation.cpp:

(JSC::JSActivation::JSActivation):
(JSC::JSActivation::visitChildren):
(JSC::JSActivation::getOwnNonIndexPropertyNames):

  • runtime/JSActivation.h:

(JSActivation):
(JSC::JSActivation::tearOff):

  • runtime/JSArray.cpp:

(JSC):
(JSC::createArrayButterflyInDictionaryIndexingMode):
(JSC::JSArray::setLengthWritable):
(JSC::JSArray::defineOwnProperty):
(JSC::JSArray::getOwnPropertySlot):
(JSC::JSArray::getOwnPropertyDescriptor):
(JSC::JSArray::put):
(JSC::JSArray::deleteProperty):
(JSC::JSArray::getOwnNonIndexPropertyNames):
(JSC::JSArray::unshiftCountSlowCase):
(JSC::JSArray::setLength):
(JSC::JSArray::pop):
(JSC::JSArray::push):
(JSC::JSArray::shiftCount):
(JSC::JSArray::unshiftCount):
(JSC::JSArray::sortNumeric):
(JSC::JSArray::sort):
(JSC::JSArray::fillArgList):
(JSC::JSArray::copyToArguments):
(JSC::JSArray::compactForSorting):

  • runtime/JSArray.h:

(JSC):
(JSArray):
(JSC::JSArray::JSArray):
(JSC::JSArray::length):
(JSC::JSArray::createStructure):
(JSC::JSArray::isLengthWritable):
(JSC::createArrayButterfly):
(JSC::JSArray::create):
(JSC::JSArray::tryCreateUninitialized):

  • runtime/JSBoundFunction.cpp:

(JSC::boundFunctionCall):
(JSC::boundFunctionConstruct):
(JSC::JSBoundFunction::finishCreation):

  • runtime/JSCell.cpp:

(JSC::JSCell::getOwnNonIndexPropertyNames):
(JSC):

  • runtime/JSCell.h:

(JSCell):

  • runtime/JSFunction.cpp:

(JSC::JSFunction::getOwnPropertySlot):
(JSC::JSFunction::getOwnPropertyDescriptor):
(JSC::JSFunction::getOwnNonIndexPropertyNames):
(JSC::JSFunction::defineOwnProperty):

  • runtime/JSFunction.h:

(JSFunction):

  • runtime/JSGlobalData.cpp:

(JSC::JSGlobalData::JSGlobalData):

  • runtime/JSGlobalData.h:

(JSGlobalData):

  • runtime/JSGlobalObject.cpp:

(JSC::JSGlobalObject::reset):

  • runtime/JSONObject.cpp:

(JSC::Stringifier::Holder::appendNextProperty):
(JSC::Walker::walk):

  • runtime/JSObject.cpp:

(JSC):
(JSC::JSObject::visitButterfly):
(JSC::JSObject::visitChildren):
(JSC::JSFinalObject::visitChildren):
(JSC::JSObject::getOwnPropertySlotByIndex):
(JSC::JSObject::put):
(JSC::JSObject::putByIndex):
(JSC::JSObject::enterDictionaryIndexingModeWhenArrayStorageAlreadyExists):
(JSC::JSObject::enterDictionaryIndexingMode):
(JSC::JSObject::createArrayStorage):
(JSC::JSObject::createInitialArrayStorage):
(JSC::JSObject::ensureArrayStorageExistsAndEnterDictionaryIndexingMode):
(JSC::JSObject::putDirectAccessor):
(JSC::JSObject::deleteProperty):
(JSC::JSObject::deletePropertyByIndex):
(JSC::JSObject::getOwnPropertyNames):
(JSC::JSObject::getOwnNonIndexPropertyNames):
(JSC::JSObject::preventExtensions):
(JSC::JSObject::fillGetterPropertySlot):
(JSC::JSObject::putIndexedDescriptor):
(JSC::JSObject::defineOwnIndexedProperty):
(JSC::JSObject::allocateSparseIndexMap):
(JSC::JSObject::deallocateSparseIndexMap):
(JSC::JSObject::putByIndexBeyondVectorLengthWithArrayStorage):
(JSC::JSObject::putByIndexBeyondVectorLength):
(JSC::JSObject::putDirectIndexBeyondVectorLengthWithArrayStorage):
(JSC::JSObject::putDirectIndexBeyondVectorLength):
(JSC::JSObject::getNewVectorLength):
(JSC::JSObject::increaseVectorLength):
(JSC::JSObject::checkIndexingConsistency):
(JSC::JSObject::growOutOfLineStorage):
(JSC::JSObject::getOwnPropertyDescriptor):
(JSC::putDescriptor):
(JSC::JSObject::putDirectMayBeIndex):
(JSC::JSObject::defineOwnNonIndexProperty):
(JSC::JSObject::defineOwnProperty):
(JSC::JSObject::getOwnPropertySlotSlow):

  • runtime/JSObject.h:

(JSC::JSObject::getArrayLength):
(JSObject):
(JSC::JSObject::getVectorLength):
(JSC::JSObject::putDirectIndex):
(JSC::JSObject::canGetIndexQuickly):
(JSC::JSObject::getIndexQuickly):
(JSC::JSObject::canSetIndexQuickly):
(JSC::JSObject::setIndexQuickly):
(JSC::JSObject::initializeIndex):
(JSC::JSObject::completeInitialization):
(JSC::JSObject::inSparseIndexingMode):
(JSC::JSObject::butterfly):
(JSC::JSObject::outOfLineStorage):
(JSC::JSObject::offsetForLocation):
(JSC::JSObject::indexingShouldBeSparse):
(JSC::JSObject::butterflyOffset):
(JSC::JSObject::butterflyAddress):
(JSC::JSObject::arrayStorage):
(JSC::JSObject::arrayStorageOrZero):
(JSC::JSObject::ensureArrayStorage):
(JSC::JSObject::checkIndexingConsistency):
(JSC::JSNonFinalObject::JSNonFinalObject):
(JSC):
(JSC::JSObject::setButterfly):
(JSC::JSObject::setButterflyWithoutChangingStructure):
(JSC::JSObject::JSObject):
(JSC::JSObject::inlineGetOwnPropertySlot):
(JSC::JSObject::putDirectInternal):
(JSC::JSObject::setStructureAndReallocateStorageIfNecessary):
(JSC::JSObject::putDirectWithoutTransition):
(JSC::offsetInButterfly):
(JSC::offsetRelativeToPatchedStorage):
(JSC::indexRelativeToBase):
(JSC::offsetRelativeToBase):

  • runtime/JSPropertyNameIterator.cpp:

(JSC::JSPropertyNameIterator::create):

  • runtime/JSSymbolTableObject.cpp:

(JSC::JSSymbolTableObject::getOwnNonIndexPropertyNames):

  • runtime/JSSymbolTableObject.h:

(JSSymbolTableObject):

  • runtime/JSTypeInfo.h:

(JSC):
(JSC::TypeInfo::interceptsGetOwnPropertySlotByIndexEvenWhenLengthIsNotZero):
(JSC::TypeInfo::overridesGetPropertyNames):

  • runtime/LiteralParser.cpp:

(JSC::::parse):

  • runtime/ObjectConstructor.cpp:
  • runtime/ObjectPrototype.cpp:

(JSC::ObjectPrototype::ObjectPrototype):
(JSC):

  • runtime/ObjectPrototype.h:

(ObjectPrototype):

  • runtime/PropertyOffset.h:

(JSC::offsetInOutOfLineStorage):

  • runtime/PropertyStorage.h: Added.

(JSC):

  • runtime/PutDirectIndexMode.h: Added.

(JSC):

  • runtime/RegExpMatchesArray.cpp:

(JSC::RegExpMatchesArray::RegExpMatchesArray):
(JSC):
(JSC::RegExpMatchesArray::create):
(JSC::RegExpMatchesArray::finishCreation):

  • runtime/RegExpMatchesArray.h:

(RegExpMatchesArray):
(JSC::RegExpMatchesArray::createStructure):

  • runtime/RegExpObject.cpp:

(JSC::RegExpObject::getOwnNonIndexPropertyNames):

  • runtime/RegExpObject.h:

(RegExpObject):

  • runtime/Reject.h: Added.

(JSC):
(JSC::reject):

  • runtime/SparseArrayValueMap.cpp: Added.

(JSC):

  • runtime/SparseArrayValueMap.h: Added.

(JSC):
(SparseArrayEntry):
(JSC::SparseArrayEntry::SparseArrayEntry):
(SparseArrayValueMap):
(JSC::SparseArrayValueMap::sparseMode):
(JSC::SparseArrayValueMap::setSparseMode):
(JSC::SparseArrayValueMap::lengthIsReadOnly):
(JSC::SparseArrayValueMap::setLengthIsReadOnly):
(JSC::SparseArrayValueMap::find):
(JSC::SparseArrayValueMap::remove):
(JSC::SparseArrayValueMap::notFound):
(JSC::SparseArrayValueMap::isEmpty):
(JSC::SparseArrayValueMap::contains):
(JSC::SparseArrayValueMap::size):
(JSC::SparseArrayValueMap::begin):
(JSC::SparseArrayValueMap::end):

  • runtime/SparseArrayValueMapInlineMethods.h: Added.

(JSC):
(JSC::SparseArrayValueMap::SparseArrayValueMap):
(JSC::SparseArrayValueMap::~SparseArrayValueMap):
(JSC::SparseArrayValueMap::finishCreation):
(JSC::SparseArrayValueMap::create):
(JSC::SparseArrayValueMap::destroy):
(JSC::SparseArrayValueMap::createStructure):
(JSC::SparseArrayValueMap::add):
(JSC::SparseArrayValueMap::putEntry):
(JSC::SparseArrayValueMap::putDirect):
(JSC::SparseArrayEntry::get):
(JSC::SparseArrayEntry::getNonSparseMode):
(JSC::SparseArrayValueMap::visitChildren):

  • runtime/StorageBarrier.h: Removed.
  • runtime/StringObject.cpp:

(JSC::StringObject::putByIndex):
(JSC):
(JSC::StringObject::deletePropertyByIndex):

  • runtime/StringObject.h:

(StringObject):

  • runtime/StringPrototype.cpp:
  • runtime/Structure.cpp:

(JSC::Structure::Structure):
(JSC::Structure::materializePropertyMap):
(JSC::Structure::nonPropertyTransition):
(JSC):

  • runtime/Structure.h:

(Structure):
(JSC::Structure::indexingType):
(JSC::Structure::indexingTypeIncludingHistory):
(JSC::Structure::indexingTypeOffset):
(JSC::Structure::create):

  • runtime/StructureTransitionTable.h:

(JSC):
(JSC::toAttributes):
(JSC::newIndexingType):
(JSC::StructureTransitionTable::Hash::hash):

  • tests/mozilla/js1_6/Array/regress-304828.js:

Source/WebCore:

Teach the DOM that to intercept get/put on indexed properties, you now have
to override getOwnPropertySlotByIndex and putByIndex.

No new tests because no new behavior. One test was rebased because indexed
property iteration order now matches other engines (indexed properties always
come first).

  • bindings/js/ArrayValue.cpp:

(WebCore::ArrayValue::get):

  • bindings/js/JSBlobCustom.cpp:

(WebCore::JSBlobConstructor::constructJSBlob):

  • bindings/js/JSCanvasRenderingContext2DCustom.cpp:

(WebCore::JSCanvasRenderingContext2D::setWebkitLineDash):

  • bindings/js/JSDOMStringListCustom.cpp:

(WebCore::toDOMStringList):

  • bindings/js/JSDOMStringMapCustom.cpp:

(WebCore::JSDOMStringMap::deletePropertyByIndex):
(WebCore):

  • bindings/js/JSDOMWindowCustom.cpp:

(WebCore::JSDOMWindow::getOwnPropertySlot):
(WebCore::JSDOMWindow::getOwnPropertySlotByIndex):
(WebCore):
(WebCore::JSDOMWindow::putByIndex):
(WebCore::JSDOMWindow::deletePropertyByIndex):

  • bindings/js/JSDOMWindowShell.cpp:

(WebCore::JSDOMWindowShell::getOwnPropertySlotByIndex):
(WebCore):
(WebCore::JSDOMWindowShell::putByIndex):
(WebCore::JSDOMWindowShell::deletePropertyByIndex):

  • bindings/js/JSDOMWindowShell.h:

(JSDOMWindowShell):

  • bindings/js/JSHistoryCustom.cpp:

(WebCore::JSHistory::deletePropertyByIndex):
(WebCore):

  • bindings/js/JSInspectorFrontendHostCustom.cpp:

(WebCore::populateContextMenuItems):

  • bindings/js/JSLocationCustom.cpp:

(WebCore::JSLocation::deletePropertyByIndex):
(WebCore):

  • bindings/js/JSStorageCustom.cpp:

(WebCore::JSStorage::deletePropertyByIndex):
(WebCore):

  • bindings/js/JSWebSocketCustom.cpp:

(WebCore::JSWebSocketConstructor::constructJSWebSocket):

  • bindings/js/ScriptValue.cpp:

(WebCore::jsToInspectorValue):

  • bindings/js/SerializedScriptValue.cpp:

(WebCore::CloneSerializer::serialize):

  • bindings/scripts/CodeGeneratorJS.pm:

(GenerateHeader):
(GenerateImplementation):

  • bridge/runtime_array.cpp:

(JSC::RuntimeArray::RuntimeArray):

  • bridge/runtime_array.h:

(JSC::RuntimeArray::createStructure):
(RuntimeArray):

LayoutTests:

Modify the JSON test to indicate that iterating over properties now returns
indexed properties first. This is a behavior change that makes us more
compliant with other implementations.

Also check in new expected file for the edge cases of indexed property access
with prototype accessors. This changeset introduces a known regression in that
department, which is tracked here: https://bugs.webkit.org/show_bug.cgi?id=96596

  • fast/js/resources/JSON-stringify.js:
  • platform/mac/fast/js/primitive-property-access-edge-cases-expected.txt: Added.
File:
1 edited

Legend:

Unmodified
Added
Removed
  • trunk/Source/JavaScriptCore/runtime/JSObject.h

    r128146 r128400  
    22 *  Copyright (C) 1999-2001 Harri Porten ([email protected])
    33 *  Copyright (C) 2001 Peter Kelly ([email protected])
    4  *  Copyright (C) 2003, 2004, 2005, 2006, 2007, 2008, 2009 Apple Inc. All rights reserved.
     4 *  Copyright (C) 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2012 Apple Inc. All rights reserved.
    55 *
    66 *  This library is free software; you can redistribute it and/or
     
    2525
    2626#include "ArgList.h"
     27#include "ArrayConventions.h"
     28#include "ArrayStorage.h"
     29#include "Butterfly.h"
    2730#include "ClassInfo.h"
    2831#include "CommonIdentifiers.h"
     
    3033#include "JSCell.h"
    3134#include "PropertySlot.h"
     35#include "PropertyStorage.h"
     36#include "PutDirectIndexMode.h"
    3237#include "PutPropertySlot.h"
    3338
    34 #include "StorageBarrier.h"
    3539#include "Structure.h"
    3640#include "JSGlobalData.h"
    3741#include "JSString.h"
     42#include "SparseArrayValueMap.h"
    3843#include <wtf/StdLibExtras.h>
    3944
     
    8085    };
    8186
     87    COMPILE_ASSERT(None < FirstInternalAttribute, None_is_below_FirstInternalAttribute);
     88    COMPILE_ASSERT(ReadOnly < FirstInternalAttribute, ReadOnly_is_below_FirstInternalAttribute);
     89    COMPILE_ASSERT(DontEnum < FirstInternalAttribute, DontEnum_is_below_FirstInternalAttribute);
     90    COMPILE_ASSERT(DontDelete < FirstInternalAttribute, DontDelete_is_below_FirstInternalAttribute);
     91    COMPILE_ASSERT(Function < FirstInternalAttribute, Function_is_below_FirstInternalAttribute);
     92    COMPILE_ASSERT(Accessor < FirstInternalAttribute, Accessor_is_below_FirstInternalAttribute);
     93
    8294    class JSFinalObject;
    8395
     
    97109    public:
    98110        typedef JSCell Base;
    99 
     111       
    100112        JS_EXPORT_PRIVATE static void visitChildren(JSCell*, SlotVisitor&);
    101113
     
    121133        bool allowsAccessFrom(ExecState*);
    122134
     135        unsigned getArrayLength() const
     136        {
     137            switch (structure()->indexingType()) {
     138            case NonArray:
     139            case Array:
     140                return 0;
     141            case NonArrayWithArrayStorage:
     142            case ArrayWithArrayStorage:
     143                return m_butterfly->arrayStorage()->length();
     144            default:
     145                ASSERT_NOT_REACHED();
     146                return 0;
     147            }
     148        }
     149       
     150        unsigned getVectorLength()
     151        {
     152            switch (structure()->indexingType()) {
     153            case NonArray:
     154            case Array:
     155                return 0;
     156            case NonArrayWithArrayStorage:
     157            case ArrayWithArrayStorage:
     158                return m_butterfly->arrayStorage()->vectorLength();
     159            default:
     160                ASSERT_NOT_REACHED();
     161                return 0;
     162            }
     163        }
     164       
    123165        JS_EXPORT_PRIVATE static void put(JSCell*, ExecState*, PropertyName, JSValue, PutPropertySlot&);
    124166        JS_EXPORT_PRIVATE static void putByIndex(JSCell*, ExecState*, unsigned propertyName, JSValue, bool shouldThrow);
     167       
     168        // This is similar to the putDirect* methods:
     169        //  - the prototype chain is not consulted
     170        //  - accessors are not called.
     171        //  - it will ignore extensibility and read-only properties if PutDirectIndexLikePutDirect is passed as the mode (the default).
     172        // This method creates a property with attributes writable, enumerable and configurable all set to true.
     173        bool putDirectIndex(ExecState* exec, unsigned propertyName, JSValue value, unsigned attributes, PutDirectIndexMode mode)
     174        {
     175            if (!attributes && canSetIndexQuickly(propertyName)) {
     176                setIndexQuickly(exec->globalData(), propertyName, value);
     177                return true;
     178            }
     179            return putDirectIndexBeyondVectorLength(exec, propertyName, value, attributes, mode);
     180        }
     181        bool putDirectIndex(ExecState* exec, unsigned propertyName, JSValue value)
     182        {
     183            return putDirectIndex(exec, propertyName, value, 0, PutDirectIndexLikePutDirect);
     184        }
     185
     186        // A non-throwing version of putDirect and putDirectIndex.
     187        void putDirectMayBeIndex(ExecState*, PropertyName, JSValue);
     188       
     189        bool canGetIndexQuickly(unsigned i)
     190        {
     191            switch (structure()->indexingType()) {
     192            case NonArray:
     193            case Array:
     194                return false;
     195            case NonArrayWithArrayStorage:
     196            case ArrayWithArrayStorage:
     197                return i < m_butterfly->arrayStorage()->vectorLength() && m_butterfly->arrayStorage()->m_vector[i];
     198            default:
     199                ASSERT_NOT_REACHED();
     200                return false;
     201            }
     202        }
     203       
     204        JSValue getIndexQuickly(unsigned i)
     205        {
     206            switch (structure()->indexingType()) {
     207            case NonArrayWithArrayStorage:
     208            case ArrayWithArrayStorage:
     209                return m_butterfly->arrayStorage()->m_vector[i].get();
     210            default:
     211                ASSERT_NOT_REACHED();
     212                return JSValue();
     213            }
     214        }
     215       
     216        bool canSetIndexQuickly(unsigned i)
     217        {
     218            switch (structure()->indexingType()) {
     219            case NonArray:
     220            case Array:
     221                return false;
     222            case NonArrayWithArrayStorage:
     223            case ArrayWithArrayStorage:
     224                return i < m_butterfly->arrayStorage()->vectorLength();
     225            default:
     226                ASSERT_NOT_REACHED();
     227                return false;
     228            }
     229        }
     230       
     231        void setIndexQuickly(JSGlobalData& globalData, unsigned i, JSValue v)
     232        {
     233            switch (structure()->indexingType()) {
     234            case NonArrayWithArrayStorage:
     235            case ArrayWithArrayStorage: {
     236                WriteBarrier<Unknown>& x = m_butterfly->arrayStorage()->m_vector[i];
     237                if (!x) {
     238                    ArrayStorage* storage = m_butterfly->arrayStorage();
     239                    ++storage->m_numValuesInVector;
     240                    if (i >= storage->length())
     241                        storage->setLength(i + 1);
     242                }
     243                x.set(globalData, this, v);
     244                break;
     245            }
     246            default:
     247                ASSERT_NOT_REACHED();
     248            }
     249        }
     250       
     251        void initializeIndex(JSGlobalData& globalData, unsigned i, JSValue v)
     252        {
     253            switch (structure()->indexingType()) {
     254            case NonArrayWithArrayStorage:
     255            case ArrayWithArrayStorage: {
     256                ArrayStorage* storage = m_butterfly->arrayStorage();
     257#if CHECK_ARRAY_CONSISTENCY
     258                ASSERT(storage->m_inCompactInitialization);
     259                // Check that we are initializing the next index in sequence.
     260                ASSERT(i == storage->m_initializationIndex);
     261                // tryCreateUninitialized set m_numValuesInVector to the initialLength,
     262                // check we do not try to initialize more than this number of properties.
     263                ASSERT(storage->m_initializationIndex < storage->m_numValuesInVector);
     264                storage->m_initializationIndex++;
     265#endif
     266                ASSERT(i < storage->length());
     267                ASSERT(i < storage->m_numValuesInVector);
     268                storage->m_vector[i].set(globalData, this, v);
     269                break;
     270            }
     271            default:
     272                ASSERT_NOT_REACHED();
     273            }
     274        }
     275       
     276        void completeInitialization(unsigned newLength)
     277        {
     278            switch (structure()->indexingType()) {
     279            case NonArrayWithArrayStorage:
     280            case ArrayWithArrayStorage: {
     281                ArrayStorage* storage = m_butterfly->arrayStorage();
     282                // Check that we have initialized as meny properties as we think we have.
     283                UNUSED_PARAM(storage);
     284                ASSERT_UNUSED(newLength, newLength == storage->length());
     285#if CHECK_ARRAY_CONSISTENCY
     286                // Check that the number of propreties initialized matches the initialLength.
     287                ASSERT(storage->m_initializationIndex == m_storage->m_numValuesInVector);
     288                ASSERT(storage->m_inCompactInitialization);
     289                storage->m_inCompactInitialization = false;
     290#endif
     291                break;
     292            }
     293            default:
     294                ASSERT_NOT_REACHED();
     295            }
     296        }
     297       
     298        bool inSparseIndexingMode()
     299        {
     300            switch (structure()->indexingType()) {
     301            case NonArray:
     302            case Array:
     303                return false;
     304            case NonArrayWithArrayStorage:
     305            case ArrayWithArrayStorage:
     306                return m_butterfly->arrayStorage()->inSparseMode();
     307            default:
     308                ASSERT_NOT_REACHED();
     309                return false;
     310            }
     311        }
     312       
     313        void enterDictionaryIndexingMode(JSGlobalData&);
    125314
    126315        // putDirect is effectively an unchecked vesion of 'defineOwnProperty':
     
    128317        //  - accessors are not called.
    129318        //  - attributes will be respected (after the call the property will exist with the given attributes)
     319        //  - the property name is assumed to not be an index.
    130320        JS_EXPORT_PRIVATE static void putDirectVirtual(JSObject*, ExecState*, PropertyName, JSValue, unsigned attributes);
    131321        void putDirect(JSGlobalData&, PropertyName, JSValue, unsigned attributes = 0);
    132322        void putDirect(JSGlobalData&, PropertyName, JSValue, PutPropertySlot&);
    133323        void putDirectWithoutTransition(JSGlobalData&, PropertyName, JSValue, unsigned attributes = 0);
    134         void putDirectAccessor(JSGlobalData&, PropertyName, JSValue, unsigned attributes);
     324        void putDirectAccessor(ExecState*, PropertyName, JSValue, unsigned attributes);
    135325
    136326        bool propertyIsEnumerable(ExecState*, const Identifier& propertyName) const;
     
    148338
    149339        JS_EXPORT_PRIVATE static void getOwnPropertyNames(JSObject*, ExecState*, PropertyNameArray&, EnumerationMode);
     340        JS_EXPORT_PRIVATE static void getOwnNonIndexPropertyNames(JSObject*, ExecState*, PropertyNameArray&, EnumerationMode);
    150341        JS_EXPORT_PRIVATE static void getPropertyNames(JSObject*, ExecState*, PropertyNameArray&, EnumerationMode);
    151342
     
    204395        }
    205396       
    206         ConstPropertyStorage outOfLineStorage() const { return m_outOfLineStorage.get(); }
    207         PropertyStorage outOfLineStorage() { return m_outOfLineStorage.get(); }
     397        const Butterfly* butterfly() const { return m_butterfly; }
     398        Butterfly* butterfly() { return m_butterfly; }
     399       
     400        ConstPropertyStorage outOfLineStorage() const { return m_butterfly->propertyStorage(); }
     401        PropertyStorage outOfLineStorage() { return m_butterfly->propertyStorage(); }
    208402
    209403        const WriteBarrierBase<Unknown>* locationForOffset(PropertyOffset offset) const
     
    228422                result = offsetInInlineStorage;
    229423            else
    230                 result = outOfLineStorage() - location + (inlineStorageCapacity - 2);
     424                result = outOfLineStorage() - location + (inlineStorageCapacity - 1);
    231425            validateOffset(result, structure()->typeInfo().type());
    232426            return result;
     
    266460        bool isFrozen(JSGlobalData& globalData) { return structure()->isFrozen(globalData); }
    267461        bool isExtensible() { return structure()->isExtensible(); }
     462        bool indexingShouldBeSparse()
     463        {
     464            return !isExtensible()
     465                || structure()->typeInfo().interceptsGetOwnPropertySlotByIndexEvenWhenLengthIsNotZero();
     466        }
    268467
    269468        bool staticFunctionsReified() { return structure()->staticFunctionsReified(); }
    270469        void reifyStaticFunctionsForDelete(ExecState* exec);
    271470
    272         JS_EXPORT_PRIVATE PropertyStorage growOutOfLineStorage(JSGlobalData&, size_t oldSize, size_t newSize);
    273         void setOutOfLineStorage(JSGlobalData&, PropertyStorage, Structure*);
     471        JS_EXPORT_PRIVATE Butterfly* growOutOfLineStorage(JSGlobalData&, size_t oldSize, size_t newSize);
     472        void setButterfly(JSGlobalData&, Butterfly*, Structure*);
     473        void setButterflyWithoutChangingStructure(Butterfly*); // You probably don't want to call this.
    274474       
    275475        void setStructureAndReallocateStorageIfNecessary(JSGlobalData&, unsigned oldCapacity, Structure*);
    276476        void setStructureAndReallocateStorageIfNecessary(JSGlobalData&, Structure*);
    277 
    278         void* addressOfOutOfLineStorage()
    279         {
    280             return &m_outOfLineStorage;
    281         }
    282477
    283478        void flattenDictionaryObject(JSGlobalData& globalData)
     
    294489       
    295490        static size_t offsetOfInlineStorage();
    296         static size_t offsetOfOutOfLineStorage();
     491       
     492        static ptrdiff_t butterflyOffset()
     493        {
     494            return OBJECT_OFFSETOF(JSObject, m_butterfly);
     495        }
     496       
     497        void* butterflyAddress()
     498        {
     499            return &m_butterfly;
     500        }
    297501
    298502        static JS_EXPORTDATA const ClassInfo s_info;
     
    317521        // To instantiate objects you likely want JSFinalObject, below.
    318522        // To create derived types you likely want JSNonFinalObject, below.
    319         JSObject(JSGlobalData&, Structure*);
     523        JSObject(JSGlobalData&, Structure*, Butterfly* = 0);
    320524       
    321525        void resetInheritorID(JSGlobalData& globalData)
     
    324528        }
    325529       
    326         void visitOutOfLineStorage(SlotVisitor&, PropertyStorage, size_t storageSize);
     530        void visitButterfly(SlotVisitor&, Butterfly*, size_t storageSize);
     531
     532        // Call this if you know that the object is in a mode where it has array
     533        // storage. This will assert otherwise.
     534        ArrayStorage* arrayStorage()
     535        {
     536            ASSERT(structure()->indexingType() | HasArrayStorage);
     537            return m_butterfly->arrayStorage();
     538        }
     539       
     540        // Call this if you want to predicate some actions on whether or not the
     541        // object is in a mode where it has array storage.
     542        ArrayStorage* arrayStorageOrNull()
     543        {
     544            switch (structure()->indexingType()) {
     545            case ArrayWithArrayStorage:
     546            case NonArrayWithArrayStorage:
     547                return m_butterfly->arrayStorage();
     548               
     549            default:
     550                return 0;
     551            }
     552        }
     553
     554        // Ensure that the object is in a mode where it has array storage. Use
     555        // this if you're about to perform actions that would have required the
     556        // object to be converted to have array storage, if it didn't have it
     557        // already.
     558        ArrayStorage* ensureArrayStorage(JSGlobalData& globalData)
     559        {
     560            switch (structure()->indexingType()) {
     561            case ArrayWithArrayStorage:
     562            case NonArrayWithArrayStorage:
     563                return m_butterfly->arrayStorage();
     564               
     565            case NonArray:
     566            case Array:
     567                return createInitialArrayStorage(globalData);
     568               
     569            default:
     570                ASSERT_NOT_REACHED();
     571                return 0;
     572            }
     573        }
     574       
     575        ArrayStorage* createArrayStorage(JSGlobalData&, unsigned length, unsigned vectorLength);
     576        ArrayStorage* createInitialArrayStorage(JSGlobalData&);
     577       
     578        ArrayStorage* ensureArrayStorageExistsAndEnterDictionaryIndexingMode(JSGlobalData&);
     579       
     580        bool defineOwnNonIndexProperty(ExecState*, PropertyName, PropertyDescriptor&, bool throwException);
     581
     582        enum ConsistencyCheckType { NormalConsistencyCheck, DestructorConsistencyCheck, SortConsistencyCheck };
     583#if !CHECK_ARRAY_CONSISTENCY
     584        void checkIndexingConsistency(ConsistencyCheckType = NormalConsistencyCheck) { }
     585#else
     586        void checkIndexingConsistency(ConsistencyCheckType = NormalConsistencyCheck);
     587#endif
     588       
     589        void putByIndexBeyondVectorLengthWithArrayStorage(ExecState*, unsigned propertyName, JSValue, bool shouldThrow, ArrayStorage*);
     590
     591        bool increaseVectorLength(JSGlobalData&, unsigned newLength);
     592        void deallocateSparseIndexMap();
     593        bool defineOwnIndexedProperty(ExecState*, unsigned, PropertyDescriptor&, bool throwException);
     594        SparseArrayValueMap* allocateSparseIndexMap(JSGlobalData&);
    327595
    328596    private:
     
    337605        void isString();
    338606       
     607        ArrayStorage* enterDictionaryIndexingModeWhenArrayStorageAlreadyExists(JSGlobalData&, ArrayStorage*);
     608       
    339609        template<PutMode>
    340610        bool putDirectInternal(JSGlobalData&, PropertyName, JSValue, unsigned attr, PutPropertySlot&, JSCell*);
    341611
    342612        bool inlineGetOwnPropertySlot(ExecState*, PropertyName, PropertySlot&);
    343         JS_EXPORT_PRIVATE void fillGetterPropertySlot(PropertySlot&, WriteBarrierBase<Unknown>* location);
     613        JS_EXPORT_PRIVATE void fillGetterPropertySlot(PropertySlot&, PropertyOffset);
    344614
    345615        const HashEntry* findPropertyHashEntry(ExecState*, PropertyName) const;
    346616        Structure* createInheritorID(JSGlobalData&);
    347 
    348         StorageBarrier m_outOfLineStorage;
     617       
     618        void putIndexedDescriptor(ExecState*, SparseArrayEntry*, PropertyDescriptor&, PropertyDescriptor& old);
     619       
     620        void putByIndexBeyondVectorLength(ExecState*, unsigned propertyName, JSValue, bool shouldThrow);
     621        bool putDirectIndexBeyondVectorLengthWithArrayStorage(ExecState*, unsigned propertyName, JSValue, unsigned attributes, PutDirectIndexMode, ArrayStorage*);
     622        JS_EXPORT_PRIVATE bool putDirectIndexBeyondVectorLength(ExecState*, unsigned propertyName, JSValue, unsigned attributes, PutDirectIndexMode);
     623       
     624        unsigned getNewVectorLength(unsigned currentVectorLength, unsigned currentLength, unsigned desiredLength);
     625        unsigned getNewVectorLength(unsigned desiredLength);
     626
     627        JS_EXPORT_PRIVATE bool getOwnPropertySlotSlow(ExecState*, PropertyName, PropertySlot&);
     628       
     629    protected:
     630        Butterfly* m_butterfly;
    349631    };
    350632
     
    370652
    371653    protected:
    372         explicit JSNonFinalObject(JSGlobalData& globalData, Structure* structure)
    373             : JSObject(globalData, structure)
     654        explicit JSNonFinalObject(JSGlobalData& globalData, Structure* structure, Butterfly* butterfly = 0)
     655            : JSObject(globalData, structure, butterfly)
    374656        {
    375657        }
     
    454736}
    455737
    456 inline size_t JSObject::offsetOfOutOfLineStorage()
    457 {
    458     return OBJECT_OFFSETOF(JSObject, m_outOfLineStorage);
    459 }
    460 
    461738inline bool JSObject::isGlobalObject() const
    462739{
     
    489766}
    490767
    491 inline void JSObject::setOutOfLineStorage(JSGlobalData& globalData, PropertyStorage storage, Structure* structure)
     768inline void JSObject::setButterfly(JSGlobalData& globalData, Butterfly* butterfly, Structure* structure)
    492769{
    493770    ASSERT(structure);
    494     if (!storage) {
    495         ASSERT(!structure->outOfLineCapacity());
    496         ASSERT(!structure->outOfLineSize());
    497     } else {
    498         ASSERT(structure->outOfLineCapacity());
    499         ASSERT(structure->outOfLineSize());
    500     }
     771    ASSERT(!butterfly == (!structure->outOfLineCapacity() && !hasIndexingHeader(structure->indexingType())));
    501772    setStructure(globalData, structure);
    502     m_outOfLineStorage.set(globalData, this, storage);
     773    m_butterfly = butterfly;
     774}
     775
     776inline void JSObject::setButterflyWithoutChangingStructure(Butterfly* butterfly)
     777{
     778    m_butterfly = butterfly;
    503779}
    504780
     
    538814}
    539815
    540 inline JSObject::JSObject(JSGlobalData& globalData, Structure* structure)
     816inline JSObject::JSObject(JSGlobalData& globalData, Structure* structure, Butterfly* butterfly)
    541817    : JSCell(globalData, structure)
    542     , m_outOfLineStorage(globalData, this, 0)
     818    , m_butterfly(butterfly)
    543819{
    544820}
     
    588864ALWAYS_INLINE bool JSObject::inlineGetOwnPropertySlot(ExecState* exec, PropertyName propertyName, PropertySlot& slot)
    589865{
    590     if (WriteBarrierBase<Unknown>* location = getDirectLocation(exec->globalData(), propertyName)) {
    591         if (structure()->hasGetterSetterProperties() && location->isGetterSetter())
    592             fillGetterPropertySlot(slot, location);
     866    PropertyOffset offset = structure()->get(exec->globalData(), propertyName);
     867    if (LIKELY(isValidOffset(offset))) {
     868        JSValue value = getDirectOffset(offset);
     869        if (structure()->hasGetterSetterProperties() && value.isGetterSetter())
     870            fillGetterPropertySlot(slot, offset);
    593871        else
    594             slot.setValue(this, location->get(), offsetForLocation(location));
     872            slot.setValue(this, value, offset);
    595873        return true;
    596874    }
    597875
    598     return false;
     876    return getOwnPropertySlotSlow(exec, propertyName, slot);
    599877}
    600878
     
    682960    ASSERT(value.isGetterSetter() == !!(attributes & Accessor));
    683961    ASSERT(!Heap::heap(value) || Heap::heap(value) == Heap::heap(this));
     962    ASSERT(propertyName.asIndex() == PropertyName::NotAnIndex);
    684963
    685964    if (structure()->isDictionary()) {
     
    710989            return false;
    711990
    712         PropertyStorage newStorage = outOfLineStorage();
     991        Butterfly* newButterfly = m_butterfly;
    713992        if (structure()->putWillGrowOutOfLineStorage())
    714             newStorage = growOutOfLineStorage(globalData, structure()->outOfLineCapacity(), structure()->suggestedNewOutOfLineStorageCapacity());
     993            newButterfly = growOutOfLineStorage(globalData, structure()->outOfLineCapacity(), structure()->suggestedNewOutOfLineStorageCapacity());
    715994        offset = structure()->addPropertyWithoutTransition(globalData, propertyName, attributes, specificFunction);
    716         setOutOfLineStorage(globalData, newStorage, structure());
     995        setButterfly(globalData, newButterfly, structure());
    717996
    718997        validateOffset(offset);
     
    7281007    size_t currentCapacity = structure()->outOfLineCapacity();
    7291008    if (Structure* structure = Structure::addPropertyTransitionToExistingStructure(this->structure(), propertyName, attributes, specificFunction, offset)) {
    730         PropertyStorage newStorage = outOfLineStorage();
     1009        Butterfly* newButterfly = m_butterfly;
    7311010        if (currentCapacity != structure->outOfLineCapacity())
    732             newStorage = growOutOfLineStorage(globalData, currentCapacity, structure->outOfLineCapacity());
     1011            newButterfly = growOutOfLineStorage(globalData, currentCapacity, structure->outOfLineCapacity());
    7331012
    7341013        validateOffset(offset);
    7351014        ASSERT(structure->isValidOffset(offset));
    736         setOutOfLineStorage(globalData, newStorage, structure);
     1015        setButterfly(globalData, newButterfly, structure);
    7371016        putDirectOffset(globalData, offset, value);
    7381017        // This is a new property; transitions with specific values are not currently cachable,
     
    8011080    }
    8021081   
    803     PropertyStorage newStorage = growOutOfLineStorage(
     1082    Butterfly* newButterfly = growOutOfLineStorage(
    8041083        globalData, oldCapacity, newStructure->outOfLineCapacity());
    805     setOutOfLineStorage(globalData, newStorage, newStructure);
     1084    setButterfly(globalData, newButterfly, newStructure);
    8061085}
    8071086
     
    8371116{
    8381117    ASSERT(!value.isGetterSetter() && !(attributes & Accessor));
    839     PropertyStorage newStorage = outOfLineStorage();
     1118    Butterfly* newButterfly = m_butterfly;
    8401119    if (structure()->putWillGrowOutOfLineStorage())
    841         newStorage = growOutOfLineStorage(globalData, structure()->outOfLineCapacity(), structure()->suggestedNewOutOfLineStorageCapacity());
     1120        newButterfly = growOutOfLineStorage(globalData, structure()->outOfLineCapacity(), structure()->suggestedNewOutOfLineStorageCapacity());
    8421121    PropertyOffset offset = structure()->addPropertyWithoutTransition(globalData, propertyName, attributes, getCallableObject(value));
    843     setOutOfLineStorage(globalData, newStorage, structure());
     1122    setButterfly(globalData, newButterfly, structure());
    8441123    putDirectOffset(globalData, offset, value);
    8451124}
     
    9331212}
    9341213
     1214inline size_t offsetInButterfly(PropertyOffset offset)
     1215{
     1216    return offsetInOutOfLineStorage(offset) + Butterfly::indexOfPropertyStorage();
     1217}
     1218
    9351219// This is a helper for patching code where you want to emit a load or store and
    9361220// the base is:
     
    9401224{
    9411225    if (isOutOfLineOffset(offset))
    942         return sizeof(EncodedJSValue) * offsetInOutOfLineStorage(offset);
    943     return JSObject::offsetOfInlineStorage() - JSObject::offsetOfOutOfLineStorage() + sizeof(EncodedJSValue) * offsetInInlineStorage(offset);
     1226        return sizeof(EncodedJSValue) * offsetInButterfly(offset);
     1227    return JSObject::offsetOfInlineStorage() - JSObject::butterflyOffset() + sizeof(EncodedJSValue) * offsetInInlineStorage(offset);
    9441228}
    9451229
     
    9471231{
    9481232    if (isOutOfLineOffset(offset))
    949         return offsetInOutOfLineStorage(offset);
     1233        return offsetInOutOfLineStorage(offset) + Butterfly::indexOfPropertyStorage();
    9501234    ASSERT(!(JSObject::offsetOfInlineStorage() % sizeof(EncodedJSValue)));
    9511235    return JSObject::offsetOfInlineStorage() / sizeof(EncodedJSValue) + offsetInInlineStorage(offset);
     
    9551239{
    9561240    if (isOutOfLineOffset(offset))
    957         return offsetInOutOfLineStorage(offset) * sizeof(EncodedJSValue);
     1241        return offsetInOutOfLineStorage(offset) * sizeof(EncodedJSValue) + Butterfly::offsetOfPropertyStorage();
    9581242    return JSObject::offsetOfInlineStorage() + offsetInInlineStorage(offset) * sizeof(EncodedJSValue);
    9591243}
Note: See TracChangeset for help on using the changeset viewer.