WebKit Bugzilla
Attachment 340771 Details for
Bug 185003
: We should have a CoW storage for NewArrayBuffer arrays.
Home
|
New
|
Browse
|
Search
|
[?]
|
Reports
|
Requests
|
Help
|
New Account
|
Log In
Remember
[x]
|
Forgot Password
Login:
[x]
[patch]
Patch
bug-185003-20180518232900.patch (text/plain), 252.28 KB, created by
Keith Miller
on 2018-05-18 23:29:01 PDT
(
hide
)
Description:
Patch
Filename:
MIME Type:
Creator:
Keith Miller
Created:
2018-05-18 23:29:01 PDT
Size:
252.28 KB
patch
obsolete
>Subversion Revision: 231172 >diff --git a/Source/JavaScriptCore/ChangeLog b/Source/JavaScriptCore/ChangeLog >index f8739f50d22f85698e3221b77bf447cb4ce2ae0b..aaba5764e0538a1868c1e65196fe5e60283129dd 100644 >--- a/Source/JavaScriptCore/ChangeLog >+++ b/Source/JavaScriptCore/ChangeLog >@@ -1,3 +1,537 @@ >+2018-05-18 Keith Miller <keith_miller@apple.com> >+ >+ We should have a CoW storage for NewArrayBuffer arrays. >+ https://bugs.webkit.org/show_bug.cgi?id=185003 >+ >+ Reviewed by NOBODY (OOPS!). >+ >+ * JavaScriptCore.xcodeproj/project.pbxproj: >+ * Sources.txt: >+ * bytecode/ArrayAllocationProfile.cpp: >+ (JSC::ArrayAllocationProfile::updateProfile): >+ * bytecode/ArrayAllocationProfile.h: >+ (JSC::ArrayAllocationProfile::initializeIndexingMode): >+ * bytecode/ArrayProfile.cpp: >+ (JSC::dumpArrayModes): >+ (JSC::ArrayProfile::briefDescriptionWithoutUpdating): >+ * bytecode/ArrayProfile.h: >+ (JSC::asArrayModes): >+ (JSC::arrayModeFromStructure): >+ (JSC::arrayModesInclude): >+ (JSC::hasSeenCopyOnWriteArray): >+ * bytecode/BytecodeList.json: >+ * bytecode/CodeBlock.cpp: >+ (JSC::CodeBlock::finishCreation): >+ * bytecode/InlineAccess.cpp: >+ (JSC::InlineAccess::generateArrayLength): >+ * bytecode/UnlinkedCodeBlock.h: >+ (JSC::UnlinkedCodeBlock::addArrayAllocationProfile): >+ (JSC::UnlinkedCodeBlock::decopressArrayAllocationProfile): >+ * bytecompiler/BytecodeGenerator.cpp: >+ (JSC::BytecodeGenerator::newArrayAllocationProfile): >+ (JSC::BytecodeGenerator::emitNewArrayBuffer): >+ (JSC::BytecodeGenerator::emitNewArray): >+ (JSC::BytecodeGenerator::emitNewArrayWithSize): >+ (JSC::BytecodeGenerator::emitExpectedFunctionSnippet): >+ * bytecompiler/BytecodeGenerator.h: >+ * bytecompiler/NodesCodegen.cpp: >+ (JSC::ArrayNode::emitBytecode): >+ (JSC::ArrayPatternNode::bindValue const): >+ (JSC::ArrayPatternNode::emitDirectBinding): >+ * dfg/DFGAbstractInterpreterInlines.h: >+ (JSC::DFG::AbstractInterpreter<AbstractStateType>::executeEffects): >+ * dfg/DFGAbstractValue.h: >+ * dfg/DFGArgumentsEliminationPhase.cpp: >+ * dfg/DFGArgumentsUtilities.cpp: >+ (JSC::DFG::emitCodeToGetArgumentsArrayLength): >+ * dfg/DFGArrayMode.cpp: >+ (JSC::DFG::ArrayMode::fromObserved): >+ (JSC::DFG::ArrayMode::refine const): >+ (JSC::DFG::ArrayMode::alreadyChecked const): >+ (JSC::DFG::toIndexingShape): >+ * dfg/DFGArrayMode.h: >+ (JSC::DFG::ArrayMode::ArrayMode): >+ (JSC::DFG::ArrayMode::action const): >+ (JSC::DFG::ArrayMode::withSpeculation const): >+ (JSC::DFG::ArrayMode::withArrayClass const): >+ (JSC::DFG::ArrayMode::withType const): >+ (JSC::DFG::ArrayMode::withConversion const): >+ (JSC::DFG::ArrayMode::withTypeAndConversion const): >+ (JSC::DFG::ArrayMode::arrayModesThatPassFiltering const): >+ (JSC::DFG::ArrayMode::arrayModesWithIndexingShape const): >+ * dfg/DFGByteCodeParser.cpp: >+ (JSC::DFG::ByteCodeParser::parseBlock): >+ * dfg/DFGClobberize.h: >+ (JSC::DFG::clobberize): >+ * dfg/DFGConstantFoldingPhase.cpp: >+ (JSC::DFG::ConstantFoldingPhase::foldConstants): >+ * dfg/DFGFixupPhase.cpp: >+ (JSC::DFG::FixupPhase::fixupNode): >+ * dfg/DFGGraph.cpp: >+ (JSC::DFG::Graph::dump): >+ * dfg/DFGNode.h: >+ (JSC::DFG::Node::indexingType): >+ (JSC::DFG::Node::indexingMode): >+ * dfg/DFGOSRExit.cpp: >+ (JSC::DFG::OSRExit::compileExit): >+ * dfg/DFGOperations.cpp: >+ * dfg/DFGOperations.h: >+ * dfg/DFGSpeculativeJIT.cpp: >+ (JSC::DFG::SpeculativeJIT::emitAllocateRawObject): >+ (JSC::DFG::SpeculativeJIT::jumpSlowForUnwantedArrayMode): >+ (JSC::DFG::SpeculativeJIT::arrayify): >+ (JSC::DFG::SpeculativeJIT::compileDoublePutByVal): >+ (JSC::DFG::SpeculativeJIT::compileCreateRest): >+ (JSC::DFG::SpeculativeJIT::compileArraySlice): >+ (JSC::DFG::SpeculativeJIT::compileArrayPush): >+ (JSC::DFG::SpeculativeJIT::compileNewArrayBuffer): >+ * dfg/DFGSpeculativeJIT32_64.cpp: >+ (JSC::DFG::SpeculativeJIT::compile): >+ * dfg/DFGSpeculativeJIT64.cpp: >+ (JSC::DFG::SpeculativeJIT::compile): >+ * dfg/DFGValidate.cpp: >+ * ftl/FTLAbstractHeapRepository.h: >+ * ftl/FTLLowerDFGToB3.cpp: >+ (JSC::FTL::DFG::LowerDFGToB3::compilePutStructure): >+ (JSC::FTL::DFG::LowerDFGToB3::compileArraySlice): >+ (JSC::FTL::DFG::LowerDFGToB3::compileNewArrayWithSpread): >+ (JSC::FTL::DFG::LowerDFGToB3::compileNewArrayBuffer): >+ (JSC::FTL::DFG::LowerDFGToB3::compileCallOrConstructVarargsSpread): >+ (JSC::FTL::DFG::LowerDFGToB3::compileForwardVarargsWithSpread): >+ (JSC::FTL::DFG::LowerDFGToB3::storeStructure): >+ (JSC::FTL::DFG::LowerDFGToB3::isArrayTypeForArrayify): >+ * ftl/FTLOperations.cpp: >+ (JSC::FTL::operationMaterializeObjectInOSR): >+ * generate-bytecode-files: >+ * jit/AssemblyHelpers.cpp: >+ (JSC::AssemblyHelpers::emitStoreStructureWithTypeInfo): >+ * jit/AssemblyHelpers.h: >+ (JSC::AssemblyHelpers::emitStoreStructureWithTypeInfo): >+ * jit/JITOperations.cpp: >+ * jit/JITPropertyAccess.cpp: >+ (JSC::JIT::emit_op_put_by_val): >+ (JSC::JIT::emitSlow_op_put_by_val): >+ * llint/LowLevelInterpreter.asm: >+ * llint/LowLevelInterpreter32_64.asm: >+ * llint/LowLevelInterpreter64.asm: >+ * runtime/Butterfly.h: >+ (JSC::ContiguousData::Data::Data): >+ (JSC::ContiguousData::Data::operator=): >+ (JSC::ContiguousData::Data::set): >+ (JSC::ContiguousData::Data::operator T&): >+ (JSC::ContiguousData::atUnsafe): >+ (JSC::ContiguousData::at const): Deleted. >+ (JSC::ContiguousData::at): Deleted. >+ * runtime/ButterflyInlines.h: >+ (JSC::ContiguousData<T>::at const): >+ (JSC::ContiguousData<T>::at): >+ * runtime/ClonedArguments.cpp: >+ (JSC::ClonedArguments::createEmpty): >+ * runtime/CommonSlowPaths.cpp: >+ (JSC::SLOW_PATH_DECL): >+ * runtime/IndexingType.cpp: >+ (JSC::dumpIndexingType): >+ * runtime/IndexingType.h: >+ (JSC::hasIndexedProperties): >+ (JSC::hasUndecided): >+ (JSC::hasInt32): >+ (JSC::hasDouble): >+ (JSC::hasContiguous): >+ (JSC::hasArrayStorage): >+ (JSC::hasAnyArrayStorage): >+ (JSC::hasSlowPutArrayStorage): >+ (JSC::shouldUseSlowPut): >+ (JSC::isCopyOnWrite): >+ (JSC::arrayIndexFromIndexingType): >+ * runtime/JSArray.cpp: >+ (JSC::JSArray::tryCreateUninitializedRestricted): >+ (JSC::JSArray::appendMemcpy): >+ (JSC::JSArray::setLength): >+ (JSC::JSArray::pop): >+ (JSC::JSArray::shiftCountWithAnyIndexingType): >+ (JSC::JSArray::unshiftCountWithAnyIndexingType): >+ (JSC::JSArray::fillArgList): >+ (JSC::JSArray::copyToArguments): >+ * runtime/JSArrayInlines.h: >+ (JSC::JSArray::pushInline): >+ * runtime/JSCell.h: >+ * runtime/JSCellInlines.h: >+ (JSC::JSCell::JSCell): >+ (JSC::JSCell::finishCreation): >+ (JSC::JSCell::indexingType const): >+ (JSC::JSCell::indexingMode const): >+ (JSC::JSCell::setStructure): >+ * runtime/JSFixedArray.h: >+ * runtime/JSGlobalObject.cpp: >+ (JSC::JSGlobalObject::init): >+ (JSC::JSGlobalObject::haveABadTime): >+ (JSC::JSGlobalObject::visitChildren): >+ * runtime/JSGlobalObject.h: >+ (JSC::JSGlobalObject::originalArrayStructureForIndexingType const): >+ (JSC::JSGlobalObject::arrayStructureForIndexingTypeDuringAllocation const): >+ (JSC::JSGlobalObject::isOriginalArrayStructure): >+ * runtime/JSImmutableButterfly.cpp: Added. >+ (JSC::JSImmutableButterfly::visitChildren): >+ * runtime/JSImmutableButterfly.h: Added. >+ (JSC::JSImmutableButterfly::createStructure): >+ (JSC::JSImmutableButterfly::tryCreate): >+ (JSC::JSImmutableButterfly::create): >+ (JSC::JSImmutableButterfly::publicLength const): >+ (JSC::JSImmutableButterfly::vectorLength const): >+ (JSC::JSImmutableButterfly::length const): >+ (JSC::JSImmutableButterfly::toButterfly const): >+ (JSC::JSImmutableButterfly::fromButterfly): >+ (JSC::JSImmutableButterfly::get const): >+ (JSC::JSImmutableButterfly::subspaceFor): >+ (JSC::JSImmutableButterfly::setIndex): >+ (JSC::JSImmutableButterfly::allocationSize): >+ (JSC::JSImmutableButterfly::JSImmutableButterfly): >+ * runtime/JSObject.cpp: >+ (JSC::JSObject::markAuxiliaryAndVisitOutOfLineProperties): >+ (JSC::JSObject::visitButterflyImpl): >+ (JSC::JSObject::getOwnPropertySlotByIndex): >+ (JSC::JSObject::putByIndex): >+ (JSC::JSObject::createInitialInt32): >+ (JSC::JSObject::createInitialDouble): >+ (JSC::JSObject::createInitialContiguous): >+ (JSC::JSObject::convertUndecidedToInt32): >+ (JSC::JSObject::convertUndecidedToDouble): >+ (JSC::JSObject::convertUndecidedToContiguous): >+ (JSC::JSObject::convertInt32ToDouble): >+ (JSC::JSObject::convertInt32ToArrayStorage): >+ (JSC::JSObject::convertDoubleToContiguous): >+ (JSC::JSObject::convertDoubleToArrayStorage): >+ (JSC::JSObject::convertContiguousToArrayStorage): >+ (JSC::JSObject::createInitialForValueAndSet): >+ (JSC::JSObject::convertInt32ForValue): >+ (JSC::JSObject::convertFromCopyOnWrite): >+ (JSC::JSObject::ensureWritableInt32Slow): >+ (JSC::JSObject::ensureWritableDoubleSlow): >+ (JSC::JSObject::ensureWritableContiguousSlow): >+ (JSC::JSObject::deletePropertyByIndex): >+ (JSC::JSObject::getOwnPropertyNames): >+ (JSC::canDoFastPutDirectIndex): >+ (JSC::JSObject::defineOwnIndexedProperty): >+ (JSC::JSObject::putByIndexBeyondVectorLengthWithoutAttributes): >+ (JSC::JSObject::putByIndexBeyondVectorLengthWithArrayStorage): >+ (JSC::JSObject::putByIndexBeyondVectorLength): >+ (JSC::JSObject::countElements): >+ (JSC::JSObject::ensureLengthSlow): >+ (JSC::JSObject::getEnumerableLength): >+ (JSC::JSObject::ensureInt32Slow): Deleted. >+ (JSC::JSObject::ensureDoubleSlow): Deleted. >+ (JSC::JSObject::ensureContiguousSlow): Deleted. >+ * runtime/JSObject.h: >+ (JSC::JSObject::putDirectIndex): >+ (JSC::JSObject::canGetIndexQuickly): >+ (JSC::JSObject::getIndexQuickly): >+ (JSC::JSObject::tryGetIndexQuickly const): >+ (JSC::JSObject::canSetIndexQuickly): >+ (JSC::JSObject::setIndexQuickly): >+ (JSC::JSObject::initializeIndex): >+ (JSC::JSObject::initializeIndexWithoutBarrier): >+ (JSC::JSObject::ensureWritableInt32): >+ (JSC::JSObject::ensureWritableDouble): >+ (JSC::JSObject::ensureWritableContiguous): >+ (JSC::JSObject::ensureInt32): Deleted. >+ (JSC::JSObject::ensureDouble): Deleted. >+ (JSC::JSObject::ensureContiguous): Deleted. >+ * runtime/JSObjectInlines.h: >+ (JSC::JSObject::putDirectInternal): >+ * runtime/JSType.h: >+ * runtime/RegExpMatchesArray.h: >+ (JSC::tryCreateUninitializedRegExpMatchesArray): >+ * runtime/Structure.cpp: >+ (JSC::Structure::Structure): >+ (JSC::Structure::addNewPropertyTransition): >+ (JSC::Structure::nonPropertyTransition): >+ * runtime/Structure.h: >+ * runtime/StructureIDBlob.h: >+ (JSC::StructureIDBlob::StructureIDBlob): >+ (JSC::StructureIDBlob::indexingModeIncludingHistory const): >+ (JSC::StructureIDBlob::setIndexingModeIncludingHistory): >+ (JSC::StructureIDBlob::indexingModeIncludingHistoryOffset): >+ (JSC::StructureIDBlob::indexingTypeIncludingHistory const): Deleted. >+ (JSC::StructureIDBlob::setIndexingTypeIncludingHistory): Deleted. >+ (JSC::StructureIDBlob::indexingTypeIncludingHistoryOffset): Deleted. >+ * runtime/StructureTransitionTable.h: >+ (JSC::newIndexingType): >+ * runtime/VM.cpp: >+ (JSC::VM::VM): >+ * runtime/VM.h: >+ >+ * JavaScriptCore.xcodeproj/project.pbxproj: >+ * Sources.txt: >+ * bytecode/ArrayAllocationProfile.cpp: >+ (JSC::ArrayAllocationProfile::updateProfile): >+ * bytecode/ArrayAllocationProfile.h: >+ (JSC::ArrayAllocationProfile::initializeIndexingMode): >+ * bytecode/ArrayProfile.cpp: >+ (JSC::dumpArrayModes): >+ (JSC::ArrayProfile::briefDescriptionWithoutUpdating): >+ * bytecode/ArrayProfile.h: >+ (JSC::asArrayModes): >+ (JSC::arrayModeFromStructure): >+ (JSC::arrayModesInclude): >+ (JSC::hasSeenCopyOnWriteArray): >+ * bytecode/BytecodeList.json: >+ * bytecode/CodeBlock.cpp: >+ (JSC::CodeBlock::finishCreation): >+ * bytecode/InlineAccess.cpp: >+ (JSC::InlineAccess::generateArrayLength): >+ * bytecode/UnlinkedCodeBlock.h: >+ (JSC::UnlinkedCodeBlock::addArrayAllocationProfile): >+ (JSC::UnlinkedCodeBlock::decopressArrayAllocationProfile): >+ * bytecompiler/BytecodeGenerator.cpp: >+ (JSC::BytecodeGenerator::newArrayAllocationProfile): >+ (JSC::BytecodeGenerator::emitNewArrayBuffer): >+ (JSC::BytecodeGenerator::emitNewArray): >+ (JSC::BytecodeGenerator::emitNewArrayWithSize): >+ (JSC::BytecodeGenerator::emitExpectedFunctionSnippet): >+ * bytecompiler/BytecodeGenerator.h: >+ * bytecompiler/NodesCodegen.cpp: >+ (JSC::ArrayNode::emitBytecode): >+ (JSC::ArrayPatternNode::bindValue const): >+ (JSC::ArrayPatternNode::emitDirectBinding): >+ * dfg/DFGAbstractInterpreterInlines.h: >+ (JSC::DFG::AbstractInterpreter<AbstractStateType>::executeEffects): >+ * dfg/DFGAbstractValue.h: >+ * dfg/DFGArgumentsEliminationPhase.cpp: >+ * dfg/DFGArgumentsUtilities.cpp: >+ (JSC::DFG::emitCodeToGetArgumentsArrayLength): >+ * dfg/DFGArrayMode.cpp: >+ (JSC::DFG::ArrayMode::fromObserved): >+ (JSC::DFG::ArrayMode::refine const): >+ (JSC::DFG::ArrayMode::alreadyChecked const): >+ (JSC::DFG::toIndexingShape): >+ * dfg/DFGArrayMode.h: >+ (JSC::DFG::ArrayMode::ArrayMode): >+ (JSC::DFG::ArrayMode::action const): >+ (JSC::DFG::ArrayMode::withSpeculation const): >+ (JSC::DFG::ArrayMode::withArrayClass const): >+ (JSC::DFG::ArrayMode::withType const): >+ (JSC::DFG::ArrayMode::withConversion const): >+ (JSC::DFG::ArrayMode::withTypeAndConversion const): >+ (JSC::DFG::ArrayMode::arrayModesThatPassFiltering const): >+ (JSC::DFG::ArrayMode::arrayModesWithIndexingShape const): >+ * dfg/DFGByteCodeParser.cpp: >+ (JSC::DFG::ByteCodeParser::handleIntrinsicCall): >+ (JSC::DFG::ByteCodeParser::handleIntrinsicGetter): >+ (JSC::DFG::ByteCodeParser::parseBlock): >+ * dfg/DFGClobberize.h: >+ (JSC::DFG::clobberize): >+ * dfg/DFGConstantFoldingPhase.cpp: >+ (JSC::DFG::ConstantFoldingPhase::foldConstants): >+ * dfg/DFGFixupPhase.cpp: >+ (JSC::DFG::FixupPhase::fixupNode): >+ (JSC::DFG::FixupPhase::attemptToForceStringArrayModeByToStringConversion): >+ (JSC::DFG::FixupPhase::attemptToMakeGetArrayLength): >+ * dfg/DFGGraph.cpp: >+ (JSC::DFG::Graph::dump): >+ * dfg/DFGNode.h: >+ (JSC::DFG::Node::indexingType): >+ (JSC::DFG::Node::indexingMode): >+ * dfg/DFGOSRExit.cpp: >+ (JSC::DFG::OSRExit::compileExit): >+ * dfg/DFGOperations.cpp: >+ * dfg/DFGOperations.h: >+ * dfg/DFGSpeculativeJIT.cpp: >+ (JSC::DFG::SpeculativeJIT::emitAllocateRawObject): >+ (JSC::DFG::SpeculativeJIT::jumpSlowForUnwantedArrayMode): >+ (JSC::DFG::SpeculativeJIT::arrayify): >+ (JSC::DFG::SpeculativeJIT::compileDoublePutByVal): >+ (JSC::DFG::SpeculativeJIT::compileGetByValOnString): >+ (JSC::DFG::SpeculativeJIT::compileGetByValOnDirectArguments): >+ (JSC::DFG::SpeculativeJIT::compileGetByValOnScopedArguments): >+ (JSC::DFG::SpeculativeJIT::compileGetArrayLength): >+ (JSC::DFG::SpeculativeJIT::compileCreateRest): >+ (JSC::DFG::SpeculativeJIT::compileArraySlice): >+ (JSC::DFG::SpeculativeJIT::compileArrayPush): >+ (JSC::DFG::SpeculativeJIT::compileNewArrayBuffer): >+ * dfg/DFGSpeculativeJIT32_64.cpp: >+ (JSC::DFG::SpeculativeJIT::compile): >+ * dfg/DFGSpeculativeJIT64.cpp: >+ (JSC::DFG::SpeculativeJIT::compile): >+ * dfg/DFGValidate.cpp: >+ * ftl/FTLAbstractHeapRepository.h: >+ * ftl/FTLLowerDFGToB3.cpp: >+ (JSC::FTL::DFG::LowerDFGToB3::compilePutStructure): >+ (JSC::FTL::DFG::LowerDFGToB3::compileArraySlice): >+ (JSC::FTL::DFG::LowerDFGToB3::compileNewArrayWithSpread): >+ (JSC::FTL::DFG::LowerDFGToB3::compileNewArrayBuffer): >+ (JSC::FTL::DFG::LowerDFGToB3::compileCallOrConstructVarargsSpread): >+ (JSC::FTL::DFG::LowerDFGToB3::compileForwardVarargsWithSpread): >+ (JSC::FTL::DFG::LowerDFGToB3::storeStructure): >+ (JSC::FTL::DFG::LowerDFGToB3::isArrayTypeForArrayify): >+ * ftl/FTLOperations.cpp: >+ (JSC::FTL::operationMaterializeObjectInOSR): >+ * generate-bytecode-files: >+ * interpreter/Interpreter.cpp: >+ (JSC::sizeOfVarargs): >+ (JSC::loadVarargs): >+ * jit/AssemblyHelpers.cpp: >+ (JSC::AssemblyHelpers::emitStoreStructureWithTypeInfo): >+ * jit/AssemblyHelpers.h: >+ (JSC::AssemblyHelpers::emitStoreStructureWithTypeInfo): >+ * jit/JITOperations.cpp: >+ * jit/JITPropertyAccess.cpp: >+ (JSC::JIT::emit_op_put_by_val): >+ (JSC::JIT::emitSlow_op_put_by_val): >+ * llint/LowLevelInterpreter.asm: >+ * llint/LowLevelInterpreter32_64.asm: >+ * llint/LowLevelInterpreter64.asm: >+ * runtime/Butterfly.h: >+ (JSC::ContiguousData::Data::Data): >+ (JSC::ContiguousData::Data::operator=): >+ (JSC::ContiguousData::Data::set): >+ (JSC::ContiguousData::Data::operator T&): >+ (JSC::ContiguousData::atUnsafe): >+ (JSC::ContiguousData::at const): Deleted. >+ (JSC::ContiguousData::at): Deleted. >+ * runtime/ButterflyInlines.h: >+ (JSC::ContiguousData<T>::at const): >+ (JSC::ContiguousData<T>::at): >+ * runtime/ClonedArguments.cpp: >+ (JSC::ClonedArguments::createEmpty): >+ * runtime/CommonSlowPaths.cpp: >+ (JSC::SLOW_PATH_DECL): >+ * runtime/IndexingType.cpp: >+ (JSC::dumpIndexingType): >+ * runtime/IndexingType.h: >+ (JSC::hasIndexedProperties): >+ (JSC::hasUndecided): >+ (JSC::hasInt32): >+ (JSC::hasDouble): >+ (JSC::hasContiguous): >+ (JSC::hasArrayStorage): >+ (JSC::hasAnyArrayStorage): >+ (JSC::hasSlowPutArrayStorage): >+ (JSC::shouldUseSlowPut): >+ (JSC::isCopyOnWrite): >+ (JSC::arrayIndexFromIndexingType): >+ * runtime/JSArray.cpp: >+ (JSC::JSArray::tryCreateUninitializedRestricted): >+ (JSC::JSArray::appendMemcpy): >+ (JSC::JSArray::setLength): >+ (JSC::JSArray::pop): >+ (JSC::JSArray::fastSlice): >+ (JSC::JSArray::shiftCountWithAnyIndexingType): >+ (JSC::JSArray::unshiftCountWithAnyIndexingType): >+ (JSC::JSArray::fillArgList): >+ (JSC::JSArray::copyToArguments): >+ * runtime/JSArrayInlines.h: >+ (JSC::JSArray::pushInline): >+ * runtime/JSCell.h: >+ * runtime/JSCellInlines.h: >+ (JSC::JSCell::JSCell): >+ (JSC::JSCell::finishCreation): >+ (JSC::JSCell::indexingType const): >+ (JSC::JSCell::indexingMode const): >+ (JSC::JSCell::setStructure): >+ * runtime/JSFixedArray.h: >+ * runtime/JSGlobalObject.cpp: >+ (JSC::JSGlobalObject::init): >+ (JSC::JSGlobalObject::haveABadTime): >+ (JSC::JSGlobalObject::visitChildren): >+ * runtime/JSGlobalObject.h: >+ (JSC::JSGlobalObject::originalArrayStructureForIndexingType const): >+ (JSC::JSGlobalObject::arrayStructureForIndexingTypeDuringAllocation const): >+ (JSC::JSGlobalObject::isOriginalArrayStructure): >+ * runtime/JSImmutableButterfly.cpp: Added. >+ (JSC::JSImmutableButterfly::visitChildren): >+ (JSC::JSImmutableButterfly::copyToArguments): >+ * runtime/JSImmutableButterfly.h: Added. >+ (JSC::JSImmutableButterfly::createStructure): >+ (JSC::JSImmutableButterfly::tryCreate): >+ (JSC::JSImmutableButterfly::create): >+ (JSC::JSImmutableButterfly::publicLength const): >+ (JSC::JSImmutableButterfly::vectorLength const): >+ (JSC::JSImmutableButterfly::length const): >+ (JSC::JSImmutableButterfly::toButterfly const): >+ (JSC::JSImmutableButterfly::fromButterfly): >+ (JSC::JSImmutableButterfly::get const): >+ (JSC::JSImmutableButterfly::subspaceFor): >+ (JSC::JSImmutableButterfly::setIndex): >+ (JSC::JSImmutableButterfly::allocationSize): >+ (JSC::JSImmutableButterfly::JSImmutableButterfly): >+ * runtime/JSObject.cpp: >+ (JSC::JSObject::markAuxiliaryAndVisitOutOfLineProperties): >+ (JSC::JSObject::visitButterflyImpl): >+ (JSC::JSObject::getOwnPropertySlotByIndex): >+ (JSC::JSObject::putByIndex): >+ (JSC::JSObject::createInitialInt32): >+ (JSC::JSObject::createInitialDouble): >+ (JSC::JSObject::createInitialContiguous): >+ (JSC::JSObject::convertUndecidedToInt32): >+ (JSC::JSObject::convertUndecidedToDouble): >+ (JSC::JSObject::convertUndecidedToContiguous): >+ (JSC::JSObject::convertInt32ToDouble): >+ (JSC::JSObject::convertInt32ToArrayStorage): >+ (JSC::JSObject::convertDoubleToContiguous): >+ (JSC::JSObject::convertDoubleToArrayStorage): >+ (JSC::JSObject::convertContiguousToArrayStorage): >+ (JSC::JSObject::createInitialForValueAndSet): >+ (JSC::JSObject::convertInt32ForValue): >+ (JSC::JSObject::convertFromCopyOnWrite): >+ (JSC::JSObject::ensureWritableInt32Slow): >+ (JSC::JSObject::ensureWritableDoubleSlow): >+ (JSC::JSObject::ensureWritableContiguousSlow): >+ (JSC::JSObject::ensureArrayStorageSlow): >+ (JSC::JSObject::ensureArrayStorageExistsAndEnterDictionaryIndexingMode): >+ (JSC::JSObject::switchToSlowPutArrayStorage): >+ (JSC::JSObject::deletePropertyByIndex): >+ (JSC::JSObject::getOwnPropertyNames): >+ (JSC::canDoFastPutDirectIndex): >+ (JSC::JSObject::defineOwnIndexedProperty): >+ (JSC::JSObject::putByIndexBeyondVectorLengthWithoutAttributes): >+ (JSC::JSObject::putByIndexBeyondVectorLengthWithArrayStorage): >+ (JSC::JSObject::putByIndexBeyondVectorLength): >+ (JSC::JSObject::countElements): >+ (JSC::JSObject::ensureLengthSlow): >+ (JSC::JSObject::getEnumerableLength): >+ (JSC::JSObject::ensureInt32Slow): Deleted. >+ (JSC::JSObject::ensureDoubleSlow): Deleted. >+ (JSC::JSObject::ensureContiguousSlow): Deleted. >+ * runtime/JSObject.h: >+ (JSC::JSObject::putDirectIndex): >+ (JSC::JSObject::canGetIndexQuickly): >+ (JSC::JSObject::getIndexQuickly): >+ (JSC::JSObject::tryGetIndexQuickly const): >+ (JSC::JSObject::canSetIndexQuickly): >+ (JSC::JSObject::setIndexQuickly): >+ (JSC::JSObject::initializeIndex): >+ (JSC::JSObject::initializeIndexWithoutBarrier): >+ (JSC::JSObject::ensureWritableInt32): >+ (JSC::JSObject::ensureWritableDouble): >+ (JSC::JSObject::ensureWritableContiguous): >+ (JSC::JSObject::ensureLength): >+ (JSC::JSObject::ensureInt32): Deleted. >+ (JSC::JSObject::ensureDouble): Deleted. >+ (JSC::JSObject::ensureContiguous): Deleted. >+ * runtime/JSObjectInlines.h: >+ (JSC::JSObject::putDirectInternal): >+ * runtime/JSType.h: >+ * runtime/RegExpMatchesArray.h: >+ (JSC::tryCreateUninitializedRegExpMatchesArray): >+ * runtime/Structure.cpp: >+ (JSC::Structure::Structure): >+ (JSC::Structure::addNewPropertyTransition): >+ (JSC::Structure::nonPropertyTransition): >+ * runtime/Structure.h: >+ * runtime/StructureIDBlob.h: >+ (JSC::StructureIDBlob::StructureIDBlob): >+ (JSC::StructureIDBlob::indexingModeIncludingHistory const): >+ (JSC::StructureIDBlob::setIndexingModeIncludingHistory): >+ (JSC::StructureIDBlob::indexingModeIncludingHistoryOffset): >+ (JSC::StructureIDBlob::indexingTypeIncludingHistory const): Deleted. >+ (JSC::StructureIDBlob::setIndexingTypeIncludingHistory): Deleted. >+ (JSC::StructureIDBlob::indexingTypeIncludingHistoryOffset): Deleted. >+ * runtime/StructureTransitionTable.h: >+ (JSC::newIndexingType): >+ * runtime/VM.cpp: >+ (JSC::VM::VM): >+ * runtime/VM.h: >+ > 2018-04-30 Keith Miller <keith_miller@apple.com> > > Move the MayBePrototype JSCell header bit to InlineTypeFlags >diff --git a/Source/WebCore/ChangeLog b/Source/WebCore/ChangeLog >index 895e2ef9312b218c2c6b621c7208ec1646ab2b6b..73dfcecc6b04cdea15c815e2427ffd7b5ba6c812 100644 >--- a/Source/WebCore/ChangeLog >+++ b/Source/WebCore/ChangeLog >@@ -1,3 +1,14 @@ >+2018-05-18 Keith Miller <keith_miller@apple.com> >+ >+ We should have a CoW storage for NewArrayBuffer arrays. >+ https://bugs.webkit.org/show_bug.cgi?id=185003 >+ >+ Reviewed by NOBODY (OOPS!). >+ >+ * bindings/js/JSDOMConvertSequences.h: >+ (WebCore::Detail::NumericSequenceConverter::convertArray): >+ (WebCore::Detail::SequenceConverter::convertArray): >+ > 2018-04-30 JF Bastien <jfbastien@apple.com> > > Use some C++17 features >diff --git a/Source/JavaScriptCore/JavaScriptCore.xcodeproj/project.pbxproj b/Source/JavaScriptCore/JavaScriptCore.xcodeproj/project.pbxproj >index 94435d8ae573baedffb1f6ad95dd0ce0225b5e73..68cd7a02f21bb8d19efce0293eaee65b5a55c6be 100644 >--- a/Source/JavaScriptCore/JavaScriptCore.xcodeproj/project.pbxproj >+++ b/Source/JavaScriptCore/JavaScriptCore.xcodeproj/project.pbxproj >@@ -1028,6 +1028,7 @@ > 53E777E41E92E265007CBEC4 /* WasmModuleInformation.h in Headers */ = {isa = PBXBuildFile; fileRef = 53E777E21E92E265007CBEC4 /* WasmModuleInformation.h */; }; > 53E9E0AC1EAE83DF00FEE251 /* WasmMachineThreads.h in Headers */ = {isa = PBXBuildFile; fileRef = 53E9E0AA1EAE83DE00FEE251 /* WasmMachineThreads.h */; }; > 53E9E0AF1EAEC45700FEE251 /* WasmTierUpCount.h in Headers */ = {isa = PBXBuildFile; fileRef = 53E9E0AE1EAEC45700FEE251 /* WasmTierUpCount.h */; settings = {ATTRIBUTES = (Private, ); }; }; >+ 53F11F41209138D700E411A7 /* JSImmutableButterfly.h in Headers */ = {isa = PBXBuildFile; fileRef = 53F11F40209138D700E411A7 /* JSImmutableButterfly.h */; }; > 53F40E851D58F9770099A1B6 /* WasmSections.h in Headers */ = {isa = PBXBuildFile; fileRef = 53F40E841D58F9770099A1B6 /* WasmSections.h */; }; > 53F40E8B1D5901BB0099A1B6 /* WasmFunctionParser.h in Headers */ = {isa = PBXBuildFile; fileRef = 53F40E8A1D5901BB0099A1B6 /* WasmFunctionParser.h */; }; > 53F40E8D1D5901F20099A1B6 /* WasmParser.h in Headers */ = {isa = PBXBuildFile; fileRef = 53F40E8C1D5901F20099A1B6 /* WasmParser.h */; }; >@@ -3285,6 +3286,7 @@ > 535557131D9D9EA5006D583B /* WasmMemory.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = WasmMemory.h; sourceTree = "<group>"; }; > 535557151D9DFA32006D583B /* WasmMemory.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = WasmMemory.cpp; sourceTree = "<group>"; }; > 535C246B1F7A1777006EC40E /* UnifiedSource136.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = UnifiedSource136.cpp; sourceTree = "<group>"; }; >+ 53696E5720A3A70200D7E01E /* BytecodeStructs.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = BytecodeStructs.h; sourceTree = "<group>"; }; > 536B30871F71C5380037FC33 /* UnifiedSource119.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = UnifiedSource119.cpp; sourceTree = "<group>"; }; > 536B30881F71C5380037FC33 /* UnifiedSource125.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = UnifiedSource125.cpp; sourceTree = "<group>"; }; > 536B30891F71C5380037FC33 /* UnifiedSource131.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = UnifiedSource131.cpp; sourceTree = "<group>"; }; >@@ -3448,6 +3450,8 @@ > 53E9E0A91EAE83DE00FEE251 /* WasmMachineThreads.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = WasmMachineThreads.cpp; sourceTree = "<group>"; }; > 53E9E0AA1EAE83DE00FEE251 /* WasmMachineThreads.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = WasmMachineThreads.h; sourceTree = "<group>"; }; > 53E9E0AE1EAEC45700FEE251 /* WasmTierUpCount.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = WasmTierUpCount.h; sourceTree = "<group>"; }; >+ 53F11F40209138D700E411A7 /* JSImmutableButterfly.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = JSImmutableButterfly.h; sourceTree = "<group>"; }; >+ 53F11F422091749800E411A7 /* JSImmutableButterfly.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = JSImmutableButterfly.cpp; sourceTree = "<group>"; }; > 53F256E11B87E28000B4B768 /* JSTypedArrayViewPrototype.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = JSTypedArrayViewPrototype.cpp; sourceTree = "<group>"; }; > 53F40E841D58F9770099A1B6 /* WasmSections.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = WasmSections.h; sourceTree = "<group>"; }; > 53F40E8A1D5901BB0099A1B6 /* WasmFunctionParser.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = WasmFunctionParser.h; sourceTree = "<group>"; }; >@@ -6168,6 +6172,7 @@ > 8B3BF5E31E3D365A0076A87A /* AsyncGeneratorPrototype.lut.h */, > 996B73071BD9FA2C00331B84 /* BooleanPrototype.lut.h */, > 6514F21718B3E1670098FF8B /* Bytecodes.h */, >+ 53696E5720A3A70200D7E01E /* BytecodeStructs.h */, > A53243951856A475002ED692 /* CombinedDomains.json */, > 996B73081BD9FA2C00331B84 /* DateConstructor.lut.h */, > BCD203E70E1718F4002C7E82 /* DatePrototype.lut.h */, >@@ -6670,6 +6675,7 @@ > 865A30F0135007E100CDB49E /* JSCJSValueInlines.h */, > FE2B0B681FD0D2970075DA5F /* JSCPoison.cpp */, > FE2B0B701FD8C4630075DA5F /* JSCPoison.h */, >+ FE7497E5209001B00003565B /* JSCPtrTag.h */, > 72AAF7CB1D0D318B005E60BE /* JSCustomGetterSetterFunction.cpp */, > 72AAF7CC1D0D318B005E60BE /* JSCustomGetterSetterFunction.h */, > 0F2B66BD17B6B5AB00A7AE3F /* JSDataView.cpp */, >@@ -6707,6 +6713,8 @@ > BC756FC60E2031B200DE7D12 /* JSGlobalObjectFunctions.cpp */, > BC756FC70E2031B200DE7D12 /* JSGlobalObjectFunctions.h */, > 79B819921DD25CF500DDC714 /* JSGlobalObjectInlines.h */, >+ 53F11F422091749800E411A7 /* JSImmutableButterfly.cpp */, >+ 53F11F40209138D700E411A7 /* JSImmutableButterfly.h */, > 0F2B66CA17B6B5AB00A7AE3F /* JSInt16Array.h */, > 0F2B66CB17B6B5AB00A7AE3F /* JSInt32Array.h */, > 0F2B66C917B6B5AB00A7AE3F /* JSInt8Array.h */, >@@ -6755,7 +6763,6 @@ > 2A05ABD41961DF2400341750 /* JSPropertyNameEnumerator.h */, > 862553CE16136AA5009F17D0 /* JSProxy.cpp */, > 862553CF16136AA5009F17D0 /* JSProxy.h */, >- FE7497E5209001B00003565B /* JSCPtrTag.h */, > 534638721E70D01500F12AC1 /* JSRunLoopTimer.cpp */, > 534638701E70CF3D00F12AC1 /* JSRunLoopTimer.h */, > 14874AE115EBDE4A002E3587 /* JSScope.cpp */, >@@ -9000,6 +9007,7 @@ > A5D2E665195E174000A518E7 /* JSContextRefInternal.h in Headers */, > 148CD1D8108CF902008163C6 /* JSContextRefPrivate.h in Headers */, > FE2B0B731FD9EF700075DA5F /* JSCPoison.h in Headers */, >+ FE7497E6209001B10003565B /* JSCPtrTag.h in Headers */, > A72028B81797601E0098028C /* JSCTestRunnerUtils.h in Headers */, > 72AAF7CE1D0D31B3005E60BE /* JSCustomGetterSetterFunction.h in Headers */, > 0F2B66EC17B6B5AB00A7AE3F /* JSDataView.h in Headers */, >@@ -9036,6 +9044,7 @@ > A50E4B6418809DD50068A46D /* JSGlobalObjectRuntimeAgent.h in Headers */, > A503FA2A188F105900110F14 /* JSGlobalObjectScriptDebugServer.h in Headers */, > 0F0CAEFC1EC4DA6B00970D12 /* JSHeapFinalizerPrivate.h in Headers */, >+ 53F11F41209138D700E411A7 /* JSImmutableButterfly.h in Headers */, > A513E5C0185BFACC007E95AD /* JSInjectedScriptHost.h in Headers */, > A513E5C2185BFACC007E95AD /* JSInjectedScriptHostPrototype.h in Headers */, > 0F2B66F817B6B5AB00A7AE3F /* JSInt16Array.h in Headers */, >@@ -9075,7 +9084,6 @@ > 7C008CDB187124BB00955C24 /* JSPromiseDeferred.h in Headers */, > 7C184E1F17BEE22E007CB63A /* JSPromisePrototype.h in Headers */, > 996B731F1BDA08EF00331B84 /* JSPromisePrototype.lut.h in Headers */, >- FE7497E6209001B10003565B /* JSCPtrTag.h in Headers */, > 2A05ABD61961DF2400341750 /* JSPropertyNameEnumerator.h in Headers */, > 862553D216136E1A009F17D0 /* JSProxy.h in Headers */, > A552C3801ADDB8FE00139726 /* JSRemoteInspector.h in Headers */, >diff --git a/Source/JavaScriptCore/Sources.txt b/Source/JavaScriptCore/Sources.txt >index eb467ea98139dfbcad9021ee1812192906e51b35..86f888b4dcf46e58219bf677c9d216574bcbe681 100644 >--- a/Source/JavaScriptCore/Sources.txt >+++ b/Source/JavaScriptCore/Sources.txt >@@ -805,6 +805,7 @@ runtime/JSGlobalLexicalEnvironment.cpp > runtime/JSGlobalObject.cpp > runtime/JSGlobalObjectDebuggable.cpp > runtime/JSGlobalObjectFunctions.cpp >+runtime/JSImmutableButterfly.cpp > runtime/JSInternalPromise.cpp > runtime/JSInternalPromiseConstructor.cpp > runtime/JSInternalPromiseDeferred.cpp >diff --git a/Source/JavaScriptCore/bytecode/ArrayAllocationProfile.cpp b/Source/JavaScriptCore/bytecode/ArrayAllocationProfile.cpp >index 41ce23c385fef66412cbce30169b363f901c137f..bd73651ab22cdc1015b67fa8b8c366aeea133b2b 100644 >--- a/Source/JavaScriptCore/bytecode/ArrayAllocationProfile.cpp >+++ b/Source/JavaScriptCore/bytecode/ArrayAllocationProfile.cpp >@@ -28,6 +28,8 @@ > > #include "JSCInlines.h" > >+#include <algorithm> >+ > namespace JSC { > > void ArrayAllocationProfile::updateProfile() >@@ -50,7 +52,14 @@ void ArrayAllocationProfile::updateProfile() > if (!lastArray) > return; > if (LIKELY(Options::useArrayAllocationProfiling())) { >- m_currentIndexingType = leastUpperBoundOfIndexingTypes(m_currentIndexingType, lastArray->indexingType()); >+ // The basic model here is that we will upgrade ourselves to whatever the CoW version of lastArray is except ArrayStorage since we don't have CoW ArrayStorage. >+ IndexingType indexingType = leastUpperBoundOfIndexingTypes(m_currentIndexingType & IndexingTypeMask, lastArray->indexingType()); >+ if (isCopyOnWrite(m_currentIndexingType)) { >+ if (indexingType > ArrayWithContiguous) >+ indexingType = ArrayWithContiguous; >+ indexingType |= CopyOnWrite; >+ } >+ m_currentIndexingType = indexingType; > m_largestSeenVectorLength = std::min(std::max(m_largestSeenVectorLength, lastArray->getVectorLength()), BASE_CONTIGUOUS_VECTOR_LEN_MAX); > } > m_lastArray = nullptr; >diff --git a/Source/JavaScriptCore/bytecode/ArrayAllocationProfile.h b/Source/JavaScriptCore/bytecode/ArrayAllocationProfile.h >index 1bfb470deeb733ea1cca90398e962bdde8933dcc..c233deb7a24114553257a9ab8fc874e1e8709a6f 100644 >--- a/Source/JavaScriptCore/bytecode/ArrayAllocationProfile.h >+++ b/Source/JavaScriptCore/bytecode/ArrayAllocationProfile.h >@@ -56,7 +56,7 @@ public: > } > > JS_EXPORT_PRIVATE void updateProfile(); >- >+ > static IndexingType selectIndexingTypeFor(ArrayAllocationProfile* profile) > { > if (!profile) >@@ -71,6 +71,8 @@ public: > return lastArray; > } > >+ void initializeIndexingMode(IndexingType recommendedIndexingMode) { m_currentIndexingType = recommendedIndexingMode; } >+ > private: > > IndexingType m_currentIndexingType { ArrayWithUndecided }; >diff --git a/Source/JavaScriptCore/bytecode/ArrayProfile.cpp b/Source/JavaScriptCore/bytecode/ArrayProfile.cpp >index cb1b7585b22ec31471f84c2f1567d6858b16848c..d2cf2b99e38eb0e872a8ca69d36e8a5d863aac91 100644 >--- a/Source/JavaScriptCore/bytecode/ArrayProfile.cpp >+++ b/Source/JavaScriptCore/bytecode/ArrayProfile.cpp >@@ -72,6 +72,12 @@ void dumpArrayModes(PrintStream& out, ArrayModes arrayModes) > out.print(comma, "ArrayWithArrayStorage"); > if (arrayModes & asArrayModes(ArrayWithSlowPutArrayStorage)) > out.print(comma, "ArrayWithSlowPutArrayStorage"); >+ if (arrayModes & asArrayModes(CopyOnWriteArrayWithInt32)) >+ out.print(comma, "CopyOnWriteArrayWithInt32"); >+ if (arrayModes & asArrayModes(CopyOnWriteArrayWithDouble)) >+ out.print(comma, "CopyOnWriteArrayWithDouble"); >+ if (arrayModes & asArrayModes(CopyOnWriteArrayWithContiguous)) >+ out.print(comma, "CopyOnWriteArrayWithContiguous"); > > if (arrayModes & Int8ArrayMode) > out.print(comma, "Int8ArrayMode"); >@@ -130,46 +136,19 @@ CString ArrayProfile::briefDescription(const ConcurrentJSLocker& locker, CodeBlo > CString ArrayProfile::briefDescriptionWithoutUpdating(const ConcurrentJSLocker&) > { > StringPrintStream out; >- >- bool hasPrinted = false; >- >- if (m_observedArrayModes) { >- if (hasPrinted) >- out.print(", "); >- out.print(ArrayModesDump(m_observedArrayModes)); >- hasPrinted = true; >- } >- >- if (m_mayStoreToHole) { >- if (hasPrinted) >- out.print(", "); >- out.print("Hole"); >- hasPrinted = true; >- } >- >- if (m_outOfBounds) { >- if (hasPrinted) >- out.print(", "); >- out.print("OutOfBounds"); >- hasPrinted = true; >- } >- >- if (m_mayInterceptIndexedAccesses) { >- if (hasPrinted) >- out.print(", "); >- out.print("Intercept"); >- hasPrinted = true; >- } >- >- if (m_usesOriginalArrayStructures) { >- if (hasPrinted) >- out.print(", "); >- out.print("Original"); >- hasPrinted = true; >- } >- >- UNUSED_PARAM(hasPrinted); >- >+ CommaPrinter comma; >+ >+ if (m_observedArrayModes) >+ out.print(comma, ArrayModesDump(m_observedArrayModes)); >+ if (m_mayStoreToHole) >+ out.print(comma, "Hole"); >+ if (m_outOfBounds) >+ out.print(comma, "OutOfBounds"); >+ if (m_mayInterceptIndexedAccesses) >+ out.print(comma, "Intercept"); >+ if (m_usesOriginalArrayStructures) >+ out.print(comma, "Original"); >+ > return out.toCString(); > } > >diff --git a/Source/JavaScriptCore/bytecode/ArrayProfile.h b/Source/JavaScriptCore/bytecode/ArrayProfile.h >index c10c5e2c16addfcb11c6133cc09ca05c89476869..2a9a36e6898cc869268946a5a228c303d6ea3471 100644 >--- a/Source/JavaScriptCore/bytecode/ArrayProfile.h >+++ b/Source/JavaScriptCore/bytecode/ArrayProfile.h >@@ -35,22 +35,42 @@ class CodeBlock; > class LLIntOffsetsExtractor; > > // This is a bitfield where each bit represents an type of array access that we have seen. >-// There are 16 indexing types that use the lower bits. >+// There are 19 indexing types that use the lower bits. > // There are 9 typed array types taking the bits 16 to 25. > typedef unsigned ArrayModes; > >-const ArrayModes Int8ArrayMode = 1 << 16; >-const ArrayModes Int16ArrayMode = 1 << 17; >-const ArrayModes Int32ArrayMode = 1 << 18; >-const ArrayModes Uint8ArrayMode = 1 << 19; >-const ArrayModes Uint8ClampedArrayMode = 1 << 20; >-const ArrayModes Uint16ArrayMode = 1 << 21; >-const ArrayModes Uint32ArrayMode = 1 << 22; >-const ArrayModes Float32ArrayMode = 1 << 23; >-const ArrayModes Float64ArrayMode = 1 << 24; >+const ArrayModes CopyOnWriteArrayWithInt32ArrayMode = 1 << 16; >+const ArrayModes CopyOnWriteArrayWithDoubleArrayMode = 1 << 17; >+const ArrayModes CopyOnWriteArrayWithContiguousArrayMode = 1 << 18; > >-#define asArrayModes(type) \ >- (static_cast<unsigned>(1) << static_cast<unsigned>(type)) >+const ArrayModes Int8ArrayMode = 1 << 19; >+const ArrayModes Int16ArrayMode = 1 << 20; >+const ArrayModes Int32ArrayMode = 1 << 21; >+const ArrayModes Uint8ArrayMode = 1 << 22; >+const ArrayModes Uint8ClampedArrayMode = 1 << 23; >+const ArrayModes Uint16ArrayMode = 1 << 24; >+const ArrayModes Uint32ArrayMode = 1 << 25; >+const ArrayModes Float32ArrayMode = 1 << 26; >+const ArrayModes Float64ArrayMode = 1 << 27; >+ >+inline constexpr ArrayModes asArrayModes(IndexingType indexingMode) >+{ >+ if (isCopyOnWrite(indexingMode)) { >+ switch (indexingMode) { >+ case CopyOnWriteArrayWithInt32: >+ return CopyOnWriteArrayWithInt32ArrayMode; >+ case CopyOnWriteArrayWithDouble: >+ return CopyOnWriteArrayWithDoubleArrayMode; >+ case CopyOnWriteArrayWithContiguous: >+ return CopyOnWriteArrayWithContiguousArrayMode; >+ default: >+ UNREACHABLE_FOR_PLATFORM(); >+ return 0; >+ } >+ } >+ >+ return static_cast<unsigned>(1) << static_cast<unsigned>(indexingMode); >+} > > #define ALL_TYPED_ARRAY_MODES \ > (Int8ArrayMode \ >@@ -73,6 +93,11 @@ const ArrayModes Float64ArrayMode = 1 << 24; > | asArrayModes(NonArrayWithSlowPutArrayStorage) \ > | ALL_TYPED_ARRAY_MODES) > >+#define ALL_COPY_ON_WRITE_ARRAY_MODES \ >+ (CopyOnWriteArrayWithInt32ArrayMode \ >+ | CopyOnWriteArrayWithDoubleArrayMode \ >+ | CopyOnWriteArrayWithContiguousArrayMode) >+ > #define ALL_ARRAY_ARRAY_MODES \ > (asArrayModes(ArrayClass) \ > | asArrayModes(ArrayWithUndecided) \ >@@ -80,7 +105,8 @@ const ArrayModes Float64ArrayMode = 1 << 24; > | asArrayModes(ArrayWithDouble) \ > | asArrayModes(ArrayWithContiguous) \ > | asArrayModes(ArrayWithArrayStorage) \ >- | asArrayModes(ArrayWithSlowPutArrayStorage)) >+ | asArrayModes(ArrayWithSlowPutArrayStorage) \ >+ | ALL_COPY_ON_WRITE_ARRAY_MODES) > > #define ALL_ARRAY_MODES (ALL_NON_ARRAY_ARRAY_MODES | ALL_ARRAY_ARRAY_MODES) > >@@ -109,7 +135,8 @@ inline ArrayModes arrayModeFromStructure(Structure* structure) > case NotTypedArray: > break; > } >- return asArrayModes(structure->indexingType()); >+ >+ return asArrayModes(structure->indexingMode()); > } > > void dumpArrayModes(PrintStream&, ArrayModes); >@@ -137,7 +164,10 @@ inline bool arrayModesAlreadyChecked(ArrayModes proven, ArrayModes expected) > > inline bool arrayModesInclude(ArrayModes arrayModes, IndexingType shape) > { >- return !!(arrayModes & (asArrayModes(NonArray | shape) | asArrayModes(ArrayClass | shape))); >+ ArrayModes modes = asArrayModes(NonArray | shape) | asArrayModes(ArrayClass | shape); >+ if (hasInt32(shape) || hasDouble(shape) || hasContiguous(shape)) >+ modes |= asArrayModes(ArrayClass | shape | CopyOnWrite); >+ return !!(arrayModes & modes); > } > > inline bool shouldUseSlowPutArrayStorage(ArrayModes arrayModes) >@@ -175,6 +205,11 @@ inline bool hasSeenNonArray(ArrayModes arrayModes) > return arrayModes & ALL_NON_ARRAY_ARRAY_MODES; > } > >+inline bool hasSeenCopyOnWriteArray(ArrayModes arrayModes) >+{ >+ return arrayModes & ALL_COPY_ON_WRITE_ARRAY_MODES; >+} >+ > class ArrayProfile { > public: > ArrayProfile() >@@ -226,7 +261,7 @@ public: > bool outOfBounds(const ConcurrentJSLocker&) const { return m_outOfBounds; } > > bool usesOriginalArrayStructures(const ConcurrentJSLocker&) const { return m_usesOriginalArrayStructures; } >- >+ > CString briefDescription(const ConcurrentJSLocker&, CodeBlock*); > CString briefDescriptionWithoutUpdating(const ConcurrentJSLocker&); > >diff --git a/Source/JavaScriptCore/bytecode/BytecodeList.json b/Source/JavaScriptCore/bytecode/BytecodeList.json >index 5628df5b462163eb296321fe858d03b6d9f76e55..473abe78f5aaa7995049892b39bc5a79833ab612 100644 >--- a/Source/JavaScriptCore/bytecode/BytecodeList.json >+++ b/Source/JavaScriptCore/bytecode/BytecodeList.json >@@ -20,9 +20,12 @@ > { "name" : "op_new_object", "length" : 4 }, > { "name" : "op_new_array", "length" : 5 }, > { "name" : "op_new_array_with_size", "length" : 4 }, >+ { "name" : "op_new_array_buffer", "offsets" : >+ [{"dst" : "int"}, >+ {"immutableButterfly" : "int"}, >+ {"profile" : "ArrayAllocationProfile*"}]}, > { "name" : "op_new_array_with_spread", "length" : 5 }, > { "name" : "op_spread", "length" : 3 }, >- { "name" : "op_new_array_buffer", "length" : 4 }, > { "name" : "op_new_regexp", "length" : 3 }, > { "name" : "op_mov", "length" : 3 }, > { "name" : "op_not", "length" : 3 }, >diff --git a/Source/JavaScriptCore/bytecode/CodeBlock.cpp b/Source/JavaScriptCore/bytecode/CodeBlock.cpp >index cf6684ca829020388904ed8fc86ea5226138cdb9..b74a85987fb7ec250b06b5dd790dbd672566caae 100644 >--- a/Source/JavaScriptCore/bytecode/CodeBlock.cpp >+++ b/Source/JavaScriptCore/bytecode/CodeBlock.cpp >@@ -35,6 +35,7 @@ > #include "BytecodeDumper.h" > #include "BytecodeGenerator.h" > #include "BytecodeLivenessAnalysis.h" >+#include "BytecodeStructs.h" > #include "BytecodeUseDef.h" > #include "CallLinkStatus.h" > #include "CodeBlockSet.h" >@@ -591,12 +592,19 @@ bool CodeBlock::finishCreation(VM& vm, ScriptExecutable* ownerExecutable, Unlink > } > > case op_new_array: >- case op_new_array_buffer: >- case op_new_array_with_size: { >- int arrayAllocationProfileIndex = pc[opLength - 1].u.operand; >- instructions[i + opLength - 1] = &m_arrayAllocationProfiles[arrayAllocationProfileIndex]; >+ case op_new_array_with_size: >+ case op_new_array_buffer: { >+ unsigned arrayAllocationProfileIndex; >+ IndexingType recommendedIndexingType; >+ std::tie(arrayAllocationProfileIndex, recommendedIndexingType) = UnlinkedCodeBlock::decopressArrayAllocationProfile(pc[opLength - 1].u.operand); >+ >+ ArrayAllocationProfile* profile = &m_arrayAllocationProfiles[arrayAllocationProfileIndex]; >+ if (pc[0].u.opcode == op_new_array_buffer) >+ profile->initializeIndexingMode(recommendedIndexingType); >+ instructions[i + opLength - 1] = profile; > break; > } >+ > case op_new_object: { > int objectAllocationProfileIndex = pc[opLength - 1].u.operand; > ObjectAllocationProfile* objectAllocationProfile = &m_objectAllocationProfiles[objectAllocationProfileIndex]; >diff --git a/Source/JavaScriptCore/bytecode/InlineAccess.cpp b/Source/JavaScriptCore/bytecode/InlineAccess.cpp >index dbb07a8bb16a0235ca4fe7eafb3499b17c802866..c18ce2729faaab80f701799d95c321d8a995e8f0 100644 >--- a/Source/JavaScriptCore/bytecode/InlineAccess.cpp >+++ b/Source/JavaScriptCore/bytecode/InlineAccess.cpp >@@ -265,7 +265,7 @@ bool InlineAccess::generateArrayLength(StructureStubInfo& stubInfo, JSArray* arr > GPRReg scratch = getScratchRegister(stubInfo); > > jit.load8(CCallHelpers::Address(base, JSCell::indexingTypeAndMiscOffset()), scratch); >- jit.and32(CCallHelpers::TrustedImm32(IsArray | IndexingShapeMask), scratch); >+ jit.and32(CCallHelpers::TrustedImm32(IndexingTypeMask), scratch); > auto branchToSlowPath = jit.patchableBranch32( > CCallHelpers::NotEqual, scratch, CCallHelpers::TrustedImm32(array->indexingType())); > jit.loadPtr(CCallHelpers::Address(base, JSObject::butterflyOffset()), value.payloadGPR()); >diff --git a/Source/JavaScriptCore/bytecode/UnlinkedCodeBlock.h b/Source/JavaScriptCore/bytecode/UnlinkedCodeBlock.h >index 6acb500f89de33e9c053c02f4907421570947d04..3d1d46d516a25512cde67f9833775476849fcdd2 100644 >--- a/Source/JavaScriptCore/bytecode/UnlinkedCodeBlock.h >+++ b/Source/JavaScriptCore/bytecode/UnlinkedCodeBlock.h >@@ -302,9 +302,16 @@ public: > > UnlinkedArrayProfile addArrayProfile() { return m_arrayProfileCount++; } > unsigned numberOfArrayProfiles() { return m_arrayProfileCount; } >- UnlinkedArrayAllocationProfile addArrayAllocationProfile() { return m_arrayAllocationProfileCount++; } >+ UnlinkedArrayAllocationProfile addArrayAllocationProfile(IndexingType recommendedIndexingType) { return (m_arrayAllocationProfileCount++) | recommendedIndexingType << 24; } > unsigned numberOfArrayAllocationProfiles() { return m_arrayAllocationProfileCount; } > UnlinkedObjectAllocationProfile addObjectAllocationProfile() { return m_objectAllocationProfileCount++; } >+ static std::tuple<unsigned, IndexingType> decopressArrayAllocationProfile(UnlinkedArrayAllocationProfile compressedProfile) >+ { >+ unsigned profile = (compressedProfile << 8) >> 8; >+ IndexingType recommendedIndexingType = compressedProfile >> 24; >+ return std::make_tuple<unsigned, IndexingType>(WTFMove(profile), WTFMove(recommendedIndexingType)); >+ >+ } > unsigned numberOfObjectAllocationProfiles() { return m_objectAllocationProfileCount; } > UnlinkedValueProfile addValueProfile() { return m_valueProfileCount++; } > unsigned numberOfValueProfiles() { return m_valueProfileCount; } >diff --git a/Source/JavaScriptCore/bytecompiler/BytecodeGenerator.cpp b/Source/JavaScriptCore/bytecompiler/BytecodeGenerator.cpp >index d1d4192a8ff3b9a3c708e944cb9dc415eccb91cd..d34dd79e67165266c4697ce7c597f17f8811ac38 100644 >--- a/Source/JavaScriptCore/bytecompiler/BytecodeGenerator.cpp >+++ b/Source/JavaScriptCore/bytecompiler/BytecodeGenerator.cpp >@@ -45,6 +45,7 @@ > #include "JSFixedArray.h" > #include "JSFunction.h" > #include "JSGeneratorFunction.h" >+#include "JSImmutableButterfly.h" > #include "JSLexicalEnvironment.h" > #include "JSTemplateObjectDescriptor.h" > #include "LowLevelInterpreter.h" >@@ -1284,9 +1285,9 @@ UnlinkedArrayProfile BytecodeGenerator::newArrayProfile() > return m_codeBlock->addArrayProfile(); > } > >-UnlinkedArrayAllocationProfile BytecodeGenerator::newArrayAllocationProfile() >+UnlinkedArrayAllocationProfile BytecodeGenerator::newArrayAllocationProfile(IndexingType recommendedIndexingType) > { >- return m_codeBlock->addArrayAllocationProfile(); >+ return m_codeBlock->addArrayAllocationProfile(recommendedIndexingType); > } > > UnlinkedObjectAllocationProfile BytecodeGenerator::newObjectAllocationProfile() >@@ -3177,16 +3178,16 @@ RegisterID* BytecodeGenerator::addTemplateObjectConstant(Ref<TemplateObjectDescr > return &m_constantPoolRegisters[index]; > } > >-RegisterID* BytecodeGenerator::emitNewArrayBuffer(RegisterID* dst, JSFixedArray* array) >+RegisterID* BytecodeGenerator::emitNewArrayBuffer(RegisterID* dst, JSImmutableButterfly* array, IndexingType recommendedIndexingType) > { > emitOpcode(op_new_array_buffer); > instructions().append(dst->index()); > instructions().append(addConstantValue(array)->index()); >- instructions().append(newArrayAllocationProfile()); >+ instructions().append(newArrayAllocationProfile(recommendedIndexingType)); > return dst; > } > >-RegisterID* BytecodeGenerator::emitNewArray(RegisterID* dst, ElementNode* elements, unsigned length) >+RegisterID* BytecodeGenerator::emitNewArray(RegisterID* dst, ElementNode* elements, unsigned length, IndexingType recommendedIndexingType) > { > Vector<RefPtr<RegisterID>, 16, UnsafeVectorOverflow> argv; > for (ElementNode* n = elements; n; n = n->next()) { >@@ -3204,7 +3205,7 @@ RegisterID* BytecodeGenerator::emitNewArray(RegisterID* dst, ElementNode* elemen > instructions().append(dst->index()); > instructions().append(argv.size() ? argv[0]->index() : 0); // argv > instructions().append(argv.size()); // argc >- instructions().append(newArrayAllocationProfile()); >+ instructions().append(newArrayAllocationProfile(recommendedIndexingType)); > return dst; > } > >@@ -3256,7 +3257,7 @@ RegisterID* BytecodeGenerator::emitNewArrayWithSize(RegisterID* dst, RegisterID* > emitOpcode(op_new_array_with_size); > instructions().append(dst->index()); > instructions().append(length->index()); >- instructions().append(newArrayAllocationProfile()); >+ instructions().append(newArrayAllocationProfile(ArrayWithUndecided)); > > return dst; > } >@@ -3450,7 +3451,7 @@ ExpectedFunction BytecodeGenerator::emitExpectedFunctionSnippet(RegisterID* dst, > instructions().append(dst->index()); > instructions().append(0); > instructions().append(0); >- instructions().append(newArrayAllocationProfile()); >+ instructions().append(newArrayAllocationProfile(ArrayWithUndecided)); > } > } > break; >diff --git a/Source/JavaScriptCore/bytecompiler/BytecodeGenerator.h b/Source/JavaScriptCore/bytecompiler/BytecodeGenerator.h >index b7255ac6216e09dce1ad4d7c669ec546a2cb4673..a31a8e2fa6b3f7d13319a967ab5107dd7f5cdf70 100644 >--- a/Source/JavaScriptCore/bytecompiler/BytecodeGenerator.h >+++ b/Source/JavaScriptCore/bytecompiler/BytecodeGenerator.h >@@ -54,6 +54,7 @@ > > namespace JSC { > >+ class JSImmutableButterfly; > class Identifier; > > enum ExpectedFunction { >@@ -666,10 +667,11 @@ namespace JSC { > void emitTDZCheckIfNecessary(const Variable&, RegisterID* target, RegisterID* scope); > void liftTDZCheckIfPossible(const Variable&); > RegisterID* emitNewObject(RegisterID* dst); >- RegisterID* emitNewArray(RegisterID* dst, ElementNode*, unsigned length); // stops at first elision >+ RegisterID* emitNewArray(RegisterID* dst, ElementNode*, unsigned length, IndexingType recommendedIndexingType); // stops at first elision >+ RegisterID* emitNewArrayBuffer(RegisterID* dst, JSImmutableButterfly*, IndexingType recommendedIndexingType); >+ // FIXME: new_array_with_spread should use an array allocation profile and take a recommendedIndexingType > RegisterID* emitNewArrayWithSpread(RegisterID* dst, ElementNode*); > RegisterID* emitNewArrayWithSize(RegisterID* dst, RegisterID* length); >- RegisterID* emitNewArrayBuffer(RegisterID* dst, JSFixedArray*); > > RegisterID* emitNewFunction(RegisterID* dst, FunctionMetadataNode*); > RegisterID* emitNewFunctionExpression(RegisterID* dst, FuncExprNode*); >@@ -1005,7 +1007,7 @@ namespace JSC { > Variable variableForLocalEntry(const Identifier&, const SymbolTableEntry&, int symbolTableConstantIndex, bool isLexicallyScoped); > > void emitOpcode(OpcodeID); >- UnlinkedArrayAllocationProfile newArrayAllocationProfile(); >+ UnlinkedArrayAllocationProfile newArrayAllocationProfile(IndexingType); > UnlinkedObjectAllocationProfile newObjectAllocationProfile(); > UnlinkedValueProfile emitProfiledOpcode(OpcodeID); > int kill(RegisterID* dst) >diff --git a/Source/JavaScriptCore/bytecompiler/NodesCodegen.cpp b/Source/JavaScriptCore/bytecompiler/NodesCodegen.cpp >index 07a9c907a7e2130a4244dfa0011f7ca52b06e8a6..3f6150063da7d1461dfb3335df50004d427b1287 100644 >--- a/Source/JavaScriptCore/bytecompiler/NodesCodegen.cpp >+++ b/Source/JavaScriptCore/bytecompiler/NodesCodegen.cpp >@@ -36,6 +36,7 @@ > #include "JSFunction.h" > #include "JSGeneratorFunction.h" > #include "JSGlobalObject.h" >+#include "JSImmutableButterfly.h" > #include "LabelScope.h" > #include "Lexer.h" > #include "Parser.h" >@@ -388,26 +389,32 @@ RegisterID* ArrayNode::emitBytecode(BytecodeGenerator& generator, RegisterID* ds > { > bool hadVariableExpression = false; > unsigned length = 0; >+ >+ IndexingType recommendedIndexingType = ArrayWithUndecided; > ElementNode* firstPutElement; > for (firstPutElement = m_element; firstPutElement; firstPutElement = firstPutElement->next()) { > if (firstPutElement->elision() || firstPutElement->value()->isSpreadExpression()) > break; > if (!firstPutElement->value()->isConstant()) > hadVariableExpression = true; >+ else >+ recommendedIndexingType = leastUpperBoundOfIndexingTypeAndValue(recommendedIndexingType, static_cast<ConstantNode*>(firstPutElement->value())->jsValue(generator)); >+ > ++length; > } > >- auto newArray = [&generator] (RegisterID* dst, ElementNode* elements, unsigned length, bool hadVariableExpression) { >+ auto newArray = [&] (RegisterID* dst, ElementNode* elements, unsigned length, bool hadVariableExpression) { > if (length && !hadVariableExpression) { >- auto* array = JSFixedArray::create(*generator.vm(), length); >+ recommendedIndexingType |= CopyOnWrite; >+ auto* array = JSImmutableButterfly::create(*generator.vm(), recommendedIndexingType, length); > unsigned index = 0; > for (ElementNode* element = elements; index < length; element = element->next()) { > ASSERT(element->value()->isConstant()); >- array->set(*generator.vm(), index++, static_cast<ConstantNode*>(element->value())->jsValue(generator)); >+ array->setIndex(*generator.vm(), index++, static_cast<ConstantNode*>(element->value())->jsValue(generator)); > } >- return generator.emitNewArrayBuffer(dst, array); >+ return generator.emitNewArrayBuffer(dst, array, recommendedIndexingType); > } >- return generator.emitNewArray(dst, elements, length); >+ return generator.emitNewArray(dst, elements, length, recommendedIndexingType); > }; > > if (!firstPutElement && !m_elision) >@@ -4151,7 +4158,7 @@ void ArrayPatternNode::bindValue(BytecodeGenerator& generator, RegisterID* rhs) > } > > case BindingType::RestElement: { >- RefPtr<RegisterID> array = generator.emitNewArray(generator.newTemporary(), nullptr, 0); >+ RefPtr<RegisterID> array = generator.emitNewArray(generator.newTemporary(), nullptr, 0, ArrayWithUndecided); > > Ref<Label> iterationDone = generator.newLabel(); > if (!done) >@@ -4203,7 +4210,7 @@ RegisterID* ArrayPatternNode::emitDirectBinding(BytecodeGenerator& generator, Re > > RefPtr<RegisterID> resultRegister; > if (dst && dst != generator.ignoredResult()) >- resultRegister = generator.emitNewArray(generator.newTemporary(), nullptr, 0); >+ resultRegister = generator.emitNewArray(generator.newTemporary(), nullptr, 0, ArrayWithUndecided); > if (m_targetPatterns.size() != elements.size()) > return nullptr; > Vector<RefPtr<RegisterID>> registers; >diff --git a/Source/JavaScriptCore/dfg/DFGAbstractInterpreterInlines.h b/Source/JavaScriptCore/dfg/DFGAbstractInterpreterInlines.h >index c3afd0c2947fe0528ae64043530da0d38e458dfb..bd8ad9816ddad8a6a9485880a40f2f0ab9152c3d 100644 >--- a/Source/JavaScriptCore/dfg/DFGAbstractInterpreterInlines.h >+++ b/Source/JavaScriptCore/dfg/DFGAbstractInterpreterInlines.h >@@ -2206,6 +2206,7 @@ bool AbstractInterpreter<AbstractStateType>::executeEffects(unsigned clobberLimi > } > > case NewArray: >+ ASSERT(node->indexingMode() == node->indexingType()); // Copy on write arrays should only be created by NewArrayBuffer. > forNode(node).set( > m_graph, > m_graph.globalObjectFor(node->origin.semantic)->arrayStructureForIndexingTypeDuringAllocation(node->indexingType())); >@@ -2247,7 +2248,7 @@ bool AbstractInterpreter<AbstractStateType>::executeEffects(unsigned clobberLimi > case NewArrayBuffer: > forNode(node).set( > m_graph, >- m_graph.globalObjectFor(node->origin.semantic)->arrayStructureForIndexingTypeDuringAllocation(node->indexingType())); >+ m_graph.globalObjectFor(node->origin.semantic)->arrayStructureForIndexingTypeDuringAllocation(node->indexingMode())); > break; > > case NewArrayWithSize: >diff --git a/Source/JavaScriptCore/dfg/DFGAbstractValue.h b/Source/JavaScriptCore/dfg/DFGAbstractValue.h >index f45c13f9397af0413d93d97fbc1b2a91c24c97dc..1814d8b27868e73f118dda503510df66f79d34dd 100644 >--- a/Source/JavaScriptCore/dfg/DFGAbstractValue.h >+++ b/Source/JavaScriptCore/dfg/DFGAbstractValue.h >@@ -395,6 +395,7 @@ struct AbstractValue { > // that the value may have right now, since a structure has an immutable > // indexing type. This is subject to change upon reassignment, or any side > // effect that makes non-obvious changes to the heap. >+ // TODO: Does this need to handle CoW arrays or can we skip this... > ArrayModes m_arrayModes; > > // This is a proven constraint on the possible values that this value can >diff --git a/Source/JavaScriptCore/dfg/DFGArgumentsEliminationPhase.cpp b/Source/JavaScriptCore/dfg/DFGArgumentsEliminationPhase.cpp >index d1ccfec6c52799024bab375191e9be11985efae8..1aac90cdb0f6141b12021768d693035ab8e4a6a5 100644 >--- a/Source/JavaScriptCore/dfg/DFGArgumentsEliminationPhase.cpp >+++ b/Source/JavaScriptCore/dfg/DFGArgumentsEliminationPhase.cpp >@@ -148,7 +148,7 @@ private: > } > > case NewArrayBuffer: { >- if (m_graph.isWatchingHavingABadTimeWatchpoint(node) && !hasAnyArrayStorage(node->indexingType())) >+ if (m_graph.isWatchingHavingABadTimeWatchpoint(node) && !hasAnyArrayStorage(node->indexingMode())) > m_candidates.add(node); > break; > } >@@ -426,9 +426,9 @@ private: > break; > case NewArrayBuffer: { > ASSERT(m_graph.isWatchingHavingABadTimeWatchpoint(target)); >- IndexingType indexingType = target->indexingType(); >- ASSERT(!hasAnyArrayStorage(indexingType)); >- structure = globalObject->originalArrayStructureForIndexingType(indexingType); >+ IndexingType indexingMode = target->indexingMode(); >+ ASSERT(!hasAnyArrayStorage(indexingMode)); >+ structure = globalObject->originalArrayStructureForIndexingType(indexingMode); > break; > } > default: >@@ -864,7 +864,7 @@ private: > } > > if (candidate->op() == PhantomNewArrayBuffer) >- return candidate->castOperand<JSFixedArray*>()->length(); >+ return candidate->castOperand<JSImmutableButterfly*>()->length(); > > ASSERT(candidate->op() == PhantomCreateRest); > unsigned numberOfArgumentsToSkip = candidate->numberOfArgumentsToSkip(); >diff --git a/Source/JavaScriptCore/dfg/DFGArgumentsUtilities.cpp b/Source/JavaScriptCore/dfg/DFGArgumentsUtilities.cpp >index f4333e424d89f66b926f273928f202293dd1c87a..a06d6748d17851bbb2619fca10d3d50277a76c31 100644 >--- a/Source/JavaScriptCore/dfg/DFGArgumentsUtilities.cpp >+++ b/Source/JavaScriptCore/dfg/DFGArgumentsUtilities.cpp >@@ -72,7 +72,7 @@ Node* emitCodeToGetArgumentsArrayLength( > > if (arguments->op() == NewArrayBuffer || arguments->op() == PhantomNewArrayBuffer) { > return insertionSet.insertConstant( >- nodeIndex, origin, jsNumber(arguments->castOperand<JSFixedArray*>()->length())); >+ nodeIndex, origin, jsNumber(arguments->castOperand<JSImmutableButterfly*>()->length())); > } > > InlineCallFrame* inlineCallFrame = arguments->origin.semantic.inlineCallFrame; >diff --git a/Source/JavaScriptCore/dfg/DFGArrayMode.cpp b/Source/JavaScriptCore/dfg/DFGArrayMode.cpp >index 216bbeb6b37c6e5aa5d1792cc87bfad09ec3fad1..523b92b52d13fdaf0cc2793c0cf1caa37b25bca2 100644 >--- a/Source/JavaScriptCore/dfg/DFGArrayMode.cpp >+++ b/Source/JavaScriptCore/dfg/DFGArrayMode.cpp >@@ -42,85 +42,110 @@ ArrayMode ArrayMode::fromObserved(const ConcurrentJSLocker& locker, ArrayProfile > nonArray = Array::OriginalNonArray; > else > nonArray = Array::NonArray; >- >+ >+ auto handleContiguousModes = [&] (Array::Type type, ArrayModes observed) { >+ Array::Class isArray; >+ Array::Conversion converts; >+ >+ RELEASE_ASSERT((observed & (asArrayModes(toIndexingShape(type)) | asArrayModes(toIndexingShape(type) | ArrayClass) | asArrayModes(toIndexingShape(type) | ArrayClass | CopyOnWrite))) == observed); >+ >+ if (observed & asArrayModes(toIndexingShape(type))) { >+ if ((observed & asArrayModes(toIndexingShape(type))) == observed) >+ isArray = nonArray; >+ else >+ isArray = Array::PossiblyArray; >+ } else >+ isArray = Array::Array; >+ >+ if (action == Array::Write && observed & asArrayModes(toIndexingShape(type) | ArrayClass | CopyOnWrite)) >+ converts = Array::Convert; >+ else >+ converts = Array::AsIs; >+ >+ return ArrayMode(type, isArray, converts, action).withProfile(locker, profile, makeSafe); >+ }; >+ > ArrayModes observed = profile->observedArrayModes(locker); > switch (observed) { > case 0: > return ArrayMode(Array::Unprofiled); > case asArrayModes(NonArray): > if (action == Array::Write && !profile->mayInterceptIndexedAccesses(locker)) >- return ArrayMode(Array::SelectUsingArguments, nonArray, Array::OutOfBounds, Array::Convert); >- return ArrayMode(Array::SelectUsingPredictions, nonArray).withSpeculationFromProfile(locker, profile, makeSafe); >+ return ArrayMode(Array::SelectUsingArguments, nonArray, Array::OutOfBounds, Array::Convert, action); >+ return ArrayMode(Array::SelectUsingPredictions, nonArray, action).withSpeculationFromProfile(locker, profile, makeSafe); > > case asArrayModes(ArrayWithUndecided): > if (action == Array::Write) >- return ArrayMode(Array::SelectUsingArguments, Array::Array, Array::OutOfBounds, Array::Convert); >- return ArrayMode(Array::Undecided, Array::Array, Array::OutOfBounds, Array::AsIs).withProfile(locker, profile, makeSafe); >+ return ArrayMode(Array::SelectUsingArguments, Array::Array, Array::OutOfBounds, Array::Convert, action); >+ return ArrayMode(Array::Undecided, Array::Array, Array::OutOfBounds, Array::AsIs, action).withProfile(locker, profile, makeSafe); > > case asArrayModes(NonArray) | asArrayModes(ArrayWithUndecided): > if (action == Array::Write && !profile->mayInterceptIndexedAccesses(locker)) >- return ArrayMode(Array::SelectUsingArguments, Array::PossiblyArray, Array::OutOfBounds, Array::Convert); >- return ArrayMode(Array::SelectUsingPredictions).withSpeculationFromProfile(locker, profile, makeSafe); >+ return ArrayMode(Array::SelectUsingArguments, Array::PossiblyArray, Array::OutOfBounds, Array::Convert, action); >+ return ArrayMode(Array::SelectUsingPredictions, action).withSpeculationFromProfile(locker, profile, makeSafe); > > case asArrayModes(NonArrayWithInt32): >- return ArrayMode(Array::Int32, nonArray, Array::AsIs).withProfile(locker, profile, makeSafe); > case asArrayModes(ArrayWithInt32): >- return ArrayMode(Array::Int32, Array::Array, Array::AsIs).withProfile(locker, profile, makeSafe); > case asArrayModes(NonArrayWithInt32) | asArrayModes(ArrayWithInt32): >- return ArrayMode(Array::Int32, Array::PossiblyArray, Array::AsIs).withProfile(locker, profile, makeSafe); >+ case asArrayModes(NonArrayWithInt32) | asArrayModes(CopyOnWriteArrayWithInt32): >+ case asArrayModes(ArrayWithInt32) | asArrayModes(CopyOnWriteArrayWithInt32): >+ case asArrayModes(NonArrayWithInt32) | asArrayModes(ArrayWithInt32) | asArrayModes(CopyOnWriteArrayWithInt32): >+ return handleContiguousModes(Array::Int32, observed); > > case asArrayModes(NonArrayWithDouble): >- return ArrayMode(Array::Double, nonArray, Array::AsIs).withProfile(locker, profile, makeSafe); > case asArrayModes(ArrayWithDouble): >- return ArrayMode(Array::Double, Array::Array, Array::AsIs).withProfile(locker, profile, makeSafe); > case asArrayModes(NonArrayWithDouble) | asArrayModes(ArrayWithDouble): >- return ArrayMode(Array::Double, Array::PossiblyArray, Array::AsIs).withProfile(locker, profile, makeSafe); >+ case asArrayModes(NonArrayWithDouble) | asArrayModes(CopyOnWriteArrayWithDouble): >+ case asArrayModes(ArrayWithDouble) | asArrayModes(CopyOnWriteArrayWithDouble): >+ case asArrayModes(NonArrayWithDouble) | asArrayModes(ArrayWithDouble) | asArrayModes(CopyOnWriteArrayWithDouble): >+ return handleContiguousModes(Array::Double, observed); > > case asArrayModes(NonArrayWithContiguous): >- return ArrayMode(Array::Contiguous, nonArray, Array::AsIs).withProfile(locker, profile, makeSafe); > case asArrayModes(ArrayWithContiguous): >- return ArrayMode(Array::Contiguous, Array::Array, Array::AsIs).withProfile(locker, profile, makeSafe); > case asArrayModes(NonArrayWithContiguous) | asArrayModes(ArrayWithContiguous): >- return ArrayMode(Array::Contiguous, Array::PossiblyArray, Array::AsIs).withProfile(locker, profile, makeSafe); >+ case asArrayModes(NonArrayWithContiguous) | asArrayModes(CopyOnWriteArrayWithContiguous): >+ case asArrayModes(ArrayWithContiguous) | asArrayModes(CopyOnWriteArrayWithContiguous): >+ case asArrayModes(NonArrayWithContiguous) | asArrayModes(ArrayWithContiguous) | asArrayModes(CopyOnWriteArrayWithContiguous): >+ return handleContiguousModes(Array::Contiguous, observed); > > case asArrayModes(NonArrayWithArrayStorage): >- return ArrayMode(Array::ArrayStorage, nonArray, Array::AsIs).withProfile(locker, profile, makeSafe); >+ return ArrayMode(Array::ArrayStorage, nonArray, Array::AsIs, action).withProfile(locker, profile, makeSafe); > case asArrayModes(NonArrayWithSlowPutArrayStorage): > case asArrayModes(NonArrayWithArrayStorage) | asArrayModes(NonArrayWithSlowPutArrayStorage): >- return ArrayMode(Array::SlowPutArrayStorage, nonArray, Array::AsIs).withProfile(locker, profile, makeSafe); >+ return ArrayMode(Array::SlowPutArrayStorage, nonArray, Array::AsIs, action).withProfile(locker, profile, makeSafe); > case asArrayModes(ArrayWithArrayStorage): >- return ArrayMode(Array::ArrayStorage, Array::Array, Array::AsIs).withProfile(locker, profile, makeSafe); >+ return ArrayMode(Array::ArrayStorage, Array::Array, Array::AsIs, action).withProfile(locker, profile, makeSafe); > case asArrayModes(ArrayWithSlowPutArrayStorage): > case asArrayModes(ArrayWithArrayStorage) | asArrayModes(ArrayWithSlowPutArrayStorage): >- return ArrayMode(Array::SlowPutArrayStorage, Array::Array, Array::AsIs).withProfile(locker, profile, makeSafe); >+ return ArrayMode(Array::SlowPutArrayStorage, Array::Array, Array::AsIs, action).withProfile(locker, profile, makeSafe); > case asArrayModes(NonArrayWithArrayStorage) | asArrayModes(ArrayWithArrayStorage): >- return ArrayMode(Array::ArrayStorage, Array::PossiblyArray, Array::AsIs).withProfile(locker, profile, makeSafe); >+ return ArrayMode(Array::ArrayStorage, Array::PossiblyArray, Array::AsIs, action).withProfile(locker, profile, makeSafe); > case asArrayModes(NonArrayWithSlowPutArrayStorage) | asArrayModes(ArrayWithSlowPutArrayStorage): > case asArrayModes(NonArrayWithArrayStorage) | asArrayModes(ArrayWithArrayStorage) | asArrayModes(NonArrayWithSlowPutArrayStorage) | asArrayModes(ArrayWithSlowPutArrayStorage): >- return ArrayMode(Array::SlowPutArrayStorage, Array::PossiblyArray, Array::AsIs).withProfile(locker, profile, makeSafe); >+ return ArrayMode(Array::SlowPutArrayStorage, Array::PossiblyArray, Array::AsIs, action).withProfile(locker, profile, makeSafe); > case Int8ArrayMode: >- return ArrayMode(Array::Int8Array, nonArray, Array::AsIs).withProfile(locker, profile, makeSafe); >+ return ArrayMode(Array::Int8Array, nonArray, Array::AsIs, action).withProfile(locker, profile, makeSafe); > case Int16ArrayMode: >- return ArrayMode(Array::Int16Array, nonArray, Array::AsIs).withProfile(locker, profile, makeSafe); >+ return ArrayMode(Array::Int16Array, nonArray, Array::AsIs, action).withProfile(locker, profile, makeSafe); > case Int32ArrayMode: >- return ArrayMode(Array::Int32Array, nonArray, Array::AsIs).withProfile(locker, profile, makeSafe); >+ return ArrayMode(Array::Int32Array, nonArray, Array::AsIs, action).withProfile(locker, profile, makeSafe); > case Uint8ArrayMode: >- return ArrayMode(Array::Uint8Array, nonArray, Array::AsIs).withProfile(locker, profile, makeSafe); >+ return ArrayMode(Array::Uint8Array, nonArray, Array::AsIs, action).withProfile(locker, profile, makeSafe); > case Uint8ClampedArrayMode: >- return ArrayMode(Array::Uint8ClampedArray, nonArray, Array::AsIs).withProfile(locker, profile, makeSafe); >+ return ArrayMode(Array::Uint8ClampedArray, nonArray, Array::AsIs, action).withProfile(locker, profile, makeSafe); > case Uint16ArrayMode: >- return ArrayMode(Array::Uint16Array, nonArray, Array::AsIs).withProfile(locker, profile, makeSafe); >+ return ArrayMode(Array::Uint16Array, nonArray, Array::AsIs, action).withProfile(locker, profile, makeSafe); > case Uint32ArrayMode: >- return ArrayMode(Array::Uint32Array, nonArray, Array::AsIs).withProfile(locker, profile, makeSafe); >+ return ArrayMode(Array::Uint32Array, nonArray, Array::AsIs, action).withProfile(locker, profile, makeSafe); > case Float32ArrayMode: >- return ArrayMode(Array::Float32Array, nonArray, Array::AsIs).withProfile(locker, profile, makeSafe); >+ return ArrayMode(Array::Float32Array, nonArray, Array::AsIs, action).withProfile(locker, profile, makeSafe); > case Float64ArrayMode: >- return ArrayMode(Array::Float64Array, nonArray, Array::AsIs).withProfile(locker, profile, makeSafe); >+ return ArrayMode(Array::Float64Array, nonArray, Array::AsIs, action).withProfile(locker, profile, makeSafe); > > default: > // If we have seen multiple TypedArray types, or a TypedArray and non-typed array, it doesn't make sense to try to convert the object since you can't convert typed arrays. > if (observed & ALL_TYPED_ARRAY_MODES) >- return ArrayMode(Array::Generic, nonArray, Array::AsIs).withProfile(locker, profile, makeSafe); >+ return ArrayMode(Array::Generic, nonArray, Array::AsIs, action).withProfile(locker, profile, makeSafe); > > if ((observed & asArrayModes(NonArray)) && profile->mayInterceptIndexedAccesses(locker)) > return ArrayMode(Array::SelectUsingPredictions).withSpeculationFromProfile(locker, profile, makeSafe); >@@ -150,7 +175,7 @@ ArrayMode ArrayMode::fromObserved(const ConcurrentJSLocker& locker, ArrayProfile > else > arrayClass = Array::PossiblyArray; > >- return ArrayMode(type, arrayClass, Array::Convert).withProfile(locker, profile, makeSafe); >+ return ArrayMode(type, arrayClass, Array::Convert, action).withProfile(locker, profile, makeSafe); > } > } > >@@ -272,7 +297,7 @@ ArrayMode ArrayMode::refine( > // FIXME: Support OOB access for ScopedArguments. > // https://bugs.webkit.org/show_bug.cgi?id=179596 > if (type == Array::DirectArguments) >- return ArrayMode(type, Array::NonArray, Array::OutOfBounds, Array::AsIs); >+ return ArrayMode(type, Array::NonArray, Array::OutOfBounds, Array::AsIs, action()); > return ArrayMode(Array::Generic); > } > if (isX86() && is32Bit() && isScopedArgumentsSpeculation(base)) >@@ -382,6 +407,8 @@ bool ArrayMode::alreadyChecked(Graph& graph, Node* node, const AbstractValue& va > RegisteredStructure structure = value.m_structure[i]; > if ((structure->indexingType() & IndexingShapeMask) != shape) > return false; >+ if (isCopyOnWrite(structure->indexingMode()) && action() == Array::Write) >+ return false; > if (!(structure->indexingType() & IsArray)) > return false; > if (!graph.globalObjectFor(node->origin.semantic)->isOriginalArrayStructure(structure.get())) >@@ -397,7 +424,9 @@ bool ArrayMode::alreadyChecked(Graph& graph, Node* node, const AbstractValue& va > return false; > for (unsigned i = value.m_structure.size(); i--;) { > RegisteredStructure structure = value.m_structure[i]; >- if ((structure->indexingType() & IndexingShapeMask) != shape) >+ if ((structure->indexingMode() & IndexingShapeMask) != shape) >+ return false; >+ if (isCopyOnWrite(structure->indexingMode()) && action() == Array::Write) > return false; > if (!(structure->indexingType() & IsArray)) > return false; >@@ -412,7 +441,9 @@ bool ArrayMode::alreadyChecked(Graph& graph, Node* node, const AbstractValue& va > return false; > for (unsigned i = value.m_structure.size(); i--;) { > RegisteredStructure structure = value.m_structure[i]; >- if ((structure->indexingType() & IndexingShapeMask) != shape) >+ if ((structure->indexingMode() & IndexingShapeMask) != shape) >+ return false; >+ if (isCopyOnWrite(structure->indexingMode()) && action() == Array::Write) > return false; > } > return true; >@@ -633,26 +664,6 @@ const char* arrayConversionToString(Array::Conversion conversion) > } > } > >-IndexingType toIndexingShape(Array::Type type) >-{ >- switch (type) { >- case Array::Int32: >- return Int32Shape; >- case Array::Double: >- return DoubleShape; >- case Array::Contiguous: >- return ContiguousShape; >- case Array::Undecided: >- return UndecidedShape; >- case Array::ArrayStorage: >- return ArrayStorageShape; >- case Array::SlowPutArrayStorage: >- return SlowPutArrayStorageShape; >- default: >- return NoIndexingShape; >- } >-} >- > TypedArrayType toTypedArrayType(Array::Type type) > { > switch (type) { >@@ -708,6 +719,26 @@ Array::Type toArrayType(TypedArrayType type) > } > } > >+IndexingType toIndexingShape(Array::Type type) >+{ >+ switch (type) { >+ case Array::Int32: >+ return Int32Shape; >+ case Array::Double: >+ return DoubleShape; >+ case Array::Contiguous: >+ return ContiguousShape; >+ case Array::Undecided: >+ return UndecidedShape; >+ case Array::ArrayStorage: >+ return ArrayStorageShape; >+ case Array::SlowPutArrayStorage: >+ return SlowPutArrayStorageShape; >+ default: >+ return NoIndexingShape; >+ } >+} >+ > Array::Type refineTypedArrayType(Array::Type oldType, TypedArrayType newType) > { > if (oldType == Array::Generic) >diff --git a/Source/JavaScriptCore/dfg/DFGArrayMode.h b/Source/JavaScriptCore/dfg/DFGArrayMode.h >index 81bcf82716b75d6d5c70e70d7d170a7706074faf..99a8481aba3e0824715947a5e162852df3743ba2 100644 >--- a/Source/JavaScriptCore/dfg/DFGArrayMode.h >+++ b/Source/JavaScriptCore/dfg/DFGArrayMode.h >@@ -82,7 +82,7 @@ enum Type { > enum Class { > NonArray, // Definitely some object that is not a JSArray. > OriginalNonArray, // Definitely some object that is not a JSArray, but that object has the original structure. >- Array, // Definitely a JSArray, and may or may not have custom properties or have undergone some other bizarre transitions. >+ Array, // Definitely a JSArray, and may or may not have custom properties or have undergone some other bizarre transitions or be copy on write. > OriginalArray, // Definitely a JSArray, and still has one of the primordial JSArray structures for the global object that this code block (possibly inlined code block) belongs to. > PossiblyArray // Some object that may or may not be a JSArray. > }; >@@ -100,6 +100,7 @@ enum Conversion { > }; > } // namespace Array > >+const char* arrayActionToString(Array::Action); > const char* arrayTypeToString(Array::Type); > const char* arrayClassToString(Array::Class); > const char* arraySpeculationToString(Array::Speculation); >@@ -121,44 +122,50 @@ public: > u.asBytes.arrayClass = Array::NonArray; > u.asBytes.speculation = Array::InBounds; > u.asBytes.conversion = Array::AsIs; >+ u.asBytes.action = Array::Write; > } > >- explicit ArrayMode(Array::Type type) >+ explicit ArrayMode(Array::Type type, Array::Action action) > { > u.asBytes.type = type; > u.asBytes.arrayClass = Array::NonArray; > u.asBytes.speculation = Array::InBounds; > u.asBytes.conversion = Array::AsIs; >+ u.asBytes.action = action; > } > >- ArrayMode(Array::Type type, Array::Class arrayClass) >+ ArrayMode(Array::Type type, Array::Class arrayClass, Array::Action action) > { > u.asBytes.type = type; > u.asBytes.arrayClass = arrayClass; > u.asBytes.speculation = Array::InBounds; > u.asBytes.conversion = Array::AsIs; >+ u.asBytes.action = action; > } > >- ArrayMode(Array::Type type, Array::Class arrayClass, Array::Speculation speculation, Array::Conversion conversion) >+ ArrayMode(Array::Type type, Array::Class arrayClass, Array::Speculation speculation, Array::Conversion conversion, Array::Action action) > { > u.asBytes.type = type; > u.asBytes.arrayClass = arrayClass; > u.asBytes.speculation = speculation; > u.asBytes.conversion = conversion; >+ u.asBytes.action = action; > } > >- ArrayMode(Array::Type type, Array::Class arrayClass, Array::Conversion conversion) >+ ArrayMode(Array::Type type, Array::Class arrayClass, Array::Conversion conversion, Array::Action action) > { > u.asBytes.type = type; > u.asBytes.arrayClass = arrayClass; > u.asBytes.speculation = Array::InBounds; > u.asBytes.conversion = conversion; >+ u.asBytes.action = action; > } > > Array::Type type() const { return static_cast<Array::Type>(u.asBytes.type); } > Array::Class arrayClass() const { return static_cast<Array::Class>(u.asBytes.arrayClass); } > Array::Speculation speculation() const { return static_cast<Array::Speculation>(u.asBytes.speculation); } > Array::Conversion conversion() const { return static_cast<Array::Conversion>(u.asBytes.conversion); } >+ Array::Action action() const { return static_cast<Array::Action>(u.asBytes.action); } > > unsigned asWord() const { return u.asWord; } > >@@ -171,12 +178,12 @@ public: > > ArrayMode withSpeculation(Array::Speculation speculation) const > { >- return ArrayMode(type(), arrayClass(), speculation, conversion()); >+ return ArrayMode(type(), arrayClass(), speculation, conversion(), action()); > } > > ArrayMode withArrayClass(Array::Class arrayClass) const > { >- return ArrayMode(type(), arrayClass, speculation(), conversion()); >+ return ArrayMode(type(), arrayClass, speculation(), conversion(), action()); > } > > ArrayMode withSpeculationFromProfile(const ConcurrentJSLocker& locker, ArrayProfile* profile, bool makeSafe) const >@@ -210,17 +217,17 @@ public: > > ArrayMode withType(Array::Type type) const > { >- return ArrayMode(type, arrayClass(), speculation(), conversion()); >+ return ArrayMode(type, arrayClass(), speculation(), conversion(), action()); > } > > ArrayMode withConversion(Array::Conversion conversion) const > { >- return ArrayMode(type(), arrayClass(), speculation(), conversion); >+ return ArrayMode(type(), arrayClass(), speculation(), conversion, action()); > } > > ArrayMode withTypeAndConversion(Array::Type type, Array::Conversion conversion) const > { >- return ArrayMode(type, arrayClass(), speculation(), conversion); >+ return ArrayMode(type, arrayClass(), speculation(), conversion, action()); > } > > ArrayMode refine(Graph&, Node*, SpeculatedType base, SpeculatedType index, SpeculatedType value = SpecNone) const; >@@ -290,7 +297,7 @@ public: > { > return type() == Array::SlowPutArrayStorage; > } >- >+ > bool canCSEStorage() const > { > switch (type()) { >@@ -410,15 +417,19 @@ public: > > ArrayModes arrayModesThatPassFiltering() const > { >+ ArrayModes result; > switch (type()) { > case Array::Generic: > return ALL_ARRAY_MODES; > case Array::Int32: >- return arrayModesWithIndexingShape(Int32Shape); >+ result = arrayModesWithIndexingShape(Int32Shape); >+ break; > case Array::Double: >- return arrayModesWithIndexingShape(DoubleShape); >+ result = arrayModesWithIndexingShape(DoubleShape); >+ break; > case Array::Contiguous: >- return arrayModesWithIndexingShape(ContiguousShape); >+ result = arrayModesWithIndexingShape(ContiguousShape); >+ break; > case Array::ArrayStorage: > return arrayModesWithIndexingShape(ArrayStorageShape); > case Array::SlowPutArrayStorage: >@@ -426,6 +437,10 @@ public: > default: > return asArrayModes(NonArray); > } >+ >+ if (action() == Array::Write) >+ result &= ~ALL_COPY_ON_WRITE_ARRAY_MODES; >+ return result; > } > > bool getIndexedPropertyStorageMayTriggerGC() const >@@ -474,8 +489,12 @@ private: > return asArrayModes(shape); > case Array::Array: > case Array::OriginalArray: >+ if (hasInt32(shape) || hasDouble(shape) || hasContiguous(shape)) >+ return asArrayModes(shape | IsArray) | asArrayModes(shape | IsArray | CopyOnWrite); > return asArrayModes(shape | IsArray); > case Array::PossiblyArray: >+ if (hasInt32(shape) || hasDouble(shape) || hasContiguous(shape)) >+ return asArrayModes(shape) | asArrayModes(shape | IsArray) | asArrayModes(shape | IsArray | CopyOnWrite); > return asArrayModes(shape) | asArrayModes(shape | IsArray); > default: > // This is only necessary for C++ compilers that don't understand enums. >@@ -497,10 +516,12 @@ private: > uint8_t type; > uint8_t arrayClass; > uint8_t speculation; >- uint8_t conversion; >+ uint8_t conversion : 4; >+ uint8_t action : 4; > } asBytes; > unsigned asWord; > } u; >+ static_assert(sizeof(decltype(u.asBytes)) == sizeof(decltype(u.asWord)), "the word form of ArrayMode should have the same size as the individual slices"); > }; > > static inline bool canCSEStorage(const ArrayMode& arrayMode) >diff --git a/Source/JavaScriptCore/dfg/DFGByteCodeParser.cpp b/Source/JavaScriptCore/dfg/DFGByteCodeParser.cpp >index 66132faa0d0c9a1ba5490eed06cd6e653e2bfc15..aac8f70d2dc527fe0dced7771171e59b4dfb3d6f 100644 >--- a/Source/JavaScriptCore/dfg/DFGByteCodeParser.cpp >+++ b/Source/JavaScriptCore/dfg/DFGByteCodeParser.cpp >@@ -49,6 +49,7 @@ > #include "Heap.h" > #include "JSCInlines.h" > #include "JSFixedArray.h" >+#include "JSImmutableButterfly.h" > #include "JSModuleEnvironment.h" > #include "JSModuleNamespaceObject.h" > #include "NumberConstructor.h" >@@ -2416,6 +2417,7 @@ bool ByteCodeParser::handleIntrinsicCall(Node* callee, int resultOperand, Intrin > return false; > > NodeType op = LastNodeType; >+ Array::Action action = Array::Write; > unsigned numArgs = 0; // Number of actual args; we add one for the backing store pointer. > switch (intrinsic) { > case AtomicsAddIntrinsic: >@@ -2443,6 +2445,7 @@ bool ByteCodeParser::handleIntrinsicCall(Node* callee, int resultOperand, Intrin > case AtomicsLoadIntrinsic: > op = AtomicsLoad; > numArgs = 2; >+ action = Array::Read; > break; > case AtomicsOrIntrinsic: > op = AtomicsOr; >@@ -2478,12 +2481,12 @@ bool ByteCodeParser::handleIntrinsicCall(Node* callee, int resultOperand, Intrin > if (numArgs + 1 <= 3) { > while (args.size() < 3) > args.append(nullptr); >- result = addToGraph(op, OpInfo(ArrayMode(Array::SelectUsingPredictions).asWord()), OpInfo(prediction), args[0], args[1], args[2]); >+ result = addToGraph(op, OpInfo(ArrayMode(Array::SelectUsingPredictions, action).asWord()), OpInfo(prediction), args[0], args[1], args[2]); > } else { > for (Node* node : args) > addVarArgChild(node); > addVarArgChild(nullptr); >- result = addToGraph(Node::VarArg, op, OpInfo(ArrayMode(Array::SelectUsingPredictions).asWord()), OpInfo(prediction)); >+ result = addToGraph(Node::VarArg, op, OpInfo(ArrayMode(Array::SelectUsingPredictions, action).asWord()), OpInfo(prediction)); > } > > set(VirtualRegister(resultOperand), result); >@@ -2518,7 +2521,7 @@ bool ByteCodeParser::handleIntrinsicCall(Node* callee, int resultOperand, Intrin > insertChecks(); > VirtualRegister thisOperand = virtualRegisterForArgument(0, registerOffset); > VirtualRegister indexOperand = virtualRegisterForArgument(1, registerOffset); >- Node* charCode = addToGraph(StringCharCodeAt, OpInfo(ArrayMode(Array::String).asWord()), get(thisOperand), get(indexOperand)); >+ Node* charCode = addToGraph(StringCharCodeAt, OpInfo(ArrayMode(Array::String, Array::Read).asWord()), get(thisOperand), get(indexOperand)); > > set(VirtualRegister(resultOperand), charCode); > return true; >@@ -2531,7 +2534,7 @@ bool ByteCodeParser::handleIntrinsicCall(Node* callee, int resultOperand, Intrin > insertChecks(); > VirtualRegister thisOperand = virtualRegisterForArgument(0, registerOffset); > VirtualRegister indexOperand = virtualRegisterForArgument(1, registerOffset); >- Node* charCode = addToGraph(StringCharAt, OpInfo(ArrayMode(Array::String).asWord()), get(thisOperand), get(indexOperand)); >+ Node* charCode = addToGraph(StringCharAt, OpInfo(ArrayMode(Array::String, Array::Read).asWord()), get(thisOperand), get(indexOperand)); > > set(VirtualRegister(resultOperand), charCode); > return true; >@@ -3186,7 +3189,7 @@ bool ByteCodeParser::handleIntrinsicGetter(int resultOperand, SpeculatedType pre > ASSERT(arrayType != Array::Generic); > }); > >- Node* lengthNode = addToGraph(GetArrayLength, OpInfo(ArrayMode(arrayType).asWord()), thisNode); >+ Node* lengthNode = addToGraph(GetArrayLength, OpInfo(ArrayMode(arrayType, Array::Read).asWord()), thisNode); > > if (!logSize) { > set(VirtualRegister(resultOperand), lengthNode); >@@ -3213,7 +3216,7 @@ bool ByteCodeParser::handleIntrinsicGetter(int resultOperand, SpeculatedType pre > ASSERT(arrayType != Array::Generic); > }); > >- set(VirtualRegister(resultOperand), addToGraph(GetArrayLength, OpInfo(ArrayMode(arrayType).asWord()), thisNode)); >+ set(VirtualRegister(resultOperand), addToGraph(GetArrayLength, OpInfo(ArrayMode(arrayType, Array::Read).asWord()), thisNode)); > > return true; > >@@ -3231,7 +3234,7 @@ bool ByteCodeParser::handleIntrinsicGetter(int resultOperand, SpeculatedType pre > ASSERT(arrayType != Array::Generic); > }); > >- set(VirtualRegister(resultOperand), addToGraph(GetTypedArrayByteOffset, OpInfo(ArrayMode(arrayType).asWord()), thisNode)); >+ set(VirtualRegister(resultOperand), addToGraph(GetTypedArrayByteOffset, OpInfo(ArrayMode(arrayType, Array::Read).asWord()), thisNode)); > > return true; > } >@@ -4535,18 +4538,19 @@ void ByteCodeParser::parseBlock(unsigned limit) > } > > case op_new_array_buffer: { >- FrozenValue* frozen = get(VirtualRegister(currentInstruction[2].u.operand))->constant(); >- JSFixedArray* fixedArray = frozen->cast<JSFixedArray*>(); >- ArrayAllocationProfile* profile = currentInstruction[3].u.arrayAllocationProfile; >+ auto& bytecode = *reinterpret_cast<OpNewArrayBuffer*>(currentInstruction); >+ // Unfortunately, we can't allocate a new JSImmutableButterfly if the profile tells us new information because we >+ // cannot allocate from compilation threads. >+ WTF::loadLoadFence(); >+ FrozenValue* frozen = get(VirtualRegister(bytecode.immutableButterfly()))->constant(); >+ WTF::loadLoadFence(); >+ JSImmutableButterfly* immutableButterfly = frozen->cast<JSImmutableButterfly*>(); > NewArrayBufferData data { }; >- data.indexingType = profile->selectIndexingType(); >- data.vectorLengthHint = std::max<unsigned>(profile->vectorLengthHint(), fixedArray->length()); >+ data.indexingMode = immutableButterfly->indexingMode(); >+ // TODO: Do I need this? >+ data.vectorLengthHint = immutableButterfly->toButterfly()->vectorLength(); > >- // If this statement has never executed, we'll have the wrong indexing type in the profile. >- for (unsigned index = 0; index < fixedArray->length(); ++index) >- data.indexingType = leastUpperBoundOfIndexingTypeAndValue(data.indexingType, fixedArray->get(index)); >- >- set(VirtualRegister(currentInstruction[1].u.operand), addToGraph(NewArrayBuffer, OpInfo(frozen), OpInfo(data.asQuadWord))); >+ set(VirtualRegister(bytecode.dst()), addToGraph(NewArrayBuffer, OpInfo(frozen), OpInfo(data.asQuadWord))); > NEXT_OPCODE(op_new_array_buffer); > } > >diff --git a/Source/JavaScriptCore/dfg/DFGClobberize.h b/Source/JavaScriptCore/dfg/DFGClobberize.h >index dd68a592a83a3f88cd769c01332fc4c87031570a..96fb87ff7761fe24ffb7c3579cd156b8f1014393 100644 >--- a/Source/JavaScriptCore/dfg/DFGClobberize.h >+++ b/Source/JavaScriptCore/dfg/DFGClobberize.h >@@ -37,6 +37,7 @@ > #include "DOMJITSignature.h" > #include "InlineCallFrame.h" > #include "JSFixedArray.h" >+#include "JSImmutableButterfly.h" > > namespace JSC { namespace DFG { > >@@ -1423,7 +1424,7 @@ void clobberize(Graph& graph, Node* node, const ReadFunctor& read, const WriteFu > read(HeapObjectCount); > write(HeapObjectCount); > >- JSFixedArray* array = node->castOperand<JSFixedArray*>(); >+ auto* array = node->castOperand<JSImmutableButterfly*>(); > unsigned numElements = array->length(); > def(HeapLocation(ArrayLengthLoc, Butterfly_publicLength, node), > LazyNode(graph.freeze(jsNumber(numElements)))); >diff --git a/Source/JavaScriptCore/dfg/DFGConstantFoldingPhase.cpp b/Source/JavaScriptCore/dfg/DFGConstantFoldingPhase.cpp >index cee65623431770f4bf402ada0c877358f800b67d..5e52f6040ef690b740a69e279e00a58295134b5f 100644 >--- a/Source/JavaScriptCore/dfg/DFGConstantFoldingPhase.cpp >+++ b/Source/JavaScriptCore/dfg/DFGConstantFoldingPhase.cpp >@@ -173,8 +173,10 @@ private: > case ArrayifyToStructure: { > AbstractValue& value = m_state.forNode(node->child1()); > RegisteredStructureSet set; >- if (node->op() == ArrayifyToStructure) >+ if (node->op() == ArrayifyToStructure) { > set = node->structure(); >+ ASSERT(!isCopyOnWrite(node->structure()->indexingMode())); >+ } > else { > set = node->structureSet(); > if ((SpecCellCheck & SpecEmpty) && node->child1().useKind() == CellUse && m_state.forNode(node->child1()).m_type & SpecEmpty) { >diff --git a/Source/JavaScriptCore/dfg/DFGFixupPhase.cpp b/Source/JavaScriptCore/dfg/DFGFixupPhase.cpp >index 47d0e66b38602191edc7054c619d1b6f61313ac6..89352bf325c68e6015fd79f661439af7ebfdcc75 100644 >--- a/Source/JavaScriptCore/dfg/DFGFixupPhase.cpp >+++ b/Source/JavaScriptCore/dfg/DFGFixupPhase.cpp >@@ -700,7 +700,7 @@ private: > case StringCharAt: > case StringCharCodeAt: { > // Currently we have no good way of refining these. >- ASSERT(node->arrayMode() == ArrayMode(Array::String)); >+ ASSERT(node->arrayMode() == ArrayMode(Array::String, Array::Read)); > blessArrayOperation(node->child1(), node->child2(), node->child3()); > fixEdge<KnownCellUse>(node->child1()); > fixEdge<Int32Use>(node->child2()); >@@ -971,7 +971,7 @@ private: > } > > if (badNews) { >- node->setArrayMode(ArrayMode(Array::Generic)); >+ node->setArrayMode(ArrayMode(Array::Generic, node->arrayMode().action())); > break; > } > >@@ -1267,6 +1267,7 @@ private: > node->indexingType(), m_graph.varArgChild(node, i)->prediction())); > } > switch (node->indexingType()) { >+ // TODO: Make these and other indexing type switches either the writable ones or not. > case ALL_BLANK_INDEXING_TYPES: > CRASH(); > break; >@@ -2258,13 +2259,13 @@ private: > template<UseKind useKind> > void attemptToForceStringArrayModeByToStringConversion(ArrayMode& arrayMode, Node* node) > { >- ASSERT(arrayMode == ArrayMode(Array::Generic)); >+ ASSERT(arrayMode == ArrayMode(Array::Generic, Array::Read)); > > if (!m_graph.canOptimizeStringObjectAccess(node->origin.semantic)) > return; > > createToString<useKind>(node, node->child1()); >- arrayMode = ArrayMode(Array::String); >+ arrayMode = ArrayMode(Array::String, Array::Read); > } > > template<UseKind useKind> >@@ -3200,7 +3201,7 @@ private: > CodeBlock* profiledBlock = m_graph.baselineCodeBlockFor(node->origin.semantic); > ArrayProfile* arrayProfile = > profiledBlock->getArrayProfile(node->origin.semantic.bytecodeIndex); >- ArrayMode arrayMode = ArrayMode(Array::SelectUsingPredictions); >+ ArrayMode arrayMode = ArrayMode(Array::SelectUsingPredictions, Array::Read); > if (arrayProfile) { > ConcurrentJSLocker locker(profiledBlock->m_lock); > arrayProfile->computeUpdatedPrediction(locker, profiledBlock); >@@ -3213,7 +3214,7 @@ private: > // GetById. I.e. ForceExit = Generic. So, there is no harm - and only > // profit - from treating the Unprofiled case as > // SelectUsingPredictions. >- arrayMode = ArrayMode(Array::SelectUsingPredictions); >+ arrayMode = ArrayMode(Array::SelectUsingPredictions, Array::Read); > } > } > >diff --git a/Source/JavaScriptCore/dfg/DFGGraph.cpp b/Source/JavaScriptCore/dfg/DFGGraph.cpp >index bb5433c0d3d32e5a02b04e9a5b83ee5310a009ff..d88eae65a29f5d81b414c6e418bf5fa3228da3cf 100644 >--- a/Source/JavaScriptCore/dfg/DFGGraph.cpp >+++ b/Source/JavaScriptCore/dfg/DFGGraph.cpp >@@ -318,7 +318,7 @@ void Graph::dump(PrintStream& out, const char* prefix, Node* node, DumpContext* > if (node->hasLazyJSValue()) > out.print(comma, node->lazyJSValue()); > if (node->hasIndexingType()) >- out.print(comma, IndexingTypeDump(node->indexingType())); >+ out.print(comma, IndexingTypeDump(node->indexingMode())); > if (node->hasTypedArrayType()) > out.print(comma, node->typedArrayType()); > if (node->hasPhi()) >diff --git a/Source/JavaScriptCore/dfg/DFGNode.h b/Source/JavaScriptCore/dfg/DFGNode.h >index 4d97cd3ab127d30bbf46ac739edbf1bea85c130d..53b1ab021ec34f40dd0d71f89ba620d0497bb5e5 100644 >--- a/Source/JavaScriptCore/dfg/DFGNode.h >+++ b/Source/JavaScriptCore/dfg/DFGNode.h >@@ -100,7 +100,7 @@ struct NewArrayBufferData { > union { > struct { > unsigned vectorLengthHint; >- unsigned indexingType; >+ unsigned indexingMode; > }; > uint64_t asQuadWord; > }; >@@ -1170,7 +1170,15 @@ public: > { > ASSERT(hasIndexingType()); > if (op() == NewArrayBuffer || op() == PhantomNewArrayBuffer) >- return static_cast<IndexingType>(newArrayBufferData().indexingType); >+ return static_cast<IndexingType>(newArrayBufferData().indexingMode) & IndexingTypeMask; >+ return static_cast<IndexingType>(m_opInfo.as<uint32_t>()); >+ } >+ >+ IndexingType indexingMode() >+ { >+ ASSERT(hasIndexingType()); >+ if (op() == NewArrayBuffer || op() == PhantomNewArrayBuffer) >+ return static_cast<IndexingType>(newArrayBufferData().indexingMode); > return static_cast<IndexingType>(m_opInfo.as<uint32_t>()); > } > >diff --git a/Source/JavaScriptCore/dfg/DFGOSRExit.cpp b/Source/JavaScriptCore/dfg/DFGOSRExit.cpp >index 92ca22aca6eb579a9eb496c8365e3e7bca7910ae..da3d67612caf609f3594848ae614ba74c07f720b 100644 >--- a/Source/JavaScriptCore/dfg/DFGOSRExit.cpp >+++ b/Source/JavaScriptCore/dfg/DFGOSRExit.cpp >@@ -1197,7 +1197,7 @@ void OSRExit::compileExit(CCallHelpers& jit, VM& vm, const OSRExit& exit, const > #if USE(JSVALUE64) > jit.load8(AssemblyHelpers::Address(value, JSCell::indexingTypeAndMiscOffset()), scratch1); > #else >- jit.load8(AssemblyHelpers::Address(scratch1, Structure::indexingTypeIncludingHistoryOffset()), scratch1); >+ jit.load8(AssemblyHelpers::Address(scratch1, Structure::indexingModeIncludingHistoryOffset()), scratch1); > #endif > jit.move(AssemblyHelpers::TrustedImm32(1), scratch2); > jit.lshift32(scratch1, scratch2); >diff --git a/Source/JavaScriptCore/dfg/DFGOperations.cpp b/Source/JavaScriptCore/dfg/DFGOperations.cpp >index f8fa9295ffdb7e93986949e5e3f07126f9c53407..1a6fe8ae6a6480b9be0a9ec85174f3aefe6900fb 100644 >--- a/Source/JavaScriptCore/dfg/DFGOperations.cpp >+++ b/Source/JavaScriptCore/dfg/DFGOperations.cpp >@@ -53,6 +53,7 @@ > #include "JSFixedArray.h" > #include "JSGenericTypedArrayViewConstructorInlines.h" > #include "JSGlobalObjectFunctions.h" >+#include "JSImmutableButterfly.h" > #include "JSLexicalEnvironment.h" > #include "JSMap.h" > #include "JSPropertyNameEnumerator.h" >@@ -920,7 +921,7 @@ void JIT_OPERATION operationPutByValDirectBeyondArrayBoundsNonStrict(ExecState* > { > VM& vm = exec->vm(); > NativeCallFrameTracer tracer(&vm, exec); >- >+ > if (index >= 0) { > object->putDirectIndex(exec, index, JSValue::decode(encodedValue)); > return; >@@ -982,7 +983,7 @@ EncodedJSValue JIT_OPERATION operationArrayPushDoubleMultiple(ExecState* exec, J > // If it can cause any JS interactions, we can call the caller JS function of this function and overwrite the > // content of ScratchBuffer. If the IndexingType is now ArrayWithDouble, we can ensure > // that there is no indexed accessors in this object and its prototype chain. >- ASSERT(array->indexingType() == ArrayWithDouble); >+ ASSERT(array->indexingMode() == ArrayWithDouble); > > double* values = static_cast<double*>(buffer); > for (int32_t i = 0; i < elementCount; ++i) { >@@ -1478,11 +1479,12 @@ char* JIT_OPERATION operationNewArrayWithSizeAndHint(ExecState* exec, Structure* > return bitwise_cast<char*>(result); > } > >-JSCell* JIT_OPERATION operationNewArrayBuffer(ExecState* exec, Structure* arrayStructure, JSCell* fixedArray, size_t size) >+JSCell* JIT_OPERATION operationNewArrayBuffer(ExecState* exec, Structure* arrayStructure, JSCell* fixedArray) > { > VM& vm = exec->vm(); > NativeCallFrameTracer tracer(&vm, exec); >- return constructArray(exec, arrayStructure, jsCast<JSFixedArray*>(fixedArray)->values(), size); >+ ASSERT(!arrayStructure->outOfLineCapacity()); >+ return JSArray::createWithButterfly(vm, nullptr, arrayStructure, jsCast<JSImmutableButterfly*>(fixedArray)->toButterfly()); > } > > char* JIT_OPERATION operationNewInt8ArrayWithSize( >@@ -1846,8 +1848,10 @@ char* JIT_OPERATION operationEnsureInt32(ExecState* exec, JSCell* cell) > > if (!cell->isObject()) > return 0; >- >- return reinterpret_cast<char*>(asObject(cell)->ensureInt32(vm).data()); >+ >+ auto* result = reinterpret_cast<char*>(asObject(cell)->ensureWritableInt32(vm).data()); >+ ASSERT(!isCopyOnWrite(asObject(cell)->indexingMode()) && hasInt32(cell->indexingMode())); >+ return result; > } > > char* JIT_OPERATION operationEnsureDouble(ExecState* exec, JSCell* cell) >@@ -1857,8 +1861,41 @@ char* JIT_OPERATION operationEnsureDouble(ExecState* exec, JSCell* cell) > > if (!cell->isObject()) > return 0; >- >- return reinterpret_cast<char*>(asObject(cell)->ensureDouble(vm).data()); >+ >+// JSObject* object = asObject(cell); >+// if (!isCopyOnWrite(object->indexingMode())) { >+// Structure* structure = object->structure(vm); >+// Butterfly* butterfly = object->butterfly(); >+// bool hasIndexingHeader = structure->hasIndexingHeader(object); >+// size_t preCapacity; >+// if (hasIndexingHeader) >+// preCapacity = butterfly->indexingHeader()->preCapacity(structure); >+// else >+// preCapacity = 0; >+// >+// HeapCell* base = bitwise_cast<HeapCell*>(butterfly->base(preCapacity, structure->outOfLineCapacity())); >+// >+// RELEASE_ASSERT(&vm.heap == Heap::heap(base)); >+// } >+ >+ auto* result = reinterpret_cast<char*>(asObject(cell)->ensureWritableDouble(vm).data()); >+ >+// if (!isCopyOnWrite(object->indexingMode())) { >+// Structure* structure = object->structure(vm); >+// Butterfly* butterfly = object->butterfly(); >+// bool hasIndexingHeader = structure->hasIndexingHeader(object); >+// size_t preCapacity; >+// if (hasIndexingHeader) >+// preCapacity = butterfly->indexingHeader()->preCapacity(structure); >+// else >+// preCapacity = 0; >+// >+// HeapCell* base = bitwise_cast<HeapCell*>(butterfly->base(preCapacity, structure->outOfLineCapacity())); >+// >+// RELEASE_ASSERT(&vm.heap == Heap::heap(base)); >+// } >+ ASSERT(!isCopyOnWrite(asObject(cell)->indexingMode()) && hasDouble(cell->indexingMode())); >+ return result; > } > > char* JIT_OPERATION operationEnsureContiguous(ExecState* exec, JSCell* cell) >@@ -1869,7 +1906,9 @@ char* JIT_OPERATION operationEnsureContiguous(ExecState* exec, JSCell* cell) > if (!cell->isObject()) > return 0; > >- return reinterpret_cast<char*>(asObject(cell)->ensureContiguous(vm).data()); >+ auto* result = reinterpret_cast<char*>(asObject(cell)->ensureWritableContiguous(vm).data()); >+ ASSERT(!isCopyOnWrite(asObject(cell)->indexingMode()) && hasContiguous(cell->indexingMode())); >+ return result; > } > > char* JIT_OPERATION operationEnsureArrayStorage(ExecState* exec, JSCell* cell) >@@ -1880,7 +1919,9 @@ char* JIT_OPERATION operationEnsureArrayStorage(ExecState* exec, JSCell* cell) > if (!cell->isObject()) > return 0; > >- return reinterpret_cast<char*>(asObject(cell)->ensureArrayStorage(vm)); >+ auto* result = reinterpret_cast<char*>(asObject(cell)->ensureArrayStorage(vm)); >+ ASSERT(!isCopyOnWrite(asObject(cell)->indexingMode()) && hasAnyArrayStorage(cell->indexingMode())); >+ return result; > } > > EncodedJSValue JIT_OPERATION operationHasGenericProperty(ExecState* exec, EncodedJSValue encodedBaseValue, JSCell* propertyName) >diff --git a/Source/JavaScriptCore/dfg/DFGOperations.h b/Source/JavaScriptCore/dfg/DFGOperations.h >index f48f9ab89f18f9e2219987bea6cc31ff1391b0d1..a79fce6732bea006291ce49b434d8b60e1593933 100644 >--- a/Source/JavaScriptCore/dfg/DFGOperations.h >+++ b/Source/JavaScriptCore/dfg/DFGOperations.h >@@ -168,7 +168,7 @@ JSCell* JIT_OPERATION operationCreateScopedArguments(ExecState*, Structure*, Reg > JSCell* JIT_OPERATION operationCreateClonedArgumentsDuringExit(ExecState*, InlineCallFrame*, JSFunction*, uint32_t argumentCount); > JSCell* JIT_OPERATION operationCreateClonedArguments(ExecState*, Structure*, Register* argumentStart, uint32_t length, JSFunction* callee); > JSCell* JIT_OPERATION operationCreateRest(ExecState*, Register* argumentStart, unsigned numberOfArgumentsToSkip, unsigned arraySize); >-JSCell* JIT_OPERATION operationNewArrayBuffer(ExecState*, Structure*, JSCell*, size_t) WTF_INTERNAL; >+JSCell* JIT_OPERATION operationNewArrayBuffer(ExecState*, Structure*, JSCell*) WTF_INTERNAL; > JSCell* JIT_OPERATION operationSetAdd(ExecState*, JSCell*, EncodedJSValue, int32_t) WTF_INTERNAL; > JSCell* JIT_OPERATION operationMapSet(ExecState*, JSCell*, EncodedJSValue, EncodedJSValue, int32_t) WTF_INTERNAL; > void JIT_OPERATION operationWeakSetAdd(ExecState*, JSCell*, JSCell*, int32_t) WTF_INTERNAL; >diff --git a/Source/JavaScriptCore/dfg/DFGSpeculativeJIT.cpp b/Source/JavaScriptCore/dfg/DFGSpeculativeJIT.cpp >index b0952689fcab8923609838116e672687cf2e5500..c59536c6b3bf0d7464c1cd7f9c3e88873b5cd7b3 100644 >--- a/Source/JavaScriptCore/dfg/DFGSpeculativeJIT.cpp >+++ b/Source/JavaScriptCore/dfg/DFGSpeculativeJIT.cpp >@@ -54,6 +54,7 @@ > #include "JSCInlines.h" > #include "JSFixedArray.h" > #include "JSGeneratorFunction.h" >+#include "JSImmutableButterfly.h" > #include "JSLexicalEnvironment.h" > #include "JSPropertyNameEnumerator.h" > #include "LinkBuffer.h" >@@ -67,6 +68,8 @@ > #include <wtf/Box.h> > #include <wtf/MathExtras.h> > >+#include "ProbeContext.h" >+ > namespace JSC { namespace DFG { > > SpeculativeJIT::SpeculativeJIT(JITCompiler& jit) >@@ -90,6 +93,7 @@ SpeculativeJIT::~SpeculativeJIT() > > void SpeculativeJIT::emitAllocateRawObject(GPRReg resultGPR, RegisteredStructure structure, GPRReg storageGPR, unsigned numElements, unsigned vectorLength) > { >+ ASSERT(!isCopyOnWrite(structure->indexingMode())); > IndexingType indexingType = structure->indexingType(); > bool hasIndexingHeader = hasIndexedProperties(indexingType); > >@@ -726,7 +730,11 @@ void SpeculativeJIT::silentFill(const SilentRegisterSavePlan& plan) > JITCompiler::JumpList SpeculativeJIT::jumpSlowForUnwantedArrayMode(GPRReg tempGPR, ArrayMode arrayMode) > { > JITCompiler::JumpList result; >- >+ >+ IndexingType indexingModeMask = IsArray | IndexingShapeMask; >+ if (arrayMode.action() == Array::Write) >+ indexingModeMask |= CopyOnWrite; >+ > switch (arrayMode.type()) { > case Array::Int32: > case Array::Double: >@@ -740,20 +748,20 @@ JITCompiler::JumpList SpeculativeJIT::jumpSlowForUnwantedArrayMode(GPRReg tempGP > return result; > > case Array::Array: >- m_jit.and32(TrustedImm32(IsArray | IndexingShapeMask), tempGPR); >+ m_jit.and32(TrustedImm32(indexingModeMask), tempGPR); > result.append(m_jit.branch32( > MacroAssembler::NotEqual, tempGPR, TrustedImm32(IsArray | shape))); > return result; > > case Array::NonArray: > case Array::OriginalNonArray: >- m_jit.and32(TrustedImm32(IsArray | IndexingShapeMask), tempGPR); >+ m_jit.and32(TrustedImm32(indexingModeMask), tempGPR); > result.append(m_jit.branch32( > MacroAssembler::NotEqual, tempGPR, TrustedImm32(shape))); > return result; > > case Array::PossiblyArray: >- m_jit.and32(TrustedImm32(IndexingShapeMask), tempGPR); >+ m_jit.and32(TrustedImm32(indexingModeMask & ~IsArray), tempGPR); > result.append(m_jit.branch32(MacroAssembler::NotEqual, tempGPR, TrustedImm32(shape))); > return result; > } >@@ -862,7 +870,30 @@ void SpeculativeJIT::arrayify(Node* node, GPRReg baseReg, GPRReg propertyReg) > GPRTemporary structure; > GPRReg tempGPR = temp.gpr(); > GPRReg structureGPR = InvalidGPRReg; >- >+ >+// unsigned bytecodeIndex = node->origin.semantic.bytecodeIndex; >+// bool isWrite = node->arrayMode().action() == Array::Write; >+// VM* vm = m_jit.vm(); >+// m_jit.probe([=] (Probe::Context& context) { >+// UNUSED_PARAM(bytecodeIndex); >+// auto* object = context.gpr<JSObject*>(baseReg); >+// >+// if (!isCopyOnWrite(object->indexingMode())) { >+// Structure* structure = object->structure(*vm); >+// Butterfly* butterfly = object->butterfly(); >+// bool hasIndexingHeader = structure->hasIndexingHeader(object); >+// size_t preCapacity; >+// if (hasIndexingHeader) >+// preCapacity = butterfly->indexingHeader()->preCapacity(structure); >+// else >+// preCapacity = 0; >+// >+// HeapCell* base = bitwise_cast<HeapCell*>(butterfly->base(preCapacity, structure->outOfLineCapacity())); >+// >+// RELEASE_ASSERT(&vm->heap == Heap::heap(base)); >+// } >+// }); >+ > if (node->op() != ArrayifyToStructure) { > GPRTemporary realStructure(this); > structure.adopt(realStructure); >@@ -873,6 +904,8 @@ void SpeculativeJIT::arrayify(Node* node, GPRReg baseReg, GPRReg propertyReg) > MacroAssembler::JumpList slowPath; > > if (node->op() == ArrayifyToStructure) { >+ ASSERT(!isCopyOnWrite(node->structure()->indexingMode())); >+ ASSERT((node->structure()->indexingType() & IndexingShapeMask) == node->arrayMode().shapeMask()); > slowPath.append(m_jit.branchWeakStructure( > JITCompiler::NotEqual, > JITCompiler::Address(baseReg, JSCell::structureIDOffset()), >@@ -886,7 +919,28 @@ void SpeculativeJIT::arrayify(Node* node, GPRReg baseReg, GPRReg propertyReg) > > addSlowPathGenerator(std::make_unique<ArrayifySlowPathGenerator>( > slowPath, this, node, baseReg, propertyReg, tempGPR, structureGPR)); >- >+ >+// m_jit.probe([=] (Probe::Context& context) { >+// UNUSED_PARAM(bytecodeIndex); >+// auto* object = context.gpr<JSObject*>(baseReg); >+// RELEASE_ASSERT(!isCopyOnWrite(object->indexingMode()) || !isWrite); >+// >+// if (!isCopyOnWrite(object->indexingMode())) { >+// Structure* structure = object->structure(*vm); >+// Butterfly* butterfly = object->butterfly(); >+// bool hasIndexingHeader = structure->hasIndexingHeader(object); >+// size_t preCapacity; >+// if (hasIndexingHeader) >+// preCapacity = butterfly->indexingHeader()->preCapacity(structure); >+// else >+// preCapacity = 0; >+// >+// HeapCell* base = bitwise_cast<HeapCell*>(butterfly->base(preCapacity, structure->outOfLineCapacity())); >+// >+// RELEASE_ASSERT(&vm->heap == Heap::heap(base)); >+// } >+// }); >+ > noResult(m_currentNode); > } > >@@ -2099,7 +2153,12 @@ void SpeculativeJIT::compileDoublePutByVal(Node* node, SpeculateCellOperand& bas > > inBounds.link(&m_jit); > } >- >+ >+ m_jit.probe([=] (Probe::Context& context) { >+ auto* object = context.gpr<JSObject*>(baseReg); >+ RELEASE_ASSERT(!isCopyOnWrite(object->indexingMode())); >+ }); >+ > m_jit.storeDouble(valueReg, MacroAssembler::BaseIndex(storageReg, propertyReg, MacroAssembler::TimesEight)); > > base.use(); >@@ -2176,7 +2235,7 @@ void SpeculativeJIT::compileGetByValOnString(Node* node) > } > #endif > >- ASSERT(ArrayMode(Array::String).alreadyChecked(m_jit.graph(), node, m_state.forNode(m_graph.child(node, 0)))); >+ ASSERT(ArrayMode(Array::String, Array::Read).alreadyChecked(m_jit.graph(), node, m_state.forNode(m_graph.child(node, 0)))); > > // unsigned comparison so we can filter out negative indices and indices that are too large > JITCompiler::Jump outOfBounds = m_jit.branch32( >@@ -6556,7 +6615,7 @@ void SpeculativeJIT::compileGetByValOnDirectArguments(Node* node) > if (!m_compileOkay) > return; > >- ASSERT(ArrayMode(Array::DirectArguments).alreadyChecked(m_jit.graph(), node, m_state.forNode(m_graph.varArgChild(node, 0)))); >+ ASSERT(ArrayMode(Array::DirectArguments, Array::Read).alreadyChecked(m_jit.graph(), node, m_state.forNode(m_graph.varArgChild(node, 0)))); > > speculationCheck( > ExoticObjectMode, JSValueSource(), 0, >@@ -6603,7 +6662,7 @@ void SpeculativeJIT::compileGetByValOnScopedArguments(Node* node) > if (!m_compileOkay) > return; > >- ASSERT(ArrayMode(Array::ScopedArguments).alreadyChecked(m_jit.graph(), node, m_state.forNode(m_graph.varArgChild(node, 0)))); >+ ASSERT(ArrayMode(Array::ScopedArguments, Array::Read).alreadyChecked(m_jit.graph(), node, m_state.forNode(m_graph.varArgChild(node, 0)))); > > m_jit.loadPtr( > MacroAssembler::Address(baseReg, ScopedArguments::offsetOfStorage()), resultRegs.payloadGPR()); >@@ -6750,7 +6809,7 @@ void SpeculativeJIT::compileGetArrayLength(Node* node) > if (!m_compileOkay) > return; > >- ASSERT(ArrayMode(Array::DirectArguments).alreadyChecked(m_jit.graph(), node, m_state.forNode(node->child1()))); >+ ASSERT(ArrayMode(Array::DirectArguments, Array::Read).alreadyChecked(m_jit.graph(), node, m_state.forNode(node->child1()))); > > speculationCheck( > ExoticObjectMode, JSValueSource(), 0, >@@ -6774,7 +6833,7 @@ void SpeculativeJIT::compileGetArrayLength(Node* node) > if (!m_compileOkay) > return; > >- ASSERT(ArrayMode(Array::ScopedArguments).alreadyChecked(m_jit.graph(), node, m_state.forNode(node->child1()))); >+ ASSERT(ArrayMode(Array::ScopedArguments, Array::Read).alreadyChecked(m_jit.graph(), node, m_state.forNode(node->child1()))); > > m_jit.loadPtr( > MacroAssembler::Address(baseReg, ScopedArguments::offsetOfStorage()), resultReg); >@@ -7408,7 +7467,7 @@ void SpeculativeJIT::compileCreateRest(Node* node) > GPRReg arrayResultGPR = arrayResult.gpr(); > > bool shouldAllowForArrayStorageStructureForLargeArrays = false; >- ASSERT(m_jit.graph().globalObjectFor(node->origin.semantic)->restParameterStructure()->indexingType() == ArrayWithContiguous || m_jit.graph().globalObjectFor(node->origin.semantic)->isHavingABadTime()); >+ ASSERT(m_jit.graph().globalObjectFor(node->origin.semantic)->restParameterStructure()->indexingMode() == ArrayWithContiguous || m_jit.graph().globalObjectFor(node->origin.semantic)->isHavingABadTime()); > compileAllocateNewArrayWithSize(m_jit.graph().globalObjectFor(node->origin.semantic), arrayResultGPR, arrayLengthGPR, ArrayWithContiguous, shouldAllowForArrayStorageStructureForLargeArrays); > > GPRTemporary argumentsStart(this); >@@ -7977,7 +8036,8 @@ void SpeculativeJIT::compileArraySlice(Node* node) > { > SpeculateCellOperand cell(this, m_jit.graph().varArgChild(node, 0)); > m_jit.load8(MacroAssembler::Address(cell.gpr(), JSCell::indexingTypeAndMiscOffset()), tempValue); >- m_jit.and32(TrustedImm32(AllArrayTypesAndHistory), tempValue); >+ // We can ignore the writability of the cell since we won't write to the source. >+ m_jit.and32(TrustedImm32(AllWritableArrayTypesAndHistory), tempValue); > } > > { >@@ -8322,6 +8382,11 @@ void SpeculativeJIT::compileArrayPush(Node* node) > m_jit.getEffectiveAddress(MacroAssembler::BaseIndex(storageGPR, indexGPR, MacroAssembler::TimesEight, offset), bufferGPR); > }; > >+ m_jit.probe([=] (Probe::Context& context) { >+ auto* object = context.gpr<JSObject*>(baseGPR); >+ RELEASE_ASSERT(!isCopyOnWrite(object->indexingMode())); >+ }); >+ > switch (node->arrayMode().type()) { > case Array::Int32: > case Array::Contiguous: { >@@ -11912,47 +11977,27 @@ void SpeculativeJIT::compileStrCat(Node* node) > void SpeculativeJIT::compileNewArrayBuffer(Node* node) > { > JSGlobalObject* globalObject = m_jit.graph().globalObjectFor(node->origin.semantic); >- JSFixedArray* array = node->castOperand<JSFixedArray*>(); >- unsigned numElements = array->length(); >- IndexingType indexingType = node->indexingType(); >- if (!globalObject->isHavingABadTime() && !hasAnyArrayStorage(indexingType)) { >- unsigned vectorLengthHint = node->vectorLengthHint(); >- ASSERT(vectorLengthHint >= numElements); >+ auto* array = node->castOperand<JSImmutableButterfly*>(); >+ >+ IndexingType indexingMode = node->indexingMode(); >+ RegisteredStructure structure = m_jit.graph().registerStructure(globalObject->arrayStructureForIndexingTypeDuringAllocation(indexingMode)); > >+ if (!globalObject->isHavingABadTime() && !hasAnyArrayStorage(indexingMode)) { > GPRTemporary result(this); >- GPRTemporary storage(this); >+ GPRTemporary scratch1(this); >+ GPRTemporary scratch2(this); > > GPRReg resultGPR = result.gpr(); >- GPRReg storageGPR = storage.gpr(); >+ GPRReg scratch1GPR = scratch1.gpr(); >+ GPRReg scratch2GPR = scratch2.gpr(); > >- emitAllocateRawObject(resultGPR, m_jit.graph().registerStructure(globalObject->arrayStructureForIndexingTypeDuringAllocation(indexingType)), storageGPR, numElements, vectorLengthHint); >+ MacroAssembler::JumpList slowCases; > >- DFG_ASSERT(m_jit.graph(), node, indexingType & IsArray, indexingType); >+ emitAllocateJSObject<JSArray>(resultGPR, TrustedImmPtr(structure), TrustedImmPtr(array->toButterfly()), scratch1GPR, scratch2GPR, slowCases); > >- for (unsigned index = 0; index < numElements; ++index) { >-#if USE(JSVALUE64) >- int64_t value; >- if (indexingType == ArrayWithDouble) >- value = bitwise_cast<int64_t>(array->get(index).asNumber()); >- else >- value = JSValue::encode(array->get(index)); >- static_assert(sizeof(double) == sizeof(JSValue), ""); >- m_jit.store64(Imm64(value), MacroAssembler::Address(storageGPR, sizeof(JSValue) * index)); >-#else >- union { >- int32_t halves[2]; >- double doubleValue; >- int64_t encodedValue; >- } u; >- if (node->indexingType() == ArrayWithDouble) >- u.doubleValue = array->get(index).asNumber(); >- else >- u.encodedValue = JSValue::encode(array->get(index)); >- static_assert(sizeof(double) == sizeof(JSValue), ""); >- m_jit.store32(Imm32(u.halves[0]), MacroAssembler::Address(storageGPR, sizeof(JSValue) * index)); >- m_jit.store32(Imm32(u.halves[1]), MacroAssembler::Address(storageGPR, sizeof(JSValue) * index + sizeof(int32_t))); >-#endif >- } >+ addSlowPathGenerator(slowPathCall(slowCases, this, operationNewArrayBuffer, result.gpr(), structure, array)); >+ >+ DFG_ASSERT(m_jit.graph(), node, indexingMode & IsArray, indexingMode); > cellResult(resultGPR, node); > return; > } >@@ -11960,7 +12005,7 @@ void SpeculativeJIT::compileNewArrayBuffer(Node* node) > flushRegisters(); > GPRFlushedCallResult result(this); > >- callOperation(operationNewArrayBuffer, result.gpr(), m_jit.graph().registerStructure(globalObject->arrayStructureForIndexingTypeDuringAllocation(node->indexingType())), TrustedImmPtr(node->cellOperand()), size_t(numElements)); >+ callOperation(operationNewArrayBuffer, result.gpr(), m_jit.graph().registerStructure(globalObject->arrayStructureForIndexingTypeDuringAllocation(node->indexingType())), TrustedImmPtr(node->cellOperand())); > m_jit.exceptionCheck(); > > cellResult(result.gpr(), node); >diff --git a/Source/JavaScriptCore/dfg/DFGSpeculativeJIT32_64.cpp b/Source/JavaScriptCore/dfg/DFGSpeculativeJIT32_64.cpp >index 99bfa09880d49879637bf8a0732690a8e615ad4b..4282a42d74de99651e949709ddb57d687bb3b699 100644 >--- a/Source/JavaScriptCore/dfg/DFGSpeculativeJIT32_64.cpp >+++ b/Source/JavaScriptCore/dfg/DFGSpeculativeJIT32_64.cpp >@@ -3403,7 +3403,7 @@ void SpeculativeJIT::compile(Node* node) > SpeculateCellOperand base(this, node->child1()); > GPRReg baseGPR = base.gpr(); > >- ASSERT_UNUSED(oldStructure, oldStructure->indexingType() == newStructure->indexingType()); >+ ASSERT_UNUSED(oldStructure, oldStructure->indexingMode() == newStructure->indexingMode()); > ASSERT(oldStructure->typeInfo().type() == newStructure->typeInfo().type()); > ASSERT(oldStructure->typeInfo().inlineTypeFlags() == newStructure->typeInfo().inlineTypeFlags()); > m_jit.storePtr(TrustedImmPtr(newStructure), MacroAssembler::Address(baseGPR, JSCell::structureIDOffset())); >diff --git a/Source/JavaScriptCore/dfg/DFGSpeculativeJIT64.cpp b/Source/JavaScriptCore/dfg/DFGSpeculativeJIT64.cpp >index 5c980e4a1f4549dcd7119d69e2f4bcf23c93664b..55aa25be419e537adcf7bbe493afea7944fcef30 100644 >--- a/Source/JavaScriptCore/dfg/DFGSpeculativeJIT64.cpp >+++ b/Source/JavaScriptCore/dfg/DFGSpeculativeJIT64.cpp >@@ -2760,6 +2760,13 @@ void SpeculativeJIT::compile(Node* node) > inBounds.link(&m_jit); > } > >+ unsigned bytecodeIndex = node->origin.semantic.bytecodeIndex; >+ m_jit.probe([=] (Probe::Context& context) { >+ UNUSED_PARAM(bytecodeIndex); >+ auto* object = context.gpr<JSObject*>(baseReg); >+ RELEASE_ASSERT(!isCopyOnWrite(object->indexingMode())); >+ }); >+ > m_jit.store64(valueReg, MacroAssembler::BaseIndex(storageReg, propertyReg, MacroAssembler::TimesEight)); > > base.use(); >@@ -3655,7 +3662,7 @@ void SpeculativeJIT::compile(Node* node) > SpeculateCellOperand base(this, node->child1()); > GPRReg baseGPR = base.gpr(); > >- ASSERT_UNUSED(oldStructure, oldStructure->indexingType() == newStructure->indexingType()); >+ ASSERT_UNUSED(oldStructure, oldStructure->indexingMode() == newStructure->indexingMode()); > ASSERT(oldStructure->typeInfo().type() == newStructure->typeInfo().type()); > ASSERT(oldStructure->typeInfo().inlineTypeFlags() == newStructure->typeInfo().inlineTypeFlags()); > m_jit.store32(MacroAssembler::TrustedImm32(newStructure->id()), MacroAssembler::Address(baseGPR, JSCell::structureIDOffset())); >diff --git a/Source/JavaScriptCore/dfg/DFGValidate.cpp b/Source/JavaScriptCore/dfg/DFGValidate.cpp >index e94783353042c980205451d9a0fa488afaf6632b..441731930590dfbf89b071bf6b3e1e1eda8e328d 100644 >--- a/Source/JavaScriptCore/dfg/DFGValidate.cpp >+++ b/Source/JavaScriptCore/dfg/DFGValidate.cpp >@@ -355,7 +355,7 @@ public: > VALIDATE((node), node->vectorLengthHint() >= node->numChildren()); > break; > case NewArrayBuffer: >- VALIDATE((node), node->vectorLengthHint() >= node->castOperand<JSFixedArray*>()->length()); >+ VALIDATE((node), node->vectorLengthHint() >= node->castOperand<JSImmutableButterfly*>()->length()); > break; > default: > break; >@@ -793,7 +793,7 @@ private: > > case PhantomNewArrayBuffer: > VALIDATE((node), m_graph.m_form == SSA); >- VALIDATE((node), node->vectorLengthHint() >= node->castOperand<JSFixedArray*>()->length()); >+ VALIDATE((node), node->vectorLengthHint() >= node->castOperand<JSImmutableButterfly*>()->length()); > break; > > case NewArrayWithSpread: { >diff --git a/Source/JavaScriptCore/ftl/FTLAbstractHeapRepository.h b/Source/JavaScriptCore/ftl/FTLAbstractHeapRepository.h >index a828711ff5978ba158a626113d2991c4ca76e46e..5f450d1f2aeb1d70adcc5fa1731292eac252fc21 100644 >--- a/Source/JavaScriptCore/ftl/FTLAbstractHeapRepository.h >+++ b/Source/JavaScriptCore/ftl/FTLAbstractHeapRepository.h >@@ -115,7 +115,7 @@ namespace JSC { namespace FTL { > macro(Structure_prototype, Structure::prototypeOffset()) \ > macro(Structure_structureID, Structure::structureIDOffset()) \ > macro(Structure_inlineCapacity, Structure::inlineCapacityOffset()) \ >- macro(Structure_indexingTypeIncludingHistory, Structure::indexingTypeIncludingHistoryOffset()) \ >+ macro(Structure_indexingModeIncludingHistory, Structure::indexingModeIncludingHistoryOffset()) \ > macro(HashMapImpl_capacity, HashMapImpl<HashMapBucket<HashMapBucketDataKey>>::offsetOfCapacity()) \ > macro(HashMapImpl_buffer, HashMapImpl<HashMapBucket<HashMapBucketDataKey>>::offsetOfBuffer()) \ > macro(HashMapImpl_head, HashMapImpl<HashMapBucket<HashMapBucketDataKey>>::offsetOfHead()) \ >diff --git a/Source/JavaScriptCore/ftl/FTLLowerDFGToB3.cpp b/Source/JavaScriptCore/ftl/FTLLowerDFGToB3.cpp >index 337205147493c086f2167f2583bf2d0e28492368..0579ffdcecc3d62c00658980cd5aff667b728000 100644 >--- a/Source/JavaScriptCore/ftl/FTLLowerDFGToB3.cpp >+++ b/Source/JavaScriptCore/ftl/FTLLowerDFGToB3.cpp >@@ -76,6 +76,7 @@ > #include "JSAsyncGeneratorFunction.h" > #include "JSCInlines.h" > #include "JSGeneratorFunction.h" >+#include "JSImmutableButterfly.h" > #include "JSLexicalEnvironment.h" > #include "JSMap.h" > #include "OperandsInlines.h" >@@ -3035,7 +3036,7 @@ private: > > RegisteredStructure oldStructure = m_node->transition()->previous; > RegisteredStructure newStructure = m_node->transition()->next; >- ASSERT_UNUSED(oldStructure, oldStructure->indexingType() == newStructure->indexingType()); >+ ASSERT_UNUSED(oldStructure, oldStructure->indexingMode() == newStructure->indexingMode()); > ASSERT(oldStructure->typeInfo().inlineTypeFlags() == newStructure->typeInfo().inlineTypeFlags()); > ASSERT(oldStructure->typeInfo().type() == newStructure->typeInfo().type()); > >@@ -4707,7 +4708,8 @@ private: > ArrayValues arrayResult; > { > LValue indexingType = m_out.load8ZeroExt32(lowCell(m_graph.varArgChild(m_node, 0)), m_heaps.JSCell_indexingTypeAndMisc); >- indexingType = m_out.bitAnd(indexingType, m_out.constInt32(AllArrayTypesAndHistory)); >+ // We can ignore the writability of the cell since we won't write to the source. >+ indexingType = m_out.bitAnd(indexingType, m_out.constInt32(AllWritableArrayTypesAndHistory)); > // When we emit an ArraySlice, we dominate the use of the array by a CheckStructure > // to ensure the incoming array is one to be one of the original array structures > // with one of the following indexing shapes: Int32, Contiguous, Double. >@@ -5479,7 +5481,7 @@ private: > else { > Edge& child = m_graph.varArgChild(m_node, i); > if (child->op() == PhantomSpread && child->child1()->op() == PhantomNewArrayBuffer) >- startLength += child->child1()->castOperand<JSFixedArray*>()->length(); >+ startLength += child->child1()->castOperand<JSImmutableButterfly*>()->length(); > } > } > >@@ -5527,7 +5529,7 @@ private: > if (use->op() == PhantomSpread) { > if (use->child1()->op() == PhantomNewArrayBuffer) { > IndexedAbstractHeap& heap = m_heaps.indexedContiguousProperties; >- auto* array = use->child1()->castOperand<JSFixedArray*>(); >+ auto* array = use->child1()->castOperand<JSImmutableButterfly*>(); > for (unsigned i = 0; i < array->length(); ++i) { > // Because resulted array from NewArrayWithSpread is always contiguous, we should not generate value > // in Double form even if PhantomNewArrayBuffer's indexingType is ArrayWithDouble. >@@ -5801,39 +5803,32 @@ private: > { > JSGlobalObject* globalObject = m_graph.globalObjectFor(m_node->origin.semantic); > RegisteredStructure structure = m_graph.registerStructure(globalObject->arrayStructureForIndexingTypeDuringAllocation( >- m_node->indexingType())); >- JSFixedArray* array = m_node->castOperand<JSFixedArray*>(); >- unsigned numElements = array->length(); >- >- if (!globalObject->isHavingABadTime() && !hasAnyArrayStorage(m_node->indexingType())) { >- unsigned vectorLengthHint = m_node->vectorLengthHint(); >- >- ASSERT(vectorLengthHint >= numElements); >- ArrayValues arrayValues = >- allocateUninitializedContiguousJSArray(numElements, vectorLengthHint, structure); >- >- for (unsigned index = 0; index < numElements; ++index) { >- int64_t value; >- if (hasDouble(m_node->indexingType())) >- value = bitwise_cast<int64_t>(array->get(index).asNumber()); >- else >- value = JSValue::encode(array->get(index)); >- >- m_out.store64( >- m_out.constInt64(value), >- arrayValues.butterfly, >- m_heaps.forIndexingType(m_node->indexingType())->at(index)); >- } >- >+ m_node->indexingMode())); >+ auto* immutableButterfly = m_node->castOperand<JSImmutableButterfly*>(); >+ >+ if (!globalObject->isHavingABadTime() && !hasAnyArrayStorage(m_node->indexingMode())) { >+ LBasicBlock slowPath = m_out.newBlock(); >+ LBasicBlock continuation = m_out.newBlock(); >+ >+ LValue fastArray = allocateObject<JSArray>(structure, m_out.constIntPtr(immutableButterfly->toButterfly()), slowPath); >+ ValueFromBlock fastResult = m_out.anchor(fastArray); >+ m_out.jump(continuation); >+ >+ m_out.appendTo(slowPath, continuation); >+ LValue slowArray = vmCall(Int64, m_out.operation(operationNewArrayBuffer), m_callFrame, weakStructure(structure), m_out.weakPointer(m_node->cellOperand())); >+ ValueFromBlock slowResult = m_out.anchor(slowArray); >+ m_out.jump(continuation); >+ >+ m_out.appendTo(continuation); >+ > mutatorFence(); >- setJSValue(arrayValues.array); >+ setJSValue(m_out.phi(pointerType(), slowResult, fastResult)); > return; > } > > setJSValue(vmCall( > Int64, m_out.operation(operationNewArrayBuffer), m_callFrame, >- weakStructure(structure), m_out.weakPointer(m_node->cellOperand()), >- m_out.constIntPtr(numElements))); >+ weakStructure(structure), m_out.weakPointer(m_node->cellOperand()))); > } > > void compileNewArrayWithSize() >@@ -7526,7 +7521,7 @@ private: > } > > if (target->op() == PhantomNewArrayBuffer) { >- staticArgumentCount += target->castOperand<JSFixedArray*>()->length(); >+ staticArgumentCount += target->castOperand<JSImmutableButterfly*>()->length(); > return; > } > >@@ -7677,7 +7672,7 @@ private: > } > > if (target->op() == PhantomNewArrayBuffer) { >- auto* array = target->castOperand<JSFixedArray*>(); >+ auto* array = target->castOperand<JSImmutableButterfly*>(); > Checked<int32_t> offsetCount { 1 }; > for (unsigned i = array->length(); i--; ++offsetCount) { > // Because varargs values are drained as JSValue, we should not generate value >@@ -8364,7 +8359,7 @@ private: > } > > if (target->op() == PhantomNewArrayBuffer) { >- numberOfStaticArguments += target->castOperand<JSFixedArray*>()->length(); >+ numberOfStaticArguments += target->castOperand<JSImmutableButterfly*>()->length(); > return; > } > >@@ -8409,7 +8404,7 @@ private: > } > > if (target->op() == PhantomNewArrayBuffer) { >- auto* array = target->castOperand<JSFixedArray*>(); >+ auto* array = target->castOperand<JSImmutableButterfly*>(); > for (unsigned i = 0; i < array->length(); i++) { > // Because forwarded values are drained as JSValue, we should not generate value > // in Double form even if PhantomNewArrayBuffer's indexingType is ArrayWithDouble. >@@ -12509,7 +12504,7 @@ private: > LValue id = m_out.load32(structure, m_heaps.Structure_structureID); > m_out.store32(id, object, m_heaps.JSCell_structureID); > >- LValue blob = m_out.load32(structure, m_heaps.Structure_indexingTypeIncludingHistory); >+ LValue blob = m_out.load32(structure, m_heaps.Structure_indexingModeIncludingHistory); > m_out.store32(blob, object, m_heaps.JSCell_usefulBytes); > } > >@@ -14921,6 +14916,10 @@ private: > case Array::Contiguous: > case Array::Undecided: > case Array::ArrayStorage: { >+ IndexingType indexingModeMask = IsArray | IndexingShapeMask; >+ if (arrayMode.action() == Array::Write) >+ indexingModeMask |= CopyOnWrite; >+ > IndexingType shape = arrayMode.shapeMask(); > LValue indexingType = m_out.load8ZeroExt32(cell, m_heaps.JSCell_indexingTypeAndMisc); > >@@ -14931,18 +14930,18 @@ private: > > case Array::Array: > return m_out.equal( >- m_out.bitAnd(indexingType, m_out.constInt32(IsArray | IndexingShapeMask)), >+ m_out.bitAnd(indexingType, m_out.constInt32(indexingModeMask)), > m_out.constInt32(IsArray | shape)); > > case Array::NonArray: > case Array::OriginalNonArray: > return m_out.equal( >- m_out.bitAnd(indexingType, m_out.constInt32(IsArray | IndexingShapeMask)), >+ m_out.bitAnd(indexingType, m_out.constInt32(indexingModeMask)), > m_out.constInt32(shape)); > > case Array::PossiblyArray: > return m_out.equal( >- m_out.bitAnd(indexingType, m_out.constInt32(IndexingShapeMask)), >+ m_out.bitAnd(indexingType, m_out.constInt32(indexingModeMask & ~IsArray)), > m_out.constInt32(shape)); > } > break; >diff --git a/Source/JavaScriptCore/ftl/FTLOperations.cpp b/Source/JavaScriptCore/ftl/FTLOperations.cpp >index 7508bb032cf23ee927ca4b3c35fb638c46a87fa7..a77655ba24b03682560f178f9a02f47f5823384d 100644 >--- a/Source/JavaScriptCore/ftl/FTLOperations.cpp >+++ b/Source/JavaScriptCore/ftl/FTLOperations.cpp >@@ -39,6 +39,7 @@ > #include "JSCInlines.h" > #include "JSFixedArray.h" > #include "JSGeneratorFunction.h" >+#include "JSImmutableButterfly.h" > #include "JSLexicalEnvironment.h" > #include "RegExpObject.h" > >@@ -458,11 +459,11 @@ extern "C" JSCell* JIT_OPERATION operationMaterializeObjectInOSR( > } > > case PhantomNewArrayBuffer: { >- JSFixedArray* array = nullptr; >+ JSImmutableButterfly* array = nullptr; > for (unsigned i = materialization->properties().size(); i--;) { > const ExitPropertyValue& property = materialization->properties()[i]; > if (property.location().kind() == NewArrayBufferPLoc) { >- array = jsCast<JSFixedArray*>(JSValue::decode(values[i])); >+ array = jsCast<JSImmutableButterfly*>(JSValue::decode(values[i])); > break; > } > } >@@ -473,7 +474,9 @@ extern "C" JSCell* JIT_OPERATION operationMaterializeObjectInOSR( > CodeBlock* codeBlock = baselineCodeBlockForOriginAndBaselineCodeBlock(materialization->origin(), exec->codeBlock()); > Instruction* currentInstruction = &codeBlock->instructions()[materialization->origin().bytecodeIndex]; > RELEASE_ASSERT(Interpreter::getOpcodeID(currentInstruction[0].u.opcode) == op_new_array_buffer); >- return constructArray(exec, currentInstruction[3].u.arrayAllocationProfile, array->values(), array->length()); >+ Structure* structure = exec->lexicalGlobalObject()->arrayStructureForIndexingTypeDuringAllocation(currentInstruction[3].u.arrayAllocationProfile->selectIndexingType()); >+ ASSERT(!structure->outOfLineCapacity()); >+ return JSArray::createWithButterfly(vm, nullptr, structure, array->toButterfly()); > } > > case PhantomNewArrayWithSpread: { >diff --git a/Source/JavaScriptCore/generate-bytecode-files b/Source/JavaScriptCore/generate-bytecode-files >index 8300bd080fec55a186c42e572fb985efaa5d4dfb..fa25fd2ef31be4c1eb3c3a585be529d67cfed6d8 100644 >--- a/Source/JavaScriptCore/generate-bytecode-files >+++ b/Source/JavaScriptCore/generate-bytecode-files >@@ -112,13 +112,13 @@ def toCpp(name): > > > def writeInstructionAccessor(bytecodeHFile, typeName, name): >- bytecodeHFile.write(" {0}& {1}() {{ return *reinterpret_cast<{0}*>(&m_{1}); }}\n".format(typeName, name)) >- bytecodeHFile.write(" const {0}& {1}() const {{ return *reinterpret_cast<const {0}*>(&m_{1}); }}\n".format(typeName, name)) >+ bytecodeHFile.write(" {0}& {1}() {{ return *bitwise_cast<{0}*>(&m_{1}); }}\n".format(typeName, name)) >+ bytecodeHFile.write(" const {0}& {1}() const {{ return *bitwise_cast<const {0}*>(&m_{1}); }}\n".format(typeName, name)) > > > def writeInstructionMember(bytecodeHFile, typeName, name): > bytecodeHFile.write(" std::aligned_storage<sizeof({0}), sizeof(Instruction)>::type m_{1};\n".format(typeName, name)) >- >+ bytecodeHFile.write(" static_assert(sizeof({0}) <= sizeof(Instruction), \"Size of {0} shouldn't be bigger than an Instruction.\");\n".format(typeName, name)) > > def writeStruct(bytecodeHFile, bytecode): > bytecodeHFile.write("struct {0} {{\n".format(toCpp(bytecode["name"]))) >diff --git a/Source/JavaScriptCore/interpreter/Interpreter.cpp b/Source/JavaScriptCore/interpreter/Interpreter.cpp >index 4f72709b9fbeab536b2b44036f7b50f9c9b9ec73..f720b97123eb4063b0bf05618b203ce5efde30c7 100644 >--- a/Source/JavaScriptCore/interpreter/Interpreter.cpp >+++ b/Source/JavaScriptCore/interpreter/Interpreter.cpp >@@ -51,6 +51,7 @@ > #include "JSBoundFunction.h" > #include "JSCInlines.h" > #include "JSFixedArray.h" >+#include "JSImmutableButterfly.h" > #include "JSLexicalEnvironment.h" > #include "JSModuleEnvironment.h" > #include "JSString.h" >@@ -200,6 +201,9 @@ unsigned sizeOfVarargs(CallFrame* callFrame, JSValue arguments, uint32_t firstVa > case JSFixedArrayType: > length = jsCast<JSFixedArray*>(cell)->size(); > break; >+ case JSImmutableButterflyType: >+ length = jsCast<JSImmutableButterfly*>(cell)->length(); >+ break; > case StringType: > case SymbolType: > case BigIntType: >@@ -271,6 +275,10 @@ void loadVarargs(CallFrame* callFrame, VirtualRegister firstElementDest, JSValue > scope.release(); > jsCast<JSFixedArray*>(cell)->copyToArguments(callFrame, firstElementDest, offset, length); > return; >+ case JSImmutableButterflyType: >+ scope.release(); >+ jsCast<JSImmutableButterfly*>(cell)->copyToArguments(callFrame, firstElementDest, offset, length); >+ return; > default: { > ASSERT(arguments.isObject()); > JSObject* object = jsCast<JSObject*>(cell); >diff --git a/Source/JavaScriptCore/jit/AssemblyHelpers.cpp b/Source/JavaScriptCore/jit/AssemblyHelpers.cpp >index 29ad53ed72f77b709a9f97ca34acaf67302e2a15..8529dda3fddeac621c87c6b139e69fbd68239d93 100644 >--- a/Source/JavaScriptCore/jit/AssemblyHelpers.cpp >+++ b/Source/JavaScriptCore/jit/AssemblyHelpers.cpp >@@ -405,7 +405,7 @@ void AssemblyHelpers::emitStoreStructureWithTypeInfo(AssemblyHelpers& jit, Trust > jit.abortWithReason(AHStructureIDIsValid); > correctStructure.link(&jit); > >- Jump correctIndexingType = jit.branch8(Equal, MacroAssembler::Address(dest, JSCell::indexingTypeAndMiscOffset()), TrustedImm32(structurePtr->indexingTypeIncludingHistory())); >+ Jump correctIndexingType = jit.branch8(Equal, MacroAssembler::Address(dest, JSCell::indexingTypeAndMiscOffset()), TrustedImm32(structurePtr->indexingModeIncludingHistory())); > jit.abortWithReason(AHIndexingTypeIsValid); > correctIndexingType.link(&jit); > >diff --git a/Source/JavaScriptCore/jit/AssemblyHelpers.h b/Source/JavaScriptCore/jit/AssemblyHelpers.h >index 20998e349ef11337b95b9cca703a4339bc3db50d..899f7e65c17a61781d2cf08dd2a358d61783397a 100644 >--- a/Source/JavaScriptCore/jit/AssemblyHelpers.h >+++ b/Source/JavaScriptCore/jit/AssemblyHelpers.h >@@ -1346,7 +1346,7 @@ public: > store64(scratch, MacroAssembler::Address(dest, JSCell::structureIDOffset())); > #else > // Store all the info flags using a single 32-bit wide load and store. >- load32(MacroAssembler::Address(structure, Structure::indexingTypeIncludingHistoryOffset()), scratch); >+ load32(MacroAssembler::Address(structure, Structure::indexingModeIncludingHistoryOffset()), scratch); > store32(scratch, MacroAssembler::Address(dest, JSCell::indexingTypeAndMiscOffset())); > > // Store the StructureID >diff --git a/Source/JavaScriptCore/jit/JITOperations.cpp b/Source/JavaScriptCore/jit/JITOperations.cpp >index 365bb73755a7a454cf085436c6378d1bf73fec4b..e596855f33a3f1c2071000230ffa1018de4ea43e 100644 >--- a/Source/JavaScriptCore/jit/JITOperations.cpp >+++ b/Source/JavaScriptCore/jit/JITOperations.cpp >@@ -660,6 +660,7 @@ static void directPutByVal(CallFrame* callFrame, JSObject* baseObject, JSValue s > VM& vm = callFrame->vm(); > auto scope = DECLARE_THROW_SCOPE(vm); > bool isStrictMode = callFrame->codeBlock()->isStrictMode(); >+ > if (LIKELY(subscript.isUInt32())) { > // Despite its name, JSValue::isUInt32 will return true only for positive boxed int32_t; all those values are valid array indices. > byValInfo->tookSlowPath = true; >@@ -727,6 +728,10 @@ static OptimizationResult tryPutByValOptimize(ExecState* exec, JSValue baseValue > > VM& vm = exec->vm(); > >+ // TODO: Do we want this? >+ if (baseValue.isObject() && isCopyOnWrite(baseValue.getObject()->indexingMode())) >+ return OptimizationResult::GiveUp; >+ > if (baseValue.isObject() && subscript.isInt32()) { > JSObject* object = asObject(baseValue); > >diff --git a/Source/JavaScriptCore/jit/JITPropertyAccess.cpp b/Source/JavaScriptCore/jit/JITPropertyAccess.cpp >index 1b97da1a07b49ac3066262b1284dc20f1462e91a..f00ee1cf3342cd5f5fdceee0be17d6a2f82296e5 100644 >--- a/Source/JavaScriptCore/jit/JITPropertyAccess.cpp >+++ b/Source/JavaScriptCore/jit/JITPropertyAccess.cpp >@@ -302,11 +302,14 @@ void JIT::emit_op_put_by_val(Instruction* currentInstruction) > zeroExtend32ToPtr(regT1, regT1); > } > emitArrayProfilingSiteWithCell(regT0, regT2, profile); >- and32(TrustedImm32(IndexingShapeMask), regT2); >- >+ > PatchableJump badType; > JumpList slowCases; >- >+ >+ // TODO: Maybe we should do this inline? >+ addSlowCase(branchTest32(NonZero, regT2, TrustedImm32(CopyOnWrite))); >+ and32(TrustedImm32(IndexingShapeMask), regT2); >+ > JITArrayMode mode = chooseArrayMode(profile); > switch (mode) { > case JITInt32: >@@ -462,25 +465,9 @@ void JIT::emitSlow_op_put_by_val(Instruction* currentInstruction, Vector<SlowCas > int base = currentInstruction[1].u.operand; > int property = currentInstruction[2].u.operand; > int value = currentInstruction[3].u.operand; >- JITArrayMode mode = m_byValCompilationInfo[m_byValInstructionIndex].arrayMode; > ByValInfo* byValInfo = m_byValCompilationInfo[m_byValInstructionIndex].byValInfo; > >- linkSlowCaseIfNotJSCell(iter, base); // base cell check >- if (!isOperandConstantInt(property)) >- linkSlowCase(iter); // property int32 check >- linkSlowCase(iter); // base not array check >- >- linkSlowCase(iter); // out of bounds >- >- switch (mode) { >- case JITInt32: >- case JITDouble: >- linkSlowCase(iter); // value type check >- break; >- default: >- break; >- } >- >+ linkAllSlowCases(iter); > Label slowPath = label(); > > emitGetVirtualRegister(base, regT0); >diff --git a/Source/JavaScriptCore/llint/LowLevelInterpreter.asm b/Source/JavaScriptCore/llint/LowLevelInterpreter.asm >index adc1d6e656f3eecdf85e5ec66f64750d4bbf27dc..9a27992690e5fbc9333304bd4f14f0b2067bad15 100644 >--- a/Source/JavaScriptCore/llint/LowLevelInterpreter.asm >+++ b/Source/JavaScriptCore/llint/LowLevelInterpreter.asm >@@ -376,6 +376,7 @@ const DoubleShape = constexpr DoubleShape > const ContiguousShape = constexpr ContiguousShape > const ArrayStorageShape = constexpr ArrayStorageShape > const SlowPutArrayStorageShape = constexpr SlowPutArrayStorageShape >+const CopyOnWrite = constexpr CopyOnWrite > > # Type constants. > const StringType = constexpr StringType >diff --git a/Source/JavaScriptCore/llint/LowLevelInterpreter32_64.asm b/Source/JavaScriptCore/llint/LowLevelInterpreter32_64.asm >index d51b6d14c00fad68d84770f3c03beb88646f2791..80f41d804a6dfa0d9124c94ec41dd11061e06489 100644 >--- a/Source/JavaScriptCore/llint/LowLevelInterpreter32_64.asm >+++ b/Source/JavaScriptCore/llint/LowLevelInterpreter32_64.asm >@@ -1703,6 +1703,7 @@ macro putByVal(slowPath) > loadi 8[PC], t0 > loadConstantOrVariablePayload(t0, Int32Tag, t3, .opPutByValSlow) > loadp JSObject::m_butterfly[t1], t0 >+ btinz t2, CopyOnWrite, .opPutByValSlow > andi IndexingShapeMask, t2 > bineq t2, Int32Shape, .opPutByValNotInt32 > contiguousPutByVal( >diff --git a/Source/JavaScriptCore/llint/LowLevelInterpreter64.asm b/Source/JavaScriptCore/llint/LowLevelInterpreter64.asm >index 626989d526faeb02a85b20e95d6dcb968abb0ad0..203c6cb1f3012ff4288b8c1a35e468b6a8882d1b 100644 >--- a/Source/JavaScriptCore/llint/LowLevelInterpreter64.asm >+++ b/Source/JavaScriptCore/llint/LowLevelInterpreter64.asm >@@ -1740,6 +1740,7 @@ macro putByVal(slowPath) > loadConstantOrVariableInt32(t0, t3, .opPutByValSlow) > sxi2q t3, t3 > loadCaged(_g_gigacageBasePtrs + Gigacage::BasePtrs::jsValue, constexpr JSVALUE_GIGACAGE_MASK, JSObject::m_butterfly[t1], t0, t5) >+ btinz t2, CopyOnWrite, .opPutByValSlow > andi IndexingShapeMask, t2 > bineq t2, Int32Shape, .opPutByValNotInt32 > contiguousPutByVal( >diff --git a/Source/JavaScriptCore/runtime/Butterfly.h b/Source/JavaScriptCore/runtime/Butterfly.h >index 71fe75b9fcc6c3b4943697a9cc8e94d8be565c46..f331e42ff796a6fa36519680a84c3b0d6ec0d45d 100644 >--- a/Source/JavaScriptCore/runtime/Butterfly.h >+++ b/Source/JavaScriptCore/runtime/Butterfly.h >@@ -48,8 +48,34 @@ struct ContiguousData { > UNUSED_PARAM(length); > } > >- const T& at(size_t index) const { ASSERT(index < m_length); return m_data[index]; } >- T& at(size_t index) { ASSERT(index < m_length); return m_data[index]; } >+ struct Data { >+ Data(T& location, bool isWritable) >+ : m_data(location) >+ , m_isWritable(isWritable) >+ { } >+ >+ T& operator=(const T& value) { >+ ASSERT(m_isWritable); >+ m_data = value; >+ return value; >+ } >+ >+ void set(VM& vm, const JSCell* owner, const T& value) >+ { >+ ASSERT(m_isWritable); >+ m_data.set(vm, owner, value); >+ } >+ >+ operator T&() { return m_data; } >+ >+ T& m_data; >+ bool m_isWritable; >+ }; >+ >+ const T& at(const JSCell* owner, size_t index) const; >+ T& at(const JSCell* owner, size_t index); >+ >+ T& atUnsafe(size_t index) { ASSERT(index < m_length); return m_data[index]; } > > T* data() const { return m_data; } > #if !ASSERT_DISABLED >diff --git a/Source/JavaScriptCore/runtime/ButterflyInlines.h b/Source/JavaScriptCore/runtime/ButterflyInlines.h >index 59a662b9a088659edb445d091e29279e51344ac9..ce895d6ccdb44c157d3c5ac8c9126f01447b0b83 100644 >--- a/Source/JavaScriptCore/runtime/ButterflyInlines.h >+++ b/Source/JavaScriptCore/runtime/ButterflyInlines.h >@@ -33,6 +33,11 @@ > > namespace JSC { > >+template<typename T> >+const T& ContiguousData<T>::at(const JSCell*, size_t index) const { ASSERT(index < m_length); return m_data[index]; } >+template<typename T> >+T& ContiguousData<T>::at(const JSCell* owner, size_t index) { ASSERT(index < m_length); return Data(m_data[index], !isCopyOnWrite(owner->indexingMode())); } >+ > ALWAYS_INLINE unsigned Butterfly::availableContiguousVectorLength(size_t propertyCapacity, unsigned vectorLength) > { > size_t cellSize = totalSize(0, propertyCapacity, true, sizeof(EncodedJSValue) * vectorLength); >diff --git a/Source/JavaScriptCore/runtime/ClonedArguments.cpp b/Source/JavaScriptCore/runtime/ClonedArguments.cpp >index 3ad6a769ccf35e85ec2b010669c84cc62a9ff2e5..8f461d0037ea4706e5bc79e2a5a46cb748732898 100644 >--- a/Source/JavaScriptCore/runtime/ClonedArguments.cpp >+++ b/Source/JavaScriptCore/runtime/ClonedArguments.cpp >@@ -61,7 +61,7 @@ ClonedArguments* ClonedArguments::createEmpty( > return 0; > > for (unsigned i = length; i < vectorLength; ++i) >- butterfly->contiguous().at(i).clear(); >+ butterfly->contiguous().atUnsafe(i).clear(); > } > > ClonedArguments* result = >diff --git a/Source/JavaScriptCore/runtime/CommonSlowPaths.cpp b/Source/JavaScriptCore/runtime/CommonSlowPaths.cpp >index e6c1a44d67f42145285fb0d200745dbcb3a7df77..d380d914dd6e988bbffaadf56456ef17f34494e3 100644 >--- a/Source/JavaScriptCore/runtime/CommonSlowPaths.cpp >+++ b/Source/JavaScriptCore/runtime/CommonSlowPaths.cpp >@@ -51,6 +51,7 @@ > #include "JSCJSValue.h" > #include "JSFixedArray.h" > #include "JSGlobalObjectFunctions.h" >+#include "JSImmutableButterfly.h" > #include "JSLexicalEnvironment.h" > #include "JSPropertyNameEnumerator.h" > #include "JSString.h" >@@ -95,6 +96,7 @@ namespace JSC { > #define OP_C(index) (exec->r(pc[index].u.operand)) > > #define GET(operand) (exec->uncheckedR(operand)) >+#define GET_C(operand) (exec->r(operand)) > > #define RETURN_TWO(first, second) do { \ > return encodeResult(first, second); \ >@@ -1069,8 +1071,46 @@ SLOW_PATH_DECL(slow_path_new_array_with_spread) > SLOW_PATH_DECL(slow_path_new_array_buffer) > { > BEGIN(); >- auto* fixedArray = jsCast<JSFixedArray*>(OP_C(2).jsValue()); >- RETURN(constructArray(exec, pc[3].u.arrayAllocationProfile, fixedArray->values(), fixedArray->length())); >+ auto* newArrayBuffer = bitwise_cast<OpNewArrayBuffer*>(pc); >+ ASSERT(exec->codeBlock()->isConstantRegisterIndex(newArrayBuffer->immutableButterfly())); >+ JSImmutableButterfly* immutableButterfly = bitwise_cast<JSImmutableButterfly*>(GET_C(newArrayBuffer->immutableButterfly())); >+ auto* profile = newArrayBuffer->profile(); >+ >+ IndexingType indexingMode = profile->selectIndexingType(); >+ Structure* originalStructure = exec->lexicalGlobalObject()->originalArrayStructureForIndexingType(indexingMode); >+ Structure* structure = exec->lexicalGlobalObject()->arrayStructureForIndexingTypeDuringAllocation(indexingMode); >+ ASSERT(originalStructure->indexingMode() == indexingMode); >+ ASSERT(isCopyOnWrite(indexingMode)); >+ ASSERT(!structure->outOfLineCapacity()); >+ >+ if (UNLIKELY(immutableButterfly->indexingMode() != indexingMode)) { >+ auto* newButterfly = JSImmutableButterfly::create(vm, indexingMode, immutableButterfly->length()); >+ for (unsigned i = 0; i < immutableButterfly->length(); ++i) >+ newButterfly->setIndex(vm, i, immutableButterfly->get(i)); >+ immutableButterfly = newButterfly; >+ CodeBlock* codeBlock = exec->codeBlock(); >+ >+ // FIXME: This is kinda gross and only works because we can't inline new_array_bufffer in the baseline. >+ // We also cannot allocate a new butterfly from compilation threads since it's invalid to allocate cells from >+ // a compilation thread. >+ WTF::storeStoreFence(); >+ codeBlock->constantRegister(newArrayBuffer->immutableButterfly()).set(vm, codeBlock, immutableButterfly); >+ WTF::storeStoreFence(); >+ } >+ >+ JSArray* result = JSArray::createWithButterfly(vm, nullptr, originalStructure, immutableButterfly->toButterfly()); >+ // FIXME: This works but it's slow. If we cared enough about the perf when having a bad time then we could fix it. >+ if (UNLIKELY(originalStructure != structure)) { >+ ASSERT(hasSlowPutArrayStorage(structure->indexingMode())); >+ ASSERT(exec->lexicalGlobalObject()->isHavingABadTime()); >+ >+ result->switchToSlowPutArrayStorage(vm); >+ ASSERT(result->butterfly() != immutableButterfly->toButterfly()); >+ ASSERT(!result->butterfly()->arrayStorage()->m_sparseMap.get()); >+ ASSERT(result->structureID() == structure->id()); >+ } >+ >+ RETURN(result); > } > > SLOW_PATH_DECL(slow_path_spread) >diff --git a/Source/JavaScriptCore/runtime/IndexingType.cpp b/Source/JavaScriptCore/runtime/IndexingType.cpp >index 8b5ab3c5bc80f832fa0da647eaba7545e2a174d4..b1bfbce3b176abadd89f75adfc4aa50f2805888a 100644 >--- a/Source/JavaScriptCore/runtime/IndexingType.cpp >+++ b/Source/JavaScriptCore/runtime/IndexingType.cpp >@@ -111,6 +111,15 @@ void dumpIndexingType(PrintStream& out, IndexingType indexingType) > case ArrayWithSlowPutArrayStorage: > basicName = "ArrayWithSlowPutArrayStorage"; > break; >+ case CopyOnWriteArrayWithInt32: >+ basicName = "CopyOnWriteArrayWithInt32"; >+ break; >+ case CopyOnWriteArrayWithDouble: >+ basicName = "CopyOnWriteArrayWithDouble"; >+ break; >+ case CopyOnWriteArrayWithContiguous: >+ basicName = "CopyOnWriteArrayWithContiguous"; >+ break; > default: > basicName = "Unknown!"; > break; >diff --git a/Source/JavaScriptCore/runtime/IndexingType.h b/Source/JavaScriptCore/runtime/IndexingType.h >index 689fae264205b1e03184190b16cc851a5ab07d80..5eb0a204fd35c95583fbef0200ed9e3929c32c60 100644 >--- a/Source/JavaScriptCore/runtime/IndexingType.h >+++ b/Source/JavaScriptCore/runtime/IndexingType.h >@@ -34,17 +34,27 @@ namespace JSC { > /* > Structure of the IndexingType > ============================= >- Conceptually, the IndexingType looks like this: >- >- struct IndexingType { >- uint8_t isArray:1; // bit 0 >- uint8_t shape:4; // bit 1 - 3 >- uint8_t mayHaveIndexedAccessors:1; // bit 4 >+ Conceptually, the IndexingTypeAndMisc looks like this: >+ >+ struct IndexingTypeAndMisc { >+ struct IndexingModeIncludingHistory { >+ struct IndexingMode { >+ struct IndexingType { >+ uint8_t isArray:1; // bit 0 >+ uint8_t shape:3; // bit 1 - 3 >+ }; >+ uint8_t copyOnWrite:1; // bit 4 >+ }; >+ uint8_t mayHaveIndexedAccessors:1; // bit 5 >+ }; >+ uint8_t cellLockBits:2; // bit 6 - 7 > }; > > The shape values (e.g. Int32Shape, ContiguousShape, etc) are an enumeration of > various shapes (though not necessarily sequential in terms of their values). > Hence, shape values are not bitwise exclusive with respect to each other. >+ >+ It's also common to refer to shape + copyOnWrite as IndexingShapeWithWritability. > */ > > typedef uint8_t IndexingType; >@@ -53,7 +63,6 @@ typedef uint8_t IndexingType; > static const IndexingType IsArray = 0x01; > > // The shape of the indexed property storage. >-static const IndexingType IndexingShapeMask = 0x0E; > static const IndexingType NoIndexingShape = 0x00; > static const IndexingType UndecidedShape = 0x02; // Only useful for arrays. > static const IndexingType Int32Shape = 0x04; >@@ -62,17 +71,25 @@ static const IndexingType ContiguousShape = 0x08; > static const IndexingType ArrayStorageShape = 0x0A; > static const IndexingType SlowPutArrayStorageShape = 0x0C; > >+static const IndexingType IndexingShapeMask = 0x0E; > static const IndexingType IndexingShapeShift = 1; > static const IndexingType NumberOfIndexingShapes = 7; >+static const IndexingType IndexingTypeMask = IndexingShapeMask | IsArray; >+ >+// Whether or not the butterfly is copy on write. If it is copy on write then the butterfly is actually a JSImmutableButterfly. This should only ever be set if there are no named properties. >+static const IndexingType CopyOnWrite = 0x10; >+static const IndexingType IndexingShapeAndWritabilityMask = CopyOnWrite | IndexingShapeMask; >+static const IndexingType NumberOfCopyOnWriteIndexingModes = 3; // We only have copy on write for int32, double, and contiguous shapes. >+static const IndexingType NumberOfArrayIndexingModes = NumberOfIndexingShapes + NumberOfCopyOnWriteIndexingModes; > > // Additional flags for tracking the history of the type. These are usually > // masked off unless you ask for them directly. >-static const IndexingType MayHaveIndexedAccessors = 0x10; >+static const IndexingType MayHaveIndexedAccessors = 0x20; > > // The IndexingType field of JSCells is stolen for locks and remembering if the object has been a > // prototype. >-static const IndexingType IndexingTypeLockIsHeld = 0x20; >-static const IndexingType IndexingTypeLockHasParked = 0x40; >+static const IndexingType IndexingTypeLockIsHeld = 0x40; >+static const IndexingType IndexingTypeLockHasParked = 0x80; > > // List of acceptable array types. > static const IndexingType NonArray = 0x0; >@@ -88,6 +105,9 @@ static const IndexingType ArrayWithDouble = IsArray | DoubleShap > static const IndexingType ArrayWithContiguous = IsArray | ContiguousShape; > static const IndexingType ArrayWithArrayStorage = IsArray | ArrayStorageShape; > static const IndexingType ArrayWithSlowPutArrayStorage = IsArray | SlowPutArrayStorageShape; >+static const IndexingType CopyOnWriteArrayWithInt32 = IsArray | Int32Shape | CopyOnWrite; >+static const IndexingType CopyOnWriteArrayWithDouble = IsArray | DoubleShape | CopyOnWrite; >+static const IndexingType CopyOnWriteArrayWithContiguous = IsArray | ContiguousShape | CopyOnWrite; > > #define ALL_BLANK_INDEXING_TYPES \ > NonArray: \ >@@ -96,17 +116,29 @@ static const IndexingType ArrayWithSlowPutArrayStorage = IsArray | SlowPutArr > #define ALL_UNDECIDED_INDEXING_TYPES \ > ArrayWithUndecided > >-#define ALL_INT32_INDEXING_TYPES \ >- NonArrayWithInt32: \ >+#define ALL_WRITABLE_INT32_INDEXING_TYPES \ >+ NonArrayWithInt32: \ > case ArrayWithInt32 > >-#define ALL_DOUBLE_INDEXING_TYPES \ >- NonArrayWithDouble: \ >- case ArrayWithDouble >+#define ALL_INT32_INDEXING_TYPES \ >+ ALL_WRITABLE_INT32_INDEXING_TYPES: \ >+ case CopyOnWriteArrayWithInt32 > >-#define ALL_CONTIGUOUS_INDEXING_TYPES \ >- NonArrayWithContiguous: \ >- case ArrayWithContiguous >+#define ALL_WRITABLE_DOUBLE_INDEXING_TYPES \ >+ NonArrayWithDouble: \ >+ case ArrayWithDouble \ >+ >+#define ALL_DOUBLE_INDEXING_TYPES \ >+ ALL_WRITABLE_DOUBLE_INDEXING_TYPES: \ >+ case CopyOnWriteArrayWithDouble >+ >+#define ALL_WRITABLE_CONTIGUOUS_INDEXING_TYPES \ >+ NonArrayWithContiguous: \ >+ case ArrayWithContiguous \ >+ >+#define ALL_CONTIGUOUS_INDEXING_TYPES \ >+ ALL_WRITABLE_CONTIGUOUS_INDEXING_TYPES: \ >+ case CopyOnWriteArrayWithContiguous > > #define ARRAY_WITH_ARRAY_STORAGE_INDEXING_TYPES \ > ArrayWithArrayStorage: \ >@@ -117,51 +149,65 @@ static const IndexingType ArrayWithSlowPutArrayStorage = IsArray | SlowPutArr > case NonArrayWithSlowPutArrayStorage: \ > case ARRAY_WITH_ARRAY_STORAGE_INDEXING_TYPES > >-static inline bool hasIndexedProperties(IndexingType indexingType) >+inline bool hasIndexedProperties(IndexingType indexingType) > { > return (indexingType & IndexingShapeMask) != NoIndexingShape; > } > >-static inline bool hasUndecided(IndexingType indexingType) >+inline bool hasUndecided(IndexingType indexingType) > { > return (indexingType & IndexingShapeMask) == UndecidedShape; > } > >-static inline bool hasInt32(IndexingType indexingType) >+inline bool hasInt32(IndexingType indexingType) > { > return (indexingType & IndexingShapeMask) == Int32Shape; > } > >-static inline bool hasDouble(IndexingType indexingType) >+inline bool hasDouble(IndexingType indexingType) > { > return (indexingType & IndexingShapeMask) == DoubleShape; > } > >-static inline bool hasContiguous(IndexingType indexingType) >+inline bool hasContiguous(IndexingType indexingType) > { > return (indexingType & IndexingShapeMask) == ContiguousShape; > } > >-static inline bool hasArrayStorage(IndexingType indexingType) >+inline bool hasArrayStorage(IndexingType indexingType) > { > return (indexingType & IndexingShapeMask) == ArrayStorageShape; > } > >-static inline bool hasAnyArrayStorage(IndexingType indexingType) >+inline bool hasAnyArrayStorage(IndexingType indexingType) > { > return static_cast<uint8_t>(indexingType & IndexingShapeMask) >= ArrayStorageShape; > } > >-static inline bool hasSlowPutArrayStorage(IndexingType indexingType) >+inline bool hasSlowPutArrayStorage(IndexingType indexingType) > { > return (indexingType & IndexingShapeMask) == SlowPutArrayStorageShape; > } > >-static inline bool shouldUseSlowPut(IndexingType indexingType) >+inline bool shouldUseSlowPut(IndexingType indexingType) > { > return hasSlowPutArrayStorage(indexingType); > } > >+inline constexpr bool isCopyOnWrite(IndexingType indexingMode) >+{ >+ return indexingMode & CopyOnWrite; >+} >+ >+inline unsigned arrayIndexFromIndexingType(IndexingType indexingType) >+{ >+ if (isCopyOnWrite(indexingType)) >+ return ((indexingType & IndexingShapeMask) - UndecidedShape + SlowPutArrayStorageShape) >> IndexingShapeShift; >+ return (indexingType & IndexingShapeMask) >> IndexingShapeShift; >+} >+ >+ >+ > inline IndexingType indexingTypeForValue(JSValue value) > { > if (value.isInt32()) >@@ -182,10 +228,9 @@ IndexingType leastUpperBoundOfIndexingTypeAndValue(IndexingType, JSValue); > void dumpIndexingType(PrintStream&, IndexingType); > MAKE_PRINT_ADAPTOR(IndexingTypeDump, IndexingType, dumpIndexingType); > >-// Mask of all possible types. >-static const IndexingType AllArrayTypes = IndexingShapeMask | IsArray; >- >-// Mask of all possible types including the history. >+static const IndexingType AllWritableArrayTypes = IndexingShapeMask | IsArray; >+static const IndexingType AllArrayTypes = AllWritableArrayTypes | CopyOnWrite; >+static const IndexingType AllWritableArrayTypesAndHistory = AllWritableArrayTypes | MayHaveIndexedAccessors; > static const IndexingType AllArrayTypesAndHistory = AllArrayTypes | MayHaveIndexedAccessors; > > typedef LockAlgorithm<IndexingType, IndexingTypeLockIsHeld, IndexingTypeLockHasParked> IndexingTypeLockAlgorithm; >diff --git a/Source/JavaScriptCore/runtime/JSArray.cpp b/Source/JavaScriptCore/runtime/JSArray.cpp >index 4260ca4f5e4a8c8453a79ad1f3684b89de355bd2..1f0fc80abf8a76f4706163a539965abec4df2a03 100644 >--- a/Source/JavaScriptCore/runtime/JSArray.cpp >+++ b/Source/JavaScriptCore/runtime/JSArray.cpp >@@ -93,10 +93,10 @@ JSArray* JSArray::tryCreateUninitializedRestricted(ObjectInitializationScope& sc > unsigned i = (createUninitialized ? initialLength : 0); > if (hasDouble(indexingType)) { > for (; i < vectorLength; ++i) >- butterfly->contiguousDouble().at(i) = PNaN; >+ butterfly->contiguousDouble().atUnsafe(i) = PNaN; > } else { > for (; i < vectorLength; ++i) >- butterfly->contiguous().at(i).clear(); >+ butterfly->contiguous().atUnsafe(i).clear(); > } > } else { > static const unsigned indexBias = 0; >@@ -547,10 +547,10 @@ bool JSArray::appendMemcpy(ExecState* exec, VM& vm, unsigned startIndex, JSC::JS > auto* butterfly = this->butterfly(); > if (type == ArrayWithDouble) { > for (unsigned i = startIndex; i < newLength; ++i) >- butterfly->contiguousDouble().at(i) = PNaN; >+ butterfly->contiguousDouble().at(this, i) = PNaN; > } else { > for (unsigned i = startIndex; i < newLength; ++i) >- butterfly->contiguousInt32().at(i).setWithoutWriteBarrier(JSValue()); >+ butterfly->contiguousInt32().at(this, i).setWithoutWriteBarrier(JSValue()); > } > } else if (type == ArrayWithDouble) > memcpy(butterfly()->contiguousDouble().data() + startIndex, otherArray->butterfly()->contiguousDouble().data(), sizeof(JSValue) * otherLength); >@@ -580,7 +580,7 @@ bool JSArray::setLength(ExecState* exec, unsigned newLength, bool throwException > } > createInitialUndecided(vm, newLength); > return true; >- >+ > case ArrayWithUndecided: > case ArrayWithInt32: > case ArrayWithDouble: >@@ -612,10 +612,10 @@ bool JSArray::setLength(ExecState* exec, unsigned newLength, bool throwException > > if (indexingType() == ArrayWithDouble) { > for (unsigned i = butterfly->publicLength(); i-- > newLength;) >- butterfly->contiguousDouble().at(i) = PNaN; >+ butterfly->contiguousDouble().at(this, i) = PNaN; > } else { > for (unsigned i = butterfly->publicLength(); i-- > newLength;) >- butterfly->contiguous().at(i).clear(); >+ butterfly->contiguous().at(this, i).clear(); > } > butterfly->setPublicLength(newLength); > return true; >@@ -637,8 +637,11 @@ JSValue JSArray::pop(ExecState* exec) > VM& vm = exec->vm(); > auto scope = DECLARE_THROW_SCOPE(vm); > >+ if (isCopyOnWrite(indexingMode())) >+ convertFromCopyOnWrite(vm); >+ > Butterfly* butterfly = this->butterfly(); >- >+ > switch (indexingType()) { > case ArrayClass: > return jsUndefined(); >@@ -657,9 +660,9 @@ JSValue JSArray::pop(ExecState* exec) > return jsUndefined(); > > RELEASE_ASSERT(length < butterfly->vectorLength()); >- JSValue value = butterfly->contiguous().at(length).get(); >+ JSValue value = butterfly->contiguous().at(this, length).get(); > if (value) { >- butterfly->contiguous().at(length).clear(); >+ butterfly->contiguous().at(this, length).clear(); > butterfly->setPublicLength(length); > return value; > } >@@ -673,9 +676,9 @@ JSValue JSArray::pop(ExecState* exec) > return jsUndefined(); > > RELEASE_ASSERT(length < butterfly->vectorLength()); >- double value = butterfly->contiguousDouble().at(length); >+ double value = butterfly->contiguousDouble().at(this, length); > if (value == value) { >- butterfly->contiguousDouble().at(length) = PNaN; >+ butterfly->contiguousDouble().at(this, length) = PNaN; > butterfly->setPublicLength(length); > return JSValue(JSValue::EncodeAsDouble, value); > } >@@ -741,12 +744,18 @@ NEVER_INLINE void JSArray::push(ExecState* exec, JSValue value) > > JSArray* JSArray::fastSlice(ExecState& exec, unsigned startIndex, unsigned count) > { >- auto arrayType = indexingType(); >+ VM& vm = exec.vm(); >+ auto arrayType = indexingMode(); > switch (arrayType) { >+ case CopyOnWriteArrayWithInt32: >+ case CopyOnWriteArrayWithDouble: >+ case CopyOnWriteArrayWithContiguous: >+ convertFromCopyOnWrite(vm); >+ arrayType = indexingMode(); >+ FALLTHROUGH; > case ArrayWithDouble: > case ArrayWithInt32: > case ArrayWithContiguous: { >- VM& vm = exec.vm(); > if (count >= MIN_SPARSE_ARRAY_INDEX || structure(vm)->holesMustForwardToPrototype(vm, this)) > return nullptr; > >@@ -888,6 +897,9 @@ bool JSArray::shiftCountWithAnyIndexingType(ExecState* exec, unsigned& startInde > VM& vm = exec->vm(); > RELEASE_ASSERT(count > 0); > >+ if (isCopyOnWrite(indexingMode())) >+ convertFromCopyOnWrite(vm); >+ > Butterfly* butterfly = this->butterfly(); > > switch (indexingType()) { >@@ -915,12 +927,12 @@ bool JSArray::shiftCountWithAnyIndexingType(ExecState* exec, unsigned& startInde > unsigned end = oldLength - count; > if (this->structure(vm)->holesMustForwardToPrototype(vm, this)) { > for (unsigned i = startIndex; i < end; ++i) { >- JSValue v = butterfly->contiguous().at(i + count).get(); >+ JSValue v = butterfly->contiguous().at(this, i + count).get(); > if (UNLIKELY(!v)) { > startIndex = i; > return shiftCountWithArrayStorage(vm, startIndex, count, ensureArrayStorage(vm)); > } >- butterfly->contiguous().at(i).setWithoutWriteBarrier(v); >+ butterfly->contiguous().at(this, i).setWithoutWriteBarrier(v); > } > } else { > memmove(butterfly->contiguous().data() + startIndex, >@@ -929,7 +941,7 @@ bool JSArray::shiftCountWithAnyIndexingType(ExecState* exec, unsigned& startInde > } > > for (unsigned i = end; i < oldLength; ++i) >- butterfly->contiguous().at(i).clear(); >+ butterfly->contiguous().at(this, i).clear(); > > butterfly->setPublicLength(oldLength - count); > >@@ -956,12 +968,12 @@ bool JSArray::shiftCountWithAnyIndexingType(ExecState* exec, unsigned& startInde > unsigned end = oldLength - count; > if (this->structure(vm)->holesMustForwardToPrototype(vm, this)) { > for (unsigned i = startIndex; i < end; ++i) { >- double v = butterfly->contiguousDouble().at(i + count); >+ double v = butterfly->contiguousDouble().at(this, i + count); > if (UNLIKELY(v != v)) { > startIndex = i; > return shiftCountWithArrayStorage(vm, startIndex, count, ensureArrayStorage(vm)); > } >- butterfly->contiguousDouble().at(i) = v; >+ butterfly->contiguousDouble().at(this, i) = v; > } > } else { > memmove(butterfly->contiguousDouble().data() + startIndex, >@@ -969,7 +981,7 @@ bool JSArray::shiftCountWithAnyIndexingType(ExecState* exec, unsigned& startInde > sizeof(JSValue) * (end - startIndex)); > } > for (unsigned i = end; i < oldLength; ++i) >- butterfly->contiguousDouble().at(i) = PNaN; >+ butterfly->contiguousDouble().at(this, i) = PNaN; > > butterfly->setPublicLength(oldLength - count); > return true; >@@ -1044,6 +1056,9 @@ bool JSArray::unshiftCountWithAnyIndexingType(ExecState* exec, unsigned startInd > VM& vm = exec->vm(); > auto scope = DECLARE_THROW_SCOPE(vm); > >+ if (isCopyOnWrite(indexingMode())) >+ convertFromCopyOnWrite(vm); >+ > Butterfly* butterfly = this->butterfly(); > > switch (indexingType()) { >@@ -1075,7 +1090,7 @@ bool JSArray::unshiftCountWithAnyIndexingType(ExecState* exec, unsigned startInd > // We have to check for holes before we start moving things around so that we don't get halfway > // through shifting and then realize we should have been in ArrayStorage mode. > for (unsigned i = oldLength; i-- > startIndex;) { >- JSValue v = butterfly->contiguous().at(i).get(); >+ JSValue v = butterfly->contiguous().at(this, i).get(); > if (UNLIKELY(!v)) { > scope.release(); > return unshiftCountWithArrayStorage(exec, startIndex, count, ensureArrayStorage(vm)); >@@ -1083,9 +1098,9 @@ bool JSArray::unshiftCountWithAnyIndexingType(ExecState* exec, unsigned startInd > } > > for (unsigned i = oldLength; i-- > startIndex;) { >- JSValue v = butterfly->contiguous().at(i).get(); >+ JSValue v = butterfly->contiguous().at(this, i).get(); > ASSERT(v); >- butterfly->contiguous().at(i + count).setWithoutWriteBarrier(v); >+ butterfly->contiguous().at(this, i + count).setWithoutWriteBarrier(v); > } > > // Our memmoving of values around in the array could have concealed some of them from >@@ -1122,7 +1137,7 @@ bool JSArray::unshiftCountWithAnyIndexingType(ExecState* exec, unsigned startInd > // We have to check for holes before we start moving things around so that we don't get halfway > // through shifting and then realize we should have been in ArrayStorage mode. > for (unsigned i = oldLength; i-- > startIndex;) { >- double v = butterfly->contiguousDouble().at(i); >+ double v = butterfly->contiguousDouble().at(this, i); > if (UNLIKELY(v != v)) { > scope.release(); > return unshiftCountWithArrayStorage(exec, startIndex, count, ensureArrayStorage(vm)); >@@ -1130,9 +1145,9 @@ bool JSArray::unshiftCountWithAnyIndexingType(ExecState* exec, unsigned startInd > } > > for (unsigned i = oldLength; i-- > startIndex;) { >- double v = butterfly->contiguousDouble().at(i); >+ double v = butterfly->contiguousDouble().at(this, i); > ASSERT(v == v); >- butterfly->contiguousDouble().at(i + count) = v; >+ butterfly->contiguousDouble().at(this, i + count) = v; > } > > // NOTE: we're leaving being garbage in the part of the array that we shifted out >@@ -1183,7 +1198,7 @@ void JSArray::fillArgList(ExecState* exec, MarkedArgumentBuffer& args) > vector = 0; > vectorEnd = 0; > for (; i < butterfly->publicLength(); ++i) { >- double v = butterfly->contiguousDouble().at(i); >+ double v = butterfly->contiguousDouble().at(this, i); > if (v != v) > break; > args.append(JSValue(JSValue::EncodeAsDouble, v)); >@@ -1256,7 +1271,7 @@ void JSArray::copyToArguments(ExecState* exec, VirtualRegister firstElementDest, > vectorEnd = 0; > for (; i < butterfly->publicLength(); ++i) { > ASSERT(i < butterfly->vectorLength()); >- double v = butterfly->contiguousDouble().at(i); >+ double v = butterfly->contiguousDouble().at(this, i); > if (v != v) > break; > exec->r(firstElementDest + i - offset) = JSValue(JSValue::EncodeAsDouble, v); >diff --git a/Source/JavaScriptCore/runtime/JSArrayInlines.h b/Source/JavaScriptCore/runtime/JSArrayInlines.h >index 032579e9fc355c27d9ce0e0ed7ca3c89aa399dbd..0299c839cf25fa9b40bf1c753b4ce52487d53d0a 100644 >--- a/Source/JavaScriptCore/runtime/JSArrayInlines.h >+++ b/Source/JavaScriptCore/runtime/JSArrayInlines.h >@@ -90,7 +90,7 @@ ALWAYS_INLINE void JSArray::pushInline(ExecState* exec, JSValue value) > > Butterfly* butterfly = this->butterfly(); > >- switch (indexingType()) { >+ switch (indexingMode()) { > case ArrayClass: { > createInitialUndecided(vm, 0); > FALLTHROUGH; >@@ -114,7 +114,7 @@ ALWAYS_INLINE void JSArray::pushInline(ExecState* exec, JSValue value) > unsigned length = butterfly->publicLength(); > ASSERT(length <= butterfly->vectorLength()); > if (length < butterfly->vectorLength()) { >- butterfly->contiguousInt32().at(length).setWithoutWriteBarrier(value); >+ butterfly->contiguousInt32().at(this, length).setWithoutWriteBarrier(value); > butterfly->setPublicLength(length + 1); > return; > } >@@ -135,7 +135,7 @@ ALWAYS_INLINE void JSArray::pushInline(ExecState* exec, JSValue value) > unsigned length = butterfly->publicLength(); > ASSERT(length <= butterfly->vectorLength()); > if (length < butterfly->vectorLength()) { >- butterfly->contiguous().at(length).set(vm, this, value); >+ butterfly->contiguous().at(this, length).set(vm, this, value); > butterfly->setPublicLength(length + 1); > return; > } >@@ -170,7 +170,7 @@ ALWAYS_INLINE void JSArray::pushInline(ExecState* exec, JSValue value) > unsigned length = butterfly->publicLength(); > ASSERT(length <= butterfly->vectorLength()); > if (length < butterfly->vectorLength()) { >- butterfly->contiguousDouble().at(length) = valueAsDouble; >+ butterfly->contiguousDouble().at(this, length) = valueAsDouble; > butterfly->setPublicLength(length + 1); > return; > } >@@ -227,8 +227,13 @@ ALWAYS_INLINE void JSArray::pushInline(ExecState* exec, JSValue value) > return; > } > >- default: >- RELEASE_ASSERT_NOT_REACHED(); >+ default: { >+ RELEASE_ASSERT(isCopyOnWrite(indexingMode())); >+ convertFromCopyOnWrite(vm); >+ scope.release(); >+ // Reloop. >+ return pushInline(exec, value); >+ } > } > } > >diff --git a/Source/JavaScriptCore/runtime/JSCell.h b/Source/JavaScriptCore/runtime/JSCell.h >index f8d5ac955f1b65ea2897ea88471bd106ae016741..4b8ae58adf21e5cc0abcc958268f784f4503f9ce 100644 >--- a/Source/JavaScriptCore/runtime/JSCell.h >+++ b/Source/JavaScriptCore/runtime/JSCell.h >@@ -130,6 +130,7 @@ public: > > JSType type() const; > IndexingType indexingTypeAndMisc() const; >+ IndexingType indexingMode() const; > IndexingType indexingType() const; > StructureID structureID() const { return m_structureID; } > Structure* structure() const; >diff --git a/Source/JavaScriptCore/runtime/JSCellInlines.h b/Source/JavaScriptCore/runtime/JSCellInlines.h >index 8028b89fa0fef8b80db5ba6b5f94ba8bb597a429..8f815c62bf62e44e2c5829cb645f14c257dc0f3e 100644 >--- a/Source/JavaScriptCore/runtime/JSCellInlines.h >+++ b/Source/JavaScriptCore/runtime/JSCellInlines.h >@@ -48,7 +48,7 @@ inline JSCell::JSCell(CreatingEarlyCellTag) > > inline JSCell::JSCell(VM&, Structure* structure) > : m_structureID(structure->id()) >- , m_indexingTypeAndMisc(structure->indexingTypeIncludingHistory()) >+ , m_indexingTypeAndMisc(structure->indexingModeIncludingHistory()) > , m_type(structure->typeInfo().type()) > , m_flags(structure->typeInfo().inlineTypeFlags()) > , m_cellState(CellState::DefinitelyWhite) >@@ -78,7 +78,7 @@ inline void JSCell::finishCreation(VM& vm, Structure* structure, CreatingEarlyCe > if (structure) { > #endif > m_structureID = structure->id(); >- m_indexingTypeAndMisc = structure->indexingTypeIncludingHistory(); >+ m_indexingTypeAndMisc = structure->indexingModeIncludingHistory(); > m_type = structure->typeInfo().type(); > m_flags = structure->typeInfo().inlineTypeFlags(); > #if ENABLE(GC_VALIDATION) >@@ -101,6 +101,11 @@ inline IndexingType JSCell::indexingTypeAndMisc() const > } > > inline IndexingType JSCell::indexingType() const >+{ >+ return indexingTypeAndMisc() & AllWritableArrayTypes; >+} >+ >+inline IndexingType JSCell::indexingMode() const > { > return indexingTypeAndMisc() & AllArrayTypes; > } >@@ -232,12 +237,12 @@ ALWAYS_INLINE void JSCell::setStructure(VM& vm, Structure* structure) > m_structureID = structure->id(); > m_flags = TypeInfo::mergeInlineTypeFlags(structure->typeInfo().inlineTypeFlags(), m_flags); > m_type = structure->typeInfo().type(); >- IndexingType newIndexingType = structure->indexingTypeIncludingHistory(); >+ IndexingType newIndexingType = structure->indexingModeIncludingHistory(); > if (m_indexingTypeAndMisc != newIndexingType) { > ASSERT(!(newIndexingType & ~AllArrayTypesAndHistory)); > for (;;) { > IndexingType oldValue = m_indexingTypeAndMisc; >- IndexingType newValue = (oldValue & ~AllArrayTypesAndHistory) | structure->indexingTypeIncludingHistory(); >+ IndexingType newValue = (oldValue & ~AllArrayTypesAndHistory) | structure->indexingModeIncludingHistory(); > if (WTF::atomicCompareExchangeWeakRelaxed(&m_indexingTypeAndMisc, oldValue, newValue)) > break; > } >diff --git a/Source/JavaScriptCore/runtime/JSFixedArray.h b/Source/JavaScriptCore/runtime/JSFixedArray.h >index c36f85661c186aad8e8c865c174fd668e9751f4d..1586133051c068c36470fe8c9613bd0b2158b867 100644 >--- a/Source/JavaScriptCore/runtime/JSFixedArray.h >+++ b/Source/JavaScriptCore/runtime/JSFixedArray.h >@@ -81,7 +81,7 @@ public: > > if (indexingType == ContiguousShape || indexingType == Int32Shape) { > for (unsigned i = 0; i < length; i++) { >- JSValue value = array->butterfly()->contiguous().at(i).get(); >+ JSValue value = array->butterfly()->contiguous().at(array, i).get(); > value = !!value ? value : jsUndefined(); > result->buffer()[i].set(vm, result, value); > } >@@ -90,7 +90,7 @@ public: > > if (indexingType == DoubleShape) { > for (unsigned i = 0; i < length; i++) { >- double d = array->butterfly()->contiguousDouble().at(i); >+ double d = array->butterfly()->contiguousDouble().at(array, i); > JSValue value = std::isnan(d) ? jsUndefined() : JSValue(JSValue::EncodeAsDouble, d); > result->buffer()[i].set(vm, result, value); > } >diff --git a/Source/JavaScriptCore/runtime/JSGlobalObject.cpp b/Source/JavaScriptCore/runtime/JSGlobalObject.cpp >index 95ed638316653c6c60329370463218116787f3ba..d46737458093e8a51b1118e6fdf89fc64f728a95 100644 >--- a/Source/JavaScriptCore/runtime/JSGlobalObject.cpp >+++ b/Source/JavaScriptCore/runtime/JSGlobalObject.cpp >@@ -582,13 +582,16 @@ void JSGlobalObject::init(VM& vm) > #endif > m_arrayPrototype.set(vm, this, ArrayPrototype::create(vm, this, ArrayPrototype::createStructure(vm, this, m_objectPrototype.get()))); > >- m_originalArrayStructureForIndexingShape[UndecidedShape >> IndexingShapeShift].set(vm, this, JSArray::createStructure(vm, this, m_arrayPrototype.get(), ArrayWithUndecided)); >- m_originalArrayStructureForIndexingShape[Int32Shape >> IndexingShapeShift].set(vm, this, JSArray::createStructure(vm, this, m_arrayPrototype.get(), ArrayWithInt32)); >- m_originalArrayStructureForIndexingShape[DoubleShape >> IndexingShapeShift].set(vm, this, JSArray::createStructure(vm, this, m_arrayPrototype.get(), ArrayWithDouble)); >- m_originalArrayStructureForIndexingShape[ContiguousShape >> IndexingShapeShift].set(vm, this, JSArray::createStructure(vm, this, m_arrayPrototype.get(), ArrayWithContiguous)); >- m_originalArrayStructureForIndexingShape[ArrayStorageShape >> IndexingShapeShift].set(vm, this, JSArray::createStructure(vm, this, m_arrayPrototype.get(), ArrayWithArrayStorage)); >- m_originalArrayStructureForIndexingShape[SlowPutArrayStorageShape >> IndexingShapeShift].set(vm, this, JSArray::createStructure(vm, this, m_arrayPrototype.get(), ArrayWithSlowPutArrayStorage)); >- for (unsigned i = 0; i < NumberOfIndexingShapes; ++i) >+ m_originalArrayStructureForIndexingShape[arrayIndexFromIndexingType(UndecidedShape)].set(vm, this, JSArray::createStructure(vm, this, m_arrayPrototype.get(), ArrayWithUndecided)); >+ m_originalArrayStructureForIndexingShape[arrayIndexFromIndexingType(Int32Shape)].set(vm, this, JSArray::createStructure(vm, this, m_arrayPrototype.get(), ArrayWithInt32)); >+ m_originalArrayStructureForIndexingShape[arrayIndexFromIndexingType(DoubleShape)].set(vm, this, JSArray::createStructure(vm, this, m_arrayPrototype.get(), ArrayWithDouble)); >+ m_originalArrayStructureForIndexingShape[arrayIndexFromIndexingType(ContiguousShape)].set(vm, this, JSArray::createStructure(vm, this, m_arrayPrototype.get(), ArrayWithContiguous)); >+ m_originalArrayStructureForIndexingShape[arrayIndexFromIndexingType(ArrayStorageShape)].set(vm, this, JSArray::createStructure(vm, this, m_arrayPrototype.get(), ArrayWithArrayStorage)); >+ m_originalArrayStructureForIndexingShape[arrayIndexFromIndexingType(SlowPutArrayStorageShape)].set(vm, this, JSArray::createStructure(vm, this, m_arrayPrototype.get(), ArrayWithSlowPutArrayStorage)); >+ m_originalArrayStructureForIndexingShape[arrayIndexFromIndexingType(CopyOnWriteArrayWithInt32)].set(vm, this, JSArray::createStructure(vm, this, m_arrayPrototype.get(), CopyOnWriteArrayWithInt32)); >+ m_originalArrayStructureForIndexingShape[arrayIndexFromIndexingType(CopyOnWriteArrayWithDouble)].set(vm, this, JSArray::createStructure(vm, this, m_arrayPrototype.get(), CopyOnWriteArrayWithDouble)); >+ m_originalArrayStructureForIndexingShape[arrayIndexFromIndexingType(CopyOnWriteArrayWithContiguous)].set(vm, this, JSArray::createStructure(vm, this, m_arrayPrototype.get(), CopyOnWriteArrayWithContiguous)); >+ for (unsigned i = 0; i < NumberOfArrayIndexingModes; ++i) > m_arrayStructureForIndexingShapeDuringAllocation[i] = m_originalArrayStructureForIndexingShape[i]; > > m_regExpPrototype.set(vm, this, RegExpPrototype::create(vm, this, RegExpPrototype::createStructure(vm, this, m_objectPrototype.get()))); >@@ -1271,7 +1274,7 @@ void JSGlobalObject::haveABadTime(VM& vm) > > // Make sure that all JSArray allocations that load the appropriate structure from > // this object now load a structure that uses SlowPut. >- for (unsigned i = 0; i < NumberOfIndexingShapes; ++i) >+ for (unsigned i = 0; i < NumberOfArrayIndexingModes; ++i) > m_arrayStructureForIndexingShapeDuringAllocation[i].set(vm, this, originalArrayStructureForIndexingType(ArrayWithSlowPutArrayStorage)); > > // Same for any special array structures. >@@ -1381,9 +1384,9 @@ void JSGlobalObject::visitChildren(JSCell* cell, SlotVisitor& visitor) > visitor.append(thisObject->m_scopedArgumentsStructure); > visitor.append(thisObject->m_clonedArgumentsStructure); > visitor.append(thisObject->m_objectStructureForObjectConstructor); >- for (unsigned i = 0; i < NumberOfIndexingShapes; ++i) >+ for (unsigned i = 0; i < NumberOfArrayIndexingModes; ++i) > visitor.append(thisObject->m_originalArrayStructureForIndexingShape[i]); >- for (unsigned i = 0; i < NumberOfIndexingShapes; ++i) >+ for (unsigned i = 0; i < NumberOfArrayIndexingModes; ++i) > visitor.append(thisObject->m_arrayStructureForIndexingShapeDuringAllocation[i]); > thisObject->m_callbackConstructorStructure.visit(visitor); > thisObject->m_callbackFunctionStructure.visit(visitor); >diff --git a/Source/JavaScriptCore/runtime/JSGlobalObject.h b/Source/JavaScriptCore/runtime/JSGlobalObject.h >index 759b87070b24a9e01a2a8361730d9bf232428238..21e00f5f2831ac5a7a84ff9bdf4cf96283b1b3d4 100644 >--- a/Source/JavaScriptCore/runtime/JSGlobalObject.h >+++ b/Source/JavaScriptCore/runtime/JSGlobalObject.h >@@ -315,10 +315,10 @@ public: > WriteBarrier<Structure> m_objectStructureForObjectConstructor; > > // Lists the actual structures used for having these particular indexing shapes. >- WriteBarrier<Structure> m_originalArrayStructureForIndexingShape[NumberOfIndexingShapes]; >+ WriteBarrier<Structure> m_originalArrayStructureForIndexingShape[NumberOfArrayIndexingModes]; > // Lists the structures we should use during allocation for these particular indexing shapes. > // These structures will differ from the originals list above when we are having a bad time. >- WriteBarrier<Structure> m_arrayStructureForIndexingShapeDuringAllocation[NumberOfIndexingShapes]; >+ WriteBarrier<Structure> m_arrayStructureForIndexingShapeDuringAllocation[NumberOfArrayIndexingModes]; > > LazyProperty<JSGlobalObject, Structure> m_callbackConstructorStructure; > LazyProperty<JSGlobalObject, Structure> m_callbackFunctionStructure; >@@ -613,12 +613,12 @@ public: > Structure* originalArrayStructureForIndexingType(IndexingType indexingType) const > { > ASSERT(indexingType & IsArray); >- return m_originalArrayStructureForIndexingShape[(indexingType & IndexingShapeMask) >> IndexingShapeShift].get(); >+ return m_originalArrayStructureForIndexingShape[arrayIndexFromIndexingType(indexingType)].get(); > } > Structure* arrayStructureForIndexingTypeDuringAllocation(IndexingType indexingType) const > { > ASSERT(indexingType & IsArray); >- return m_arrayStructureForIndexingShapeDuringAllocation[(indexingType & IndexingShapeMask) >> IndexingShapeShift].get(); >+ return m_arrayStructureForIndexingShapeDuringAllocation[arrayIndexFromIndexingType(indexingType)].get(); > } > Structure* arrayStructureForIndexingTypeDuringAllocation(ExecState* exec, IndexingType indexingType, JSValue newTarget) const > { >@@ -631,7 +631,7 @@ public: > > bool isOriginalArrayStructure(Structure* structure) > { >- return originalArrayStructureForIndexingType(structure->indexingType() | IsArray) == structure; >+ return originalArrayStructureForIndexingType(structure->indexingMode() | IsArray) == structure; > } > > Structure* booleanObjectStructure() const { return m_booleanObjectStructure.get(); } >diff --git a/Source/JavaScriptCore/runtime/JSImmutableButterfly.cpp b/Source/JavaScriptCore/runtime/JSImmutableButterfly.cpp >new file mode 100644 >index 0000000000000000000000000000000000000000..6b0c9e17529c45d93e4b23d375df071b89e5fb85 >--- /dev/null >+++ b/Source/JavaScriptCore/runtime/JSImmutableButterfly.cpp >@@ -0,0 +1,55 @@ >+/* >+ * Copyright (C) 2018 Apple Inc. All rights reserved. >+ * >+ * Redistribution and use in source and binary forms, with or without >+ * modification, are permitted provided that the following conditions >+ * are met: >+ * 1. Redistributions of source code must retain the above copyright >+ * notice, this list of conditions and the following disclaimer. >+ * 2. Redistributions in binary form must reproduce the above copyright >+ * notice, this list of conditions and the following disclaimer in the >+ * documentation and/or other materials provided with the distribution. >+ * >+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY >+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE >+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR >+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR >+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, >+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, >+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR >+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY >+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT >+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE >+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. >+ */ >+ >+#include "config.h" >+#include "JSImmutableButterfly.h" >+ >+namespace JSC { >+ >+const ClassInfo JSImmutableButterfly::s_info = { "Immutable Butterfly", nullptr, nullptr, nullptr, CREATE_METHOD_TABLE(JSImmutableButterfly) }; >+ >+void JSImmutableButterfly::visitChildren(JSCell* cell, SlotVisitor& visitor) >+{ >+ Base::visitChildren(cell, visitor); >+ if (!hasContiguous(cell->indexingType())) { >+ ASSERT(hasDouble(cell->indexingType()) || hasInt32(cell->indexingType())); >+ return; >+ } >+ >+ Butterfly* butterfly = jsCast<JSImmutableButterfly*>(cell)->toButterfly(); >+ visitor.appendValuesHidden(butterfly->contiguous().data(), butterfly->publicLength()); >+} >+ >+void JSImmutableButterfly::copyToArguments(ExecState* exec, VirtualRegister firstElementDest, unsigned offset, unsigned length) >+{ >+ for (unsigned i = 0; i < length; ++i) { >+ if ((i + offset) < publicLength()) >+ exec->r(firstElementDest + i) = get(i + offset); >+ else >+ exec->r(firstElementDest + i) = jsUndefined(); >+ } >+} >+ >+} // namespace JSC >diff --git a/Source/JavaScriptCore/runtime/JSImmutableButterfly.h b/Source/JavaScriptCore/runtime/JSImmutableButterfly.h >new file mode 100644 >index 0000000000000000000000000000000000000000..04f5714072145d6932ce224fc7d121ab228e4455 >--- /dev/null >+++ b/Source/JavaScriptCore/runtime/JSImmutableButterfly.h >@@ -0,0 +1,121 @@ >+/* >+ * Copyright (C) 2018 Apple Inc. All rights reserved. >+ * >+ * Redistribution and use in source and binary forms, with or without >+ * modification, are permitted provided that the following conditions >+ * are met: >+ * 1. Redistributions of source code must retain the above copyright >+ * notice, this list of conditions and the following disclaimer. >+ * 2. Redistributions in binary form must reproduce the above copyright >+ * notice, this list of conditions and the following disclaimer in the >+ * documentation and/or other materials provided with the distribution. >+ * >+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY >+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE >+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR >+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR >+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, >+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, >+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR >+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY >+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT >+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE >+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. >+ */ >+ >+#pragma once >+ >+#include "IndexingHeader.h" >+#include "JSCell.h" >+ >+namespace JSC { >+ >+class JSImmutableButterfly : public JSCell { >+ using Base = JSCell; >+ >+public: >+ static const unsigned StructureFlags = Base::StructureFlags | StructureIsImmortal; >+ >+ DECLARE_INFO; >+ >+ static Structure* createStructure(VM& vm, JSGlobalObject* globalObject, JSValue prototype, IndexingType indexingType) >+ { >+ return Structure::create(vm, globalObject, prototype, TypeInfo(JSImmutableButterflyType, StructureFlags), info(), indexingType); >+ } >+ >+ ALWAYS_INLINE static JSImmutableButterfly* tryCreate(VM& vm, Structure* structure, unsigned size) >+ { >+ Checked<size_t, RecordOverflow> checkedAllocationSize = allocationSize(size); >+ if (UNLIKELY(checkedAllocationSize.hasOverflowed())) >+ return nullptr; >+ >+ void* buffer = tryAllocateCell<JSImmutableButterfly>(vm.heap, checkedAllocationSize.unsafeGet()); >+ if (UNLIKELY(!buffer)) >+ return nullptr; >+ JSImmutableButterfly* result = new (NotNull, buffer) JSImmutableButterfly(vm, structure, size); >+ result->finishCreation(vm); >+ return result; >+ } >+ >+ static JSImmutableButterfly* create(VM& vm, IndexingType indexingType, unsigned length) >+ { >+ auto* array = tryCreate(vm, vm.immutableButterflyStructures[arrayIndexFromIndexingType(indexingType) - NumberOfIndexingShapes].get(), length); >+ RELEASE_ASSERT(array); >+ return array; >+ } >+ >+ unsigned publicLength() const { return m_header.publicLength(); } >+ unsigned vectorLength() const { return m_header.vectorLength(); } >+ unsigned length() const { return m_header.publicLength(); } >+ >+ Butterfly* toButterfly() const { return reinterpret_cast<Butterfly*>(bitwise_cast<char*>(this) + sizeof(JSImmutableButterfly)); } >+ static JSImmutableButterfly* fromButterfly(Butterfly* butterfly) { return reinterpret_cast<JSImmutableButterfly*>(reinterpret_cast<char*>(butterfly) - sizeof(JSImmutableButterfly)); } >+ >+ JSValue get(unsigned index) const >+ { >+ if (!hasDouble(indexingMode())) >+ return toButterfly()->contiguous().at(this, index).get(); >+ double value = toButterfly()->contiguousDouble().at(this, index); >+ // Holes are not supported yet. >+ ASSERT(!std::isnan(value)); >+ return jsNumber(value); >+ } >+ >+ static void visitChildren(JSCell*, SlotVisitor&); >+ >+ void copyToArguments(ExecState*, VirtualRegister firstElementDest, unsigned offset, unsigned length); >+ >+ template<typename> >+ static CompleteSubspace* subspaceFor(VM& vm) >+ { >+ // We allocate out of the JSValue gigacage as other code expects all butterflies to live there. >+ return &vm.jsValueGigacageAuxiliarySpace; >+ } >+ >+ // Only call this if you just allocated this butterfly. >+ void setIndex(VM& vm, unsigned index, JSValue value) >+ { >+ if (hasDouble(indexingType())) >+ toButterfly()->contiguousDouble().atUnsafe(index) = value.asNumber(); >+ else >+ toButterfly()->contiguous().atUnsafe(index).set(vm, this, value); >+ } >+ >+private: >+ >+ static Checked<size_t, RecordOverflow> allocationSize(Checked<size_t, RecordOverflow> numItems) >+ { >+ return sizeof(JSImmutableButterfly) + numItems * sizeof(WriteBarrier<Unknown>); >+ } >+ >+ JSImmutableButterfly(VM& vm, Structure* structure, unsigned length) >+ : Base(vm, structure) >+ { >+ m_header.setVectorLength(length); >+ m_header.setPublicLength(length); >+ } >+ >+ IndexingHeader m_header; >+}; >+ >+} // namespace JSC >diff --git a/Source/JavaScriptCore/runtime/JSObject.cpp b/Source/JavaScriptCore/runtime/JSObject.cpp >index 42c888e6c494e6d4973e6aac36931c83bc9ac90d..68e66483422a67ab830515694ba058c59f569bc9 100644 >--- a/Source/JavaScriptCore/runtime/JSObject.cpp >+++ b/Source/JavaScriptCore/runtime/JSObject.cpp >@@ -37,6 +37,7 @@ > #include "JSCustomGetterSetterFunction.h" > #include "JSFunction.h" > #include "JSGlobalObject.h" >+#include "JSImmutableButterfly.h" > #include "Lookup.h" > #include "NativeErrorConstructor.h" > #include "Nodes.h" >@@ -97,7 +98,12 @@ ALWAYS_INLINE void JSObject::markAuxiliaryAndVisitOutOfLineProperties(SlotVisito > > if (!butterfly) > return; >- >+ >+ if (isCopyOnWrite(structure->indexingMode())) { >+ visitor.append(bitwise_cast<WriteBarrier<JSCell>>(JSImmutableButterfly::fromButterfly(butterfly))); >+ return; >+ } >+ > bool hasIndexingHeader = structure->hasIndexingHeader(this); > size_t preCapacity; > if (hasIndexingHeader) >@@ -132,16 +138,11 @@ ALWAYS_INLINE Structure* JSObject::visitButterflyImpl(SlotVisitor& visitor) > Butterfly* butterfly; > Structure* structure; > PropertyOffset lastOffset; >- >- if (visitor.mutatorIsStopped()) { >- butterfly = this->butterfly(); >- structure = this->structure(vm); >- lastOffset = structure->lastOffset(); >- >- markAuxiliaryAndVisitOutOfLineProperties(visitor, butterfly, structure, lastOffset); >- >- switch (structure->indexingType()) { >- case ALL_CONTIGUOUS_INDEXING_TYPES: >+ >+ auto visitElements = [&] (IndexingType indexingMode) { >+ switch (indexingMode) { >+ // We don't need to visit the elements for CopyOnWrite butterflies since they we marked the JSImmutableButterfly acting as out butterfly. >+ case ALL_WRITABLE_CONTIGUOUS_INDEXING_TYPES: > visitor.appendValuesHidden(butterfly->contiguous().data(), butterfly->publicLength()); > break; > case ALL_ARRAY_STORAGE_INDEXING_TYPES: >@@ -152,6 +153,16 @@ ALWAYS_INLINE Structure* JSObject::visitButterflyImpl(SlotVisitor& visitor) > default: > break; > } >+ }; >+ >+ if (visitor.mutatorIsStopped()) { >+ butterfly = this->butterfly(); >+ structure = this->structure(vm); >+ lastOffset = structure->lastOffset(); >+ >+ markAuxiliaryAndVisitOutOfLineProperties(visitor, butterfly, structure, lastOffset); >+ visitElements(structure->indexingMode()); >+ > return structure; > } > >@@ -381,10 +392,10 @@ ALWAYS_INLINE Structure* JSObject::visitButterflyImpl(SlotVisitor& visitor) > return nullptr; > structure = vm.getStructure(structureID); > lastOffset = structure->lastOffset(); >- IndexingType indexingType = structure->indexingType(); >- Dependency indexingTypeDependency = Dependency::fence(indexingType); >+ IndexingType indexingMode = structure->indexingMode(); >+ Dependency indexingModeDependency = Dependency::fence(indexingMode); > Locker<JSCellLock> locker(NoLockingNecessary); >- switch (indexingType) { >+ switch (indexingMode) { > case ALL_CONTIGUOUS_INDEXING_TYPES: > case ALL_ARRAY_STORAGE_INDEXING_TYPES: > // We need to hold this lock to protect against changes to the innards of the butterfly >@@ -396,7 +407,7 @@ ALWAYS_INLINE Structure* JSObject::visitButterflyImpl(SlotVisitor& visitor) > default: > break; > } >- butterfly = indexingTypeDependency.consume(this)->butterfly(); >+ butterfly = indexingModeDependency.consume(this)->butterfly(); > Dependency butterflyDependency = Dependency::fence(butterfly); > if (!butterfly) > return structure; >@@ -406,21 +417,8 @@ ALWAYS_INLINE Structure* JSObject::visitButterflyImpl(SlotVisitor& visitor) > return nullptr; > > markAuxiliaryAndVisitOutOfLineProperties(visitor, butterfly, structure, lastOffset); >- >- ASSERT(indexingType == structure->indexingType()); >- >- switch (indexingType) { >- case ALL_CONTIGUOUS_INDEXING_TYPES: >- visitor.appendValuesHidden(butterfly->contiguous().data(), butterfly->publicLength()); >- break; >- case ALL_ARRAY_STORAGE_INDEXING_TYPES: >- visitor.appendValuesHidden(butterfly->arrayStorage()->m_vector, butterfly->arrayStorage()->vectorLength()); >- if (butterfly->arrayStorage()->m_sparseMap) >- visitor.append(butterfly->arrayStorage()->m_sparseMap); >- break; >- default: >- break; >- } >+ ASSERT(indexingMode == structure->indexingMode()); >+ visitElements(indexingMode); > > return structure; > } >@@ -589,7 +587,7 @@ bool JSObject::getOwnPropertySlotByIndex(JSObject* thisObject, ExecState* exec, > if (i >= butterfly->vectorLength()) > return false; > >- JSValue value = butterfly->contiguous().at(i).get(); >+ JSValue value = butterfly->contiguous().at(thisObject, i).get(); > if (value) { > slot.setValue(thisObject, static_cast<unsigned>(PropertyAttribute::None), value); > return true; >@@ -603,7 +601,7 @@ bool JSObject::getOwnPropertySlotByIndex(JSObject* thisObject, ExecState* exec, > if (i >= butterfly->vectorLength()) > return false; > >- double value = butterfly->contiguousDouble().at(i); >+ double value = butterfly->contiguousDouble().at(thisObject, i); > if (value == value) { > slot.setValue(thisObject, static_cast<unsigned>(PropertyAttribute::None), JSValue(JSValue::EncodeAsDouble, value)); > return true; >@@ -833,12 +831,15 @@ bool JSObject::putByIndex(JSCell* cell, ExecState* exec, unsigned propertyName, > { > VM& vm = exec->vm(); > JSObject* thisObject = jsCast<JSObject*>(cell); >- >+ > if (propertyName > MAX_ARRAY_INDEX) { > PutPropertySlot slot(cell, shouldThrow); > return thisObject->methodTable()->put(thisObject, exec, Identifier::from(exec, propertyName), value, slot); > } >- >+ >+ if (isCopyOnWrite(thisObject->indexingMode())) >+ thisObject->convertFromCopyOnWrite(vm); >+ > switch (thisObject->indexingType()) { > case ALL_BLANK_INDEXING_TYPES: > break; >@@ -850,7 +851,7 @@ bool JSObject::putByIndex(JSCell* cell, ExecState* exec, unsigned propertyName, > } > > case ALL_INT32_INDEXING_TYPES: { >- if (!value.isInt32()) { >+ if (!value.isInt32() || isCopyOnWrite(thisObject->indexingMode())) { > thisObject->convertInt32ForValue(vm, value); > return putByIndex(cell, exec, propertyName, value, shouldThrow); > } >@@ -861,7 +862,7 @@ bool JSObject::putByIndex(JSCell* cell, ExecState* exec, unsigned propertyName, > Butterfly* butterfly = thisObject->butterfly(); > if (propertyName >= butterfly->vectorLength()) > break; >- butterfly->contiguous().at(propertyName).set(vm, thisObject, value); >+ butterfly->contiguous().at(thisObject, propertyName).set(vm, thisObject, value); > if (propertyName >= butterfly->publicLength()) > butterfly->setPublicLength(propertyName + 1); > return true; >@@ -873,6 +874,7 @@ bool JSObject::putByIndex(JSCell* cell, ExecState* exec, unsigned propertyName, > // Reloop. > return putByIndex(cell, exec, propertyName, value, shouldThrow); > } >+ > double valueAsDouble = value.asNumber(); > if (valueAsDouble != valueAsDouble) { > thisObject->convertDoubleToContiguous(vm); >@@ -882,7 +884,7 @@ bool JSObject::putByIndex(JSCell* cell, ExecState* exec, unsigned propertyName, > Butterfly* butterfly = thisObject->butterfly(); > if (propertyName >= butterfly->vectorLength()) > break; >- butterfly->contiguousDouble().at(propertyName) = valueAsDouble; >+ butterfly->contiguousDouble().at(thisObject, propertyName) = valueAsDouble; > if (propertyName >= butterfly->publicLength()) > butterfly->setPublicLength(propertyName + 1); > return true; >@@ -1050,7 +1052,7 @@ ContiguousJSValues JSObject::createInitialInt32(VM& vm, unsigned length) > DeferGC deferGC(vm.heap); > Butterfly* newButterfly = createInitialIndexedStorage(vm, length); > for (unsigned i = newButterfly->vectorLength(); i--;) >- newButterfly->contiguous().at(i).setWithoutWriteBarrier(JSValue()); >+ newButterfly->contiguous().at(this, i).setWithoutWriteBarrier(JSValue()); > StructureID oldStructureID = this->structureID(); > Structure* oldStructure = vm.getStructure(oldStructureID); > Structure* newStructure = Structure::nonPropertyTransition(vm, oldStructure, NonPropertyTransition::AllocateInt32); >@@ -1064,7 +1066,7 @@ ContiguousDoubles JSObject::createInitialDouble(VM& vm, unsigned length) > DeferGC deferGC(vm.heap); > Butterfly* newButterfly = createInitialIndexedStorage(vm, length); > for (unsigned i = newButterfly->vectorLength(); i--;) >- newButterfly->contiguousDouble().at(i) = PNaN; >+ newButterfly->contiguousDouble().at(this, i) = PNaN; > StructureID oldStructureID = this->structureID(); > Structure* oldStructure = vm.getStructure(oldStructureID); > Structure* newStructure = Structure::nonPropertyTransition(vm, oldStructure, NonPropertyTransition::AllocateDouble); >@@ -1078,7 +1080,7 @@ ContiguousJSValues JSObject::createInitialContiguous(VM& vm, unsigned length) > DeferGC deferGC(vm.heap); > Butterfly* newButterfly = createInitialIndexedStorage(vm, length); > for (unsigned i = newButterfly->vectorLength(); i--;) >- newButterfly->contiguous().at(i).setWithoutWriteBarrier(JSValue()); >+ newButterfly->contiguous().at(this, i).setWithoutWriteBarrier(JSValue()); > StructureID oldStructureID = this->structureID(); > Structure* oldStructure = vm.getStructure(oldStructureID); > Structure* newStructure = Structure::nonPropertyTransition(vm, oldStructure, NonPropertyTransition::AllocateContiguous); >@@ -1134,7 +1136,7 @@ ContiguousJSValues JSObject::convertUndecidedToInt32(VM& vm) > > Butterfly* butterfly = this->butterfly(); > for (unsigned i = butterfly->vectorLength(); i--;) >- butterfly->contiguous().at(i).setWithoutWriteBarrier(JSValue()); >+ butterfly->contiguous().at(this, i).setWithoutWriteBarrier(JSValue()); > > setStructure(vm, Structure::nonPropertyTransition(vm, structure(vm), NonPropertyTransition::AllocateInt32)); > return m_butterfly->contiguousInt32(); >@@ -1146,7 +1148,7 @@ ContiguousDoubles JSObject::convertUndecidedToDouble(VM& vm) > > Butterfly* butterfly = m_butterfly.get(); > for (unsigned i = butterfly->vectorLength(); i--;) >- butterfly->contiguousDouble().at(i) = PNaN; >+ butterfly->contiguousDouble().at(this, i) = PNaN; > > setStructure(vm, Structure::nonPropertyTransition(vm, structure(vm), NonPropertyTransition::AllocateDouble)); > return m_butterfly->contiguousDouble(); >@@ -1158,7 +1160,7 @@ ContiguousJSValues JSObject::convertUndecidedToContiguous(VM& vm) > > Butterfly* butterfly = m_butterfly.get(); > for (unsigned i = butterfly->vectorLength(); i--;) >- butterfly->contiguous().at(i).setWithoutWriteBarrier(JSValue()); >+ butterfly->contiguous().at(this, i).setWithoutWriteBarrier(JSValue()); > > WTF::storeStoreFence(); > setStructure(vm, Structure::nonPropertyTransition(vm, structure(vm), NonPropertyTransition::AllocateContiguous)); >@@ -1220,7 +1222,7 @@ ContiguousDoubles JSObject::convertInt32ToDouble(VM& vm) > > Butterfly* butterfly = m_butterfly.get(); > for (unsigned i = butterfly->vectorLength(); i--;) { >- WriteBarrier<Unknown>* current = &butterfly->contiguous().at(i); >+ WriteBarrier<Unknown>* current = &butterfly->contiguous().at(this, i); > double* currentAsDouble = bitwise_cast<double*>(current); > JSValue v = current->get(); > // NOTE: Since this may be used during initialization, v could be garbage. If it's garbage, >@@ -1253,7 +1255,7 @@ ArrayStorage* JSObject::convertInt32ToArrayStorage(VM& vm, NonPropertyTransition > ArrayStorage* newStorage = constructConvertedArrayStorageWithoutCopyingElements(vm, vectorLength); > Butterfly* butterfly = m_butterfly.get(); > for (unsigned i = 0; i < vectorLength; i++) { >- JSValue v = butterfly->contiguous().at(i).get(); >+ JSValue v = butterfly->contiguous().at(this, i).get(); > newStorage->m_vector[i].setWithoutWriteBarrier(v); > if (v) > newStorage->m_numValuesInVector++; >@@ -1278,7 +1280,7 @@ ContiguousJSValues JSObject::convertDoubleToContiguous(VM& vm) > > Butterfly* butterfly = m_butterfly.get(); > for (unsigned i = butterfly->vectorLength(); i--;) { >- double* current = &butterfly->contiguousDouble().at(i); >+ double* current = &butterfly->contiguousDouble().at(this, i); > WriteBarrier<Unknown>* currentAsValue = bitwise_cast<WriteBarrier<Unknown>*>(current); > double value = *current; > if (value != value) { >@@ -1303,7 +1305,7 @@ ArrayStorage* JSObject::convertDoubleToArrayStorage(VM& vm, NonPropertyTransitio > ArrayStorage* newStorage = constructConvertedArrayStorageWithoutCopyingElements(vm, vectorLength); > Butterfly* butterfly = m_butterfly.get(); > for (unsigned i = 0; i < vectorLength; i++) { >- double value = butterfly->contiguousDouble().at(i); >+ double value = butterfly->contiguousDouble().at(this, i); > if (value != value) { > newStorage->m_vector[i].clear(); > continue; >@@ -1334,7 +1336,7 @@ ArrayStorage* JSObject::convertContiguousToArrayStorage(VM& vm, NonPropertyTrans > ArrayStorage* newStorage = constructConvertedArrayStorageWithoutCopyingElements(vm, vectorLength); > Butterfly* butterfly = m_butterfly.get(); > for (unsigned i = 0; i < vectorLength; i++) { >- JSValue v = butterfly->contiguous().at(i).get(); >+ JSValue v = butterfly->contiguous().at(this, i).get(); > newStorage->m_vector[i].setWithoutWriteBarrier(v); > if (v) > newStorage->m_numValuesInVector++; >@@ -1394,19 +1396,19 @@ void JSObject::convertUndecidedForValue(VM& vm, JSValue value) > void JSObject::createInitialForValueAndSet(VM& vm, unsigned index, JSValue value) > { > if (value.isInt32()) { >- createInitialInt32(vm, index + 1).at(index).set(vm, this, value); >+ createInitialInt32(vm, index + 1).at(this, index).set(vm, this, value); > return; > } > > if (value.isDouble()) { > double doubleValue = value.asNumber(); > if (doubleValue == doubleValue) { >- createInitialDouble(vm, index + 1).at(index) = doubleValue; >+ createInitialDouble(vm, index + 1).at(this, index) = doubleValue; > return; > } > } > >- createInitialContiguous(vm, index + 1).at(index).set(vm, this, value); >+ createInitialContiguous(vm, index + 1).at(this, index).set(vm, this, value); > } > > void JSObject::convertInt32ForValue(VM& vm, JSValue value) >@@ -1417,10 +1419,41 @@ void JSObject::convertInt32ForValue(VM& vm, JSValue value) > convertInt32ToDouble(vm); > return; > } >- >+ > convertInt32ToContiguous(vm); > } > >+void JSObject::convertFromCopyOnWrite(VM& vm) >+{ >+ ASSERT(isCopyOnWrite(indexingMode())); >+ >+ const bool hasIndexingHeader = true; >+ Butterfly* oldButterfly = butterfly(); >+ size_t propertyCapacity = 0; >+ unsigned newVectorLength = Butterfly::optimalContiguousVectorLength(propertyCapacity, std::min(oldButterfly->vectorLength() * 2, MAX_STORAGE_VECTOR_LENGTH)); >+ Butterfly* newButterfly = Butterfly::createUninitialized(vm, this, 0, propertyCapacity, hasIndexingHeader, newVectorLength * sizeof(JSValue)); >+ >+ memcpy(newButterfly->propertyStorage(), oldButterfly->propertyStorage(), oldButterfly->vectorLength() * sizeof(JSValue) + sizeof(IndexingHeader)); >+ WTF::storeStoreFence(); >+ NonPropertyTransition transition = ([&] () { >+ switch (indexingType()) { >+ case ArrayWithInt32: >+ return NonPropertyTransition::AllocateInt32; >+ case ArrayWithDouble: >+ return NonPropertyTransition::AllocateDouble; >+ case ArrayWithContiguous: >+ return NonPropertyTransition::AllocateContiguous; >+ default: >+ RELEASE_ASSERT_NOT_REACHED(); >+ return NonPropertyTransition::AllocateContiguous; >+ } >+ })(); >+ StructureID oldStructureID = structureID(); >+ Structure* newStructure = Structure::nonPropertyTransition(vm, structure(vm), transition); >+ nukeStructureAndSetButterfly(vm, oldStructureID, newButterfly); >+ setStructure(vm, newStructure); >+} >+ > void JSObject::setIndexQuicklyToUndecided(VM& vm, unsigned index, JSValue value) > { > ASSERT(index < m_butterfly->publicLength()); >@@ -1443,10 +1476,15 @@ void JSObject::convertDoubleToContiguousWhilePerformingSetIndex(VM& vm, unsigned > setIndexQuickly(vm, index, value); > } > >-ContiguousJSValues JSObject::ensureInt32Slow(VM& vm) >+ContiguousJSValues JSObject::ensureWritableInt32Slow(VM& vm) > { > ASSERT(inherits(vm, info())); >- >+ >+ if (isCopyOnWrite(indexingMode()) && hasInt32(indexingMode())) { >+ convertFromCopyOnWrite(vm); >+ return butterfly()->contiguousInt32(); >+ } >+ > if (structure(vm)->hijacksIndexingHeader()) > return ContiguousJSValues(); > >@@ -1470,10 +1508,16 @@ ContiguousJSValues JSObject::ensureInt32Slow(VM& vm) > } > } > >-ContiguousDoubles JSObject::ensureDoubleSlow(VM& vm) >+ContiguousDoubles JSObject::ensureWritableDoubleSlow(VM& vm) > { > ASSERT(inherits(vm, info())); >- >+ >+ if (isCopyOnWrite(indexingMode())) { >+ convertFromCopyOnWrite(vm); >+ if (hasDouble(indexingMode())) >+ return butterfly()->contiguousDouble(); >+ } >+ > if (structure(vm)->hijacksIndexingHeader()) > return ContiguousDoubles(); > >@@ -1499,10 +1543,16 @@ ContiguousDoubles JSObject::ensureDoubleSlow(VM& vm) > } > } > >-ContiguousJSValues JSObject::ensureContiguousSlow(VM& vm) >+ContiguousJSValues JSObject::ensureWritableContiguousSlow(VM& vm) > { > ASSERT(inherits(vm, info())); >- >+ >+ if (isCopyOnWrite(indexingMode())) { >+ convertFromCopyOnWrite(vm); >+ if ( hasContiguous(indexingMode())) >+ return butterfly()->contiguous(); >+ } >+ > if (structure(vm)->hijacksIndexingHeader()) > return ContiguousJSValues(); > >@@ -1536,6 +1586,9 @@ ArrayStorage* JSObject::ensureArrayStorageSlow(VM& vm) > > if (structure(vm)->hijacksIndexingHeader()) > return nullptr; >+ >+ if (isCopyOnWrite(indexingMode())) >+ convertFromCopyOnWrite(vm); > > switch (indexingType()) { > case ALL_BLANK_INDEXING_TYPES: >@@ -1571,6 +1624,9 @@ ArrayStorage* JSObject::ensureArrayStorageSlow(VM& vm) > > ArrayStorage* JSObject::ensureArrayStorageExistsAndEnterDictionaryIndexingMode(VM& vm) > { >+ if (isCopyOnWrite(indexingMode())) >+ convertFromCopyOnWrite(vm); >+ > switch (indexingType()) { > case ALL_BLANK_INDEXING_TYPES: { > createArrayStorage(vm, 0, 0); >@@ -1602,6 +1658,9 @@ ArrayStorage* JSObject::ensureArrayStorageExistsAndEnterDictionaryIndexingMode(V > > void JSObject::switchToSlowPutArrayStorage(VM& vm) > { >+ if (isCopyOnWrite(indexingMode())) >+ convertFromCopyOnWrite(vm); >+ > switch (indexingType()) { > case ArrayClass: > ensureArrayStorage(vm); >@@ -1876,7 +1935,7 @@ bool JSObject::deletePropertyByIndex(JSCell* cell, ExecState* exec, unsigned i) > Butterfly* butterfly = thisObject->butterfly(); > if (i >= butterfly->vectorLength()) > return true; >- butterfly->contiguous().at(i).clear(); >+ butterfly->contiguous().at(thisObject, i).clear(); > return true; > } > >@@ -1884,7 +1943,7 @@ bool JSObject::deletePropertyByIndex(JSCell* cell, ExecState* exec, unsigned i) > Butterfly* butterfly = thisObject->butterfly(); > if (i >= butterfly->vectorLength()) > return true; >- butterfly->contiguousDouble().at(i) = PNaN; >+ butterfly->contiguousDouble().at(thisObject, i) = PNaN; > return true; > } > >@@ -2185,7 +2244,7 @@ void JSObject::getOwnPropertyNames(JSObject* object, ExecState* exec, PropertyNa > Butterfly* butterfly = object->butterfly(); > unsigned usedLength = butterfly->publicLength(); > for (unsigned i = 0; i < usedLength; ++i) { >- if (!butterfly->contiguous().at(i)) >+ if (!butterfly->contiguous().at(object, i)) > continue; > propertyNames.add(i); > } >@@ -2196,7 +2255,7 @@ void JSObject::getOwnPropertyNames(JSObject* object, ExecState* exec, PropertyNa > Butterfly* butterfly = object->butterfly(); > unsigned usedLength = butterfly->publicLength(); > for (unsigned i = 0; i < usedLength; ++i) { >- double value = butterfly->contiguousDouble().at(i); >+ double value = butterfly->contiguousDouble().at(object, i); > if (value != value) > continue; > propertyNames.add(i); >@@ -2404,7 +2463,7 @@ bool JSObject::putIndexedDescriptor(ExecState* exec, SparseArrayEntry* entryInMa > > ALWAYS_INLINE static bool canDoFastPutDirectIndex(VM& vm, JSObject* object) > { >- return isJSArray(object) >+ return (isJSArray(object) && !isCopyOnWrite(object->indexingMode())) > || jsDynamicCast<JSFinalObject*>(vm, object) > || TypeInfo::isArgumentsType(object->type()); > } >@@ -2417,6 +2476,9 @@ bool JSObject::defineOwnIndexedProperty(ExecState* exec, unsigned index, const P > > ASSERT(index <= MAX_ARRAY_INDEX); > >+ if (isCopyOnWrite(indexingMode())) >+ convertFromCopyOnWrite(vm); >+ > if (!inSparseIndexingMode()) { > // Fast case: we're putting a regular property to a regular array > // FIXME: this will pessimistically assume that if attributes are missing then they'll default to false >@@ -2598,6 +2660,7 @@ bool JSObject::putByIndexBeyondVectorLengthWithoutAttributes(ExecState* exec, un > VM& vm = exec->vm(); > auto scope = DECLARE_THROW_SCOPE(vm); > >+ RELEASE_ASSERT_WITH_SECURITY_IMPLICATION(!isCopyOnWrite(indexingMode())); > ASSERT((indexingType() & IndexingShapeMask) == indexingShape); > ASSERT(!indexingShouldBeSparse()); > >@@ -2630,19 +2693,19 @@ bool JSObject::putByIndexBeyondVectorLengthWithoutAttributes(ExecState* exec, un > switch (indexingShape) { > case Int32Shape: > ASSERT(value.isInt32()); >- butterfly->contiguous().at(i).setWithoutWriteBarrier(value); >+ butterfly->contiguous().at(this, i).setWithoutWriteBarrier(value); > return true; > > case DoubleShape: { > ASSERT(value.isNumber()); > double valueAsDouble = value.asNumber(); > ASSERT(valueAsDouble == valueAsDouble); >- butterfly->contiguousDouble().at(i) = valueAsDouble; >+ butterfly->contiguousDouble().at(this, i) = valueAsDouble; > return true; > } > > case ContiguousShape: >- butterfly->contiguous().at(i).set(vm, this, value); >+ butterfly->contiguous().at(this, i).set(vm, this, value); > return true; > > default: >@@ -2661,6 +2724,7 @@ bool JSObject::putByIndexBeyondVectorLengthWithArrayStorage(ExecState* exec, uns > VM& vm = exec->vm(); > auto scope = DECLARE_THROW_SCOPE(vm); > >+ ASSERT(!isCopyOnWrite(indexingMode())); > // i should be a valid array index that is outside of the current vector. > ASSERT(i <= MAX_ARRAY_INDEX); > ASSERT(i >= storage->vectorLength()); >@@ -2733,6 +2797,8 @@ bool JSObject::putByIndexBeyondVectorLength(ExecState* exec, unsigned i, JSValue > { > VM& vm = exec->vm(); > >+ RELEASE_ASSERT_WITH_SECURITY_IMPLICATION(!isCopyOnWrite(indexingMode())); >+ > // i should be a valid array index that is outside of the current vector. > ASSERT(i <= MAX_ARRAY_INDEX); > >@@ -3071,12 +3137,12 @@ unsigned JSObject::countElements(Butterfly* butterfly) > switch (indexingShape) { > case Int32Shape: > case ContiguousShape: >- if (butterfly->contiguous().at(i)) >+ if (butterfly->contiguous().at(this, i)) > numValues++; > break; > > case DoubleShape: { >- double value = butterfly->contiguousDouble().at(i); >+ double value = butterfly->contiguousDouble().at(this, i); > if (value == value) > numValues++; > break; >@@ -3173,12 +3239,15 @@ bool JSObject::increaseVectorLength(VM& vm, unsigned newLength) > > bool JSObject::ensureLengthSlow(VM& vm, unsigned length) > { >+ if (isCopyOnWrite(indexingMode())) >+ convertFromCopyOnWrite(vm); >+ > Butterfly* butterfly = this->butterfly(); > > ASSERT(length <= MAX_STORAGE_VECTOR_LENGTH); > ASSERT(hasContiguous(indexingType()) || hasInt32(indexingType()) || hasDouble(indexingType()) || hasUndecided(indexingType())); > ASSERT(length > butterfly->vectorLength()); >- >+ > unsigned oldVectorLength = butterfly->vectorLength(); > unsigned newVectorLength; > >@@ -3195,7 +3264,7 @@ bool JSObject::ensureLengthSlow(VM& vm, unsigned length) > newVectorLength = availableOldLength; > } else { > newVectorLength = Butterfly::optimalContiguousVectorLength( >- propertyCapacity, std::min(length << 1, MAX_STORAGE_VECTOR_LENGTH)); >+ propertyCapacity, std::min(length * 2, MAX_STORAGE_VECTOR_LENGTH)); > butterfly = butterfly->growArrayRight( > vm, this, structure, propertyCapacity, true, > oldVectorLength * sizeof(EncodedJSValue), >@@ -3584,7 +3653,7 @@ uint32_t JSObject::getEnumerableLength(ExecState* exec, JSObject* object) > Butterfly* butterfly = object->butterfly(); > unsigned usedLength = butterfly->publicLength(); > for (unsigned i = 0; i < usedLength; ++i) { >- if (!butterfly->contiguous().at(i)) >+ if (!butterfly->contiguous().at(object, i)) > return 0; > } > return usedLength; >@@ -3594,7 +3663,7 @@ uint32_t JSObject::getEnumerableLength(ExecState* exec, JSObject* object) > Butterfly* butterfly = object->butterfly(); > unsigned usedLength = butterfly->publicLength(); > for (unsigned i = 0; i < usedLength; ++i) { >- double value = butterfly->contiguousDouble().at(i); >+ double value = butterfly->contiguousDouble().at(object, i); > if (value != value) > return 0; > } >diff --git a/Source/JavaScriptCore/runtime/JSObject.h b/Source/JavaScriptCore/runtime/JSObject.h >index c2eb8e6936429f4f6acef77754bf636d33ea3674..645301dcd3217848b267ffeff4de1933b59d6df0 100644 >--- a/Source/JavaScriptCore/runtime/JSObject.h >+++ b/Source/JavaScriptCore/runtime/JSObject.h >@@ -220,16 +220,18 @@ public: > bool putDirectIndex(ExecState* exec, unsigned propertyName, JSValue value, unsigned attributes, PutDirectIndexMode mode) > { > auto canSetIndexQuicklyForPutDirect = [&] () -> bool { >- switch (indexingType()) { >+ switch (indexingMode()) { > case ALL_BLANK_INDEXING_TYPES: > case ALL_UNDECIDED_INDEXING_TYPES: > return false; >- case ALL_INT32_INDEXING_TYPES: >- case ALL_DOUBLE_INDEXING_TYPES: >- case ALL_CONTIGUOUS_INDEXING_TYPES: >+ case ALL_WRITABLE_INT32_INDEXING_TYPES: >+ case ALL_WRITABLE_DOUBLE_INDEXING_TYPES: >+ case ALL_WRITABLE_CONTIGUOUS_INDEXING_TYPES: > case ALL_ARRAY_STORAGE_INDEXING_TYPES: > return propertyName < m_butterfly->vectorLength(); > default: >+ if (isCopyOnWrite(indexingMode())) >+ return false; > RELEASE_ASSERT_NOT_REACHED(); > return false; > } >@@ -269,11 +271,11 @@ public: > return false; > case ALL_INT32_INDEXING_TYPES: > case ALL_CONTIGUOUS_INDEXING_TYPES: >- return i < butterfly->vectorLength() && butterfly->contiguous().at(i); >+ return i < butterfly->vectorLength() && butterfly->contiguous().at(this, i); > case ALL_DOUBLE_INDEXING_TYPES: { > if (i >= butterfly->vectorLength()) > return false; >- double value = butterfly->contiguousDouble().at(i); >+ double value = butterfly->contiguousDouble().at(this, i); > if (value != value) > return false; > return true; >@@ -291,11 +293,11 @@ public: > Butterfly* butterfly = this->butterfly(); > switch (indexingType()) { > case ALL_INT32_INDEXING_TYPES: >- return jsNumber(butterfly->contiguous().at(i).get().asInt32()); >+ return jsNumber(butterfly->contiguous().at(this, i).get().asInt32()); > case ALL_CONTIGUOUS_INDEXING_TYPES: >- return butterfly->contiguous().at(i).get(); >+ return butterfly->contiguous().at(this, i).get(); > case ALL_DOUBLE_INDEXING_TYPES: >- return JSValue(JSValue::EncodeAsDouble, butterfly->contiguousDouble().at(i)); >+ return JSValue(JSValue::EncodeAsDouble, butterfly->contiguousDouble().at(this, i)); > case ALL_ARRAY_STORAGE_INDEXING_TYPES: > return butterfly->arrayStorage()->m_vector[i].get(); > default: >@@ -313,19 +315,19 @@ public: > break; > case ALL_INT32_INDEXING_TYPES: > if (i < butterfly->publicLength()) { >- JSValue result = butterfly->contiguous().at(i).get(); >+ JSValue result = butterfly->contiguous().at(this, i).get(); > ASSERT(result.isInt32() || !result); > return result; > } > break; > case ALL_CONTIGUOUS_INDEXING_TYPES: > if (i < butterfly->publicLength()) >- return butterfly->contiguous().at(i).get(); >+ return butterfly->contiguous().at(this, i).get(); > break; > case ALL_DOUBLE_INDEXING_TYPES: { > if (i >= butterfly->publicLength()) > break; >- double result = butterfly->contiguousDouble().at(i); >+ double result = butterfly->contiguousDouble().at(this, i); > if (result != result) > break; > return JSValue(JSValue::EncodeAsDouble, result); >@@ -361,13 +363,13 @@ public: > bool canSetIndexQuickly(unsigned i) > { > Butterfly* butterfly = this->butterfly(); >- switch (indexingType()) { >+ switch (indexingMode()) { > case ALL_BLANK_INDEXING_TYPES: > case ALL_UNDECIDED_INDEXING_TYPES: > return false; >- case ALL_INT32_INDEXING_TYPES: >- case ALL_DOUBLE_INDEXING_TYPES: >- case ALL_CONTIGUOUS_INDEXING_TYPES: >+ case ALL_WRITABLE_INT32_INDEXING_TYPES: >+ case ALL_WRITABLE_DOUBLE_INDEXING_TYPES: >+ case ALL_WRITABLE_CONTIGUOUS_INDEXING_TYPES: > case NonArrayWithArrayStorage: > case ArrayWithArrayStorage: > return i < butterfly->vectorLength(); >@@ -376,6 +378,8 @@ public: > return i < butterfly->arrayStorage()->vectorLength() > && !!butterfly->arrayStorage()->m_vector[i]; > default: >+ if (isCopyOnWrite(indexingMode())) >+ return false; > RELEASE_ASSERT_NOT_REACHED(); > return false; > } >@@ -384,6 +388,7 @@ public: > void setIndexQuickly(VM& vm, unsigned i, JSValue v) > { > Butterfly* butterfly = m_butterfly.get(); >+ ASSERT(!isCopyOnWrite(indexingMode())); > switch (indexingType()) { > case ALL_INT32_INDEXING_TYPES: { > ASSERT(i < butterfly->vectorLength()); >@@ -395,7 +400,7 @@ public: > } > case ALL_CONTIGUOUS_INDEXING_TYPES: { > ASSERT(i < butterfly->vectorLength()); >- butterfly->contiguous().at(i).set(vm, this, v); >+ butterfly->contiguous().at(this, i).set(vm, this, v); > if (i >= butterfly->publicLength()) > butterfly->setPublicLength(i + 1); > break; >@@ -411,7 +416,7 @@ public: > convertDoubleToContiguousWhilePerformingSetIndex(vm, i, v); > return; > } >- butterfly->contiguousDouble().at(i) = value; >+ butterfly->contiguousDouble().at(this, i) = value; > if (i >= butterfly->publicLength()) > butterfly->setPublicLength(i + 1); > break; >@@ -461,7 +466,7 @@ public: > case ALL_CONTIGUOUS_INDEXING_TYPES: { > ASSERT(i < butterfly->publicLength()); > ASSERT(i < butterfly->vectorLength()); >- butterfly->contiguous().at(i).set(vm, this, v); >+ butterfly->contiguous().at(this, i).set(vm, this, v); > break; > } > case ALL_DOUBLE_INDEXING_TYPES: { >@@ -476,7 +481,7 @@ public: > convertDoubleToContiguousWhilePerformingSetIndex(vm, i, v); > return; > } >- butterfly->contiguousDouble().at(i) = value; >+ butterfly->contiguousDouble().at(this, i) = value; > break; > } > case ALL_ARRAY_STORAGE_INDEXING_TYPES: { >@@ -515,7 +520,7 @@ public: > case ALL_CONTIGUOUS_INDEXING_TYPES: { > ASSERT(i < butterfly->publicLength()); > ASSERT(i < butterfly->vectorLength()); >- butterfly->contiguous().at(i).setWithoutWriteBarrier(v); >+ butterfly->contiguous().at(this, i).setWithoutWriteBarrier(v); > break; > } > case ALL_DOUBLE_INDEXING_TYPES: { >@@ -524,7 +529,7 @@ public: > RELEASE_ASSERT(v.isNumber()); > double value = v.asNumber(); > RELEASE_ASSERT(value == value); >- butterfly->contiguousDouble().at(i) = value; >+ butterfly->contiguousDouble().at(this, i) = value; > break; > } > case ALL_ARRAY_STORAGE_INDEXING_TYPES: { >@@ -817,34 +822,34 @@ public: > // indexing should be sparse, we're having a bad time, or because > // we already have a more general form of storage (double, > // contiguous, array storage). >- ContiguousJSValues ensureInt32(VM& vm) >+ ContiguousJSValues ensureWritableInt32(VM& vm) > { >- if (LIKELY(hasInt32(indexingType()))) >+ if (LIKELY(hasInt32(indexingType()) && !isCopyOnWrite(indexingMode()))) > return m_butterfly->contiguousInt32(); > >- return ensureInt32Slow(vm); >+ return ensureWritableInt32Slow(vm); > } > > // Returns 0 if double storage cannot be created - either because > // indexing should be sparse, we're having a bad time, or because > // we already have a more general form of storage (contiguous, > // or array storage). >- ContiguousDoubles ensureDouble(VM& vm) >+ ContiguousDoubles ensureWritableDouble(VM& vm) > { >- if (LIKELY(hasDouble(indexingType()))) >+ if (LIKELY(hasDouble(indexingType()) && !isCopyOnWrite(indexingMode()))) > return m_butterfly->contiguousDouble(); > >- return ensureDoubleSlow(vm); >+ return ensureWritableDoubleSlow(vm); > } > > // Returns 0 if contiguous storage cannot be created - either because > // indexing should be sparse or because we're having a bad time. >- ContiguousJSValues ensureContiguous(VM& vm) >+ ContiguousJSValues ensureWritableContiguous(VM& vm) > { >- if (LIKELY(hasContiguous(indexingType()))) >+ if (LIKELY(hasContiguous(indexingType()) && !isCopyOnWrite(indexingMode()))) > return m_butterfly->contiguous(); > >- return ensureContiguousSlow(vm); >+ return ensureWritableContiguousSlow(vm); > } > > // Ensure that the object is in a mode where it has array storage. Use >@@ -928,11 +933,13 @@ protected: > ContiguousJSValues createInitialInt32(VM&, unsigned length); > ContiguousDoubles createInitialDouble(VM&, unsigned length); > ContiguousJSValues createInitialContiguous(VM&, unsigned length); >- >+ > void convertUndecidedForValue(VM&, JSValue); > void createInitialForValueAndSet(VM&, unsigned index, JSValue); > void convertInt32ForValue(VM&, JSValue); >- >+ void convertDoubleForValue(VM&, JSValue); >+ void convertFromCopyOnWrite(VM&); >+ > static Butterfly* createArrayStorageButterfly(VM&, JSCell* intendedOwner, Structure*, unsigned length, unsigned vectorLength, Butterfly* oldButterfly = nullptr); > ArrayStorage* createArrayStorage(VM&, unsigned length, unsigned vectorLength); > ArrayStorage* createInitialArrayStorage(VM&); >@@ -947,7 +954,7 @@ protected: > ContiguousJSValues convertInt32ToContiguous(VM&); > ArrayStorage* convertInt32ToArrayStorage(VM&, NonPropertyTransition); > ArrayStorage* convertInt32ToArrayStorage(VM&); >- >+ > ContiguousJSValues convertDoubleToContiguous(VM&); > ArrayStorage* convertDoubleToArrayStorage(VM&, NonPropertyTransition); > ArrayStorage* convertDoubleToArrayStorage(VM&); >@@ -980,7 +987,7 @@ protected: > RELEASE_ASSERT(length <= MAX_STORAGE_VECTOR_LENGTH); > ASSERT(hasContiguous(indexingType()) || hasInt32(indexingType()) || hasDouble(indexingType()) || hasUndecided(indexingType())); > >- if (m_butterfly->vectorLength() < length) { >+ if (m_butterfly->vectorLength() < length || isCopyOnWrite(indexingMode())) { > if (!ensureLengthSlow(vm, length)) > return false; > } >@@ -1050,9 +1057,9 @@ private: > > bool ensureLengthSlow(VM&, unsigned length); > >- ContiguousJSValues ensureInt32Slow(VM&); >- ContiguousDoubles ensureDoubleSlow(VM&); >- ContiguousJSValues ensureContiguousSlow(VM&); >+ ContiguousJSValues ensureWritableInt32Slow(VM&); >+ ContiguousDoubles ensureWritableDoubleSlow(VM&); >+ ContiguousJSValues ensureWritableContiguousSlow(VM&); > JS_EXPORT_PRIVATE ArrayStorage* ensureArrayStorageSlow(VM&); > > PropertyOffset prepareToPutDirectWithoutTransition(VM&, PropertyName, unsigned attributes, StructureID, Structure*); >diff --git a/Source/JavaScriptCore/runtime/JSObjectInlines.h b/Source/JavaScriptCore/runtime/JSObjectInlines.h >index 5e2701f17a433e32d1bc6e9c87a4a5589d4f3f8f..85d1c9870b17c83d5f0fb29aa1b6b2515ba5b4ec 100644 >--- a/Source/JavaScriptCore/runtime/JSObjectInlines.h >+++ b/Source/JavaScriptCore/runtime/JSObjectInlines.h >@@ -277,6 +277,7 @@ ALWAYS_INLINE bool JSObject::putDirectInternal(VM& vm, PropertyName propertyName > StructureID structureID = this->structureID(); > Structure* structure = vm.heap.structureIDTable().get(structureID); > if (structure->isDictionary()) { >+ ASSERT(!isCopyOnWrite(indexingMode())); > ASSERT(!structure->hasInferredTypes()); > > unsigned currentAttributes; >diff --git a/Source/JavaScriptCore/runtime/JSType.h b/Source/JavaScriptCore/runtime/JSType.h >index d86dc3b4a5d4ca9057915e3408d44f2322b9e1e4..afa7dc2fd434f468ce27024240b6a0ea3cbbab18 100644 >--- a/Source/JavaScriptCore/runtime/JSType.h >+++ b/Source/JavaScriptCore/runtime/JSType.h >@@ -47,6 +47,7 @@ enum JSType : uint8_t { > CodeBlockType, > > JSFixedArrayType, >+ JSImmutableButterflyType, > JSSourceCodeType, > JSScriptFetcherType, > JSScriptFetchParametersType, >diff --git a/Source/JavaScriptCore/runtime/RegExpMatchesArray.h b/Source/JavaScriptCore/runtime/RegExpMatchesArray.h >index 940c2e5f7b94b4b885f927cb7946e53c39cb0b00..d1a1cbe4ff0a7bb0f5db6298ef23654dec9c347e 100644 >--- a/Source/JavaScriptCore/runtime/RegExpMatchesArray.h >+++ b/Source/JavaScriptCore/runtime/RegExpMatchesArray.h >@@ -51,7 +51,7 @@ ALWAYS_INLINE JSArray* tryCreateUninitializedRegExpMatchesArray(ObjectInitializa > > unsigned i = (createUninitialized ? initialLength : 0); > for (; i < vectorLength; ++i) >- butterfly->contiguous().at(i).clear(); >+ butterfly->contiguous().atUnsafe(i).clear(); > > JSArray* result = JSArray::createWithButterfly(vm, deferralContext, structure, butterfly); > scope.notifyAllocated(result, createUninitialized); >diff --git a/Source/JavaScriptCore/runtime/Structure.cpp b/Source/JavaScriptCore/runtime/Structure.cpp >index 34673866cc62f3a9697b1db44094118d1003baa9..dd33e83dd3b5462b3a3cc368b44ee73fd5f6b5f2 100644 >--- a/Source/JavaScriptCore/runtime/Structure.cpp >+++ b/Source/JavaScriptCore/runtime/Structure.cpp >@@ -271,7 +271,7 @@ Structure::Structure(VM& vm, Structure* previous, DeferredStructureTransitionWat > setIsAddingPropertyForTransition(false); > > TypeInfo typeInfo = previous->typeInfo(); >- m_blob = StructureIDBlob(vm.heap.structureIDTable().allocateID(this), previous->indexingTypeIncludingHistory(), typeInfo); >+ m_blob = StructureIDBlob(vm.heap.structureIDTable().allocateID(this), previous->indexingModeIncludingHistory(), typeInfo); > m_outOfLineTypeFlags = typeInfo.outOfLineTypeFlags(); > > ASSERT(!previous->typeInfo().structureIsImmortal()); >@@ -470,6 +470,7 @@ Structure* Structure::addNewPropertyTransition(VM& vm, Structure* structure, Pro > else > maxTransitionLength = s_maxTransitionLength; > if (structure->transitionCount() > maxTransitionLength) { >+ ASSERT(!isCopyOnWrite(structure->indexingMode())); > Structure* transition = toCacheableDictionaryTransition(vm, structure, deferred); > ASSERT(structure != transition); > offset = transition->add(vm, propertyName, attributes); >@@ -493,7 +494,8 @@ Structure* Structure::addNewPropertyTransition(VM& vm, Structure* structure, Pro > ConcurrentJSLocker locker(transition->m_lock); > transition->setIsAddingPropertyForTransition(true); > } >- >+ >+ transition->m_blob.setIndexingModeIncludingHistory(structure->indexingModeIncludingHistory() & ~CopyOnWrite); > transition->m_nameInPrevious = propertyName.uid(); > transition->setAttributesInPrevious(attributes); > transition->setPropertyTable(vm, structure->takePropertyTableOrCloneIfPinned(vm)); >@@ -644,13 +646,13 @@ PropertyTable* Structure::takePropertyTableOrCloneIfPinned(VM& vm) > Structure* Structure::nonPropertyTransition(VM& vm, Structure* structure, NonPropertyTransition transitionKind) > { > unsigned attributes = toAttributes(transitionKind); >- IndexingType indexingTypeIncludingHistory = newIndexingType(structure->indexingTypeIncludingHistory(), transitionKind); >+ IndexingType indexingModeIncludingHistory = newIndexingType(structure->indexingModeIncludingHistory(), transitionKind); > > if (changesIndexingType(transitionKind)) { > if (JSGlobalObject* globalObject = structure->m_globalObject.get()) { > if (globalObject->isOriginalArrayStructure(structure)) { >- Structure* result = globalObject->originalArrayStructureForIndexingType(indexingTypeIncludingHistory); >- if (result->indexingTypeIncludingHistory() == indexingTypeIncludingHistory) { >+ Structure* result = globalObject->originalArrayStructureForIndexingType(indexingModeIncludingHistory); >+ if (result->indexingModeIncludingHistory() == indexingModeIncludingHistory) { > structure->didTransitionFromThisStructure(); > return result; > } >@@ -661,7 +663,7 @@ Structure* Structure::nonPropertyTransition(VM& vm, Structure* structure, NonPro > Structure* existingTransition; > if (!structure->isDictionary() && (existingTransition = structure->m_transitionTable.get(0, attributes))) { > ASSERT(existingTransition->attributesInPrevious() == attributes); >- ASSERT(existingTransition->indexingTypeIncludingHistory() == indexingTypeIncludingHistory); >+ ASSERT(existingTransition->indexingModeIncludingHistory() == indexingModeIncludingHistory); > return existingTransition; > } > >@@ -669,7 +671,7 @@ Structure* Structure::nonPropertyTransition(VM& vm, Structure* structure, NonPro > > Structure* transition = create(vm, structure); > transition->setAttributesInPrevious(attributes); >- transition->m_blob.setIndexingTypeIncludingHistory(indexingTypeIncludingHistory); >+ transition->m_blob.setIndexingModeIncludingHistory(indexingModeIncludingHistory); > > if (preventsExtensions(transitionKind)) > transition->setDidPreventExtensions(true); >diff --git a/Source/JavaScriptCore/runtime/Structure.h b/Source/JavaScriptCore/runtime/Structure.h >index 37696bb1d039c1be24507da409863a2b9bbe5805..8c4ef75bd67b08d58aeef7e7b0e83f9610ade9d1 100644 >--- a/Source/JavaScriptCore/runtime/Structure.h >+++ b/Source/JavaScriptCore/runtime/Structure.h >@@ -251,12 +251,13 @@ public: > TypeInfo typeInfo() const { return m_blob.typeInfo(m_outOfLineTypeFlags); } > bool isObject() const { return typeInfo().isObject(); } > >- IndexingType indexingType() const { return m_blob.indexingTypeIncludingHistory() & AllArrayTypes; } >- IndexingType indexingTypeIncludingHistory() const { return m_blob.indexingTypeIncludingHistory(); } >+ IndexingType indexingType() const { return m_blob.indexingModeIncludingHistory() & AllWritableArrayTypes; } >+ IndexingType indexingMode() const { return m_blob.indexingModeIncludingHistory() & AllArrayTypes; } >+ IndexingType indexingModeIncludingHistory() const { return m_blob.indexingModeIncludingHistory(); } > > bool mayInterceptIndexedAccesses() const > { >- return !!(indexingTypeIncludingHistory() & MayHaveIndexedAccessors); >+ return !!(indexingModeIncludingHistory() & MayHaveIndexedAccessors); > } > > bool holesMustForwardToPrototype(VM&, JSObject*) const; >@@ -496,9 +497,9 @@ public: > return OBJECT_OFFSETOF(Structure, m_classInfo); > } > >- static ptrdiff_t indexingTypeIncludingHistoryOffset() >+ static ptrdiff_t indexingModeIncludingHistoryOffset() > { >- return OBJECT_OFFSETOF(Structure, m_blob) + StructureIDBlob::indexingTypeIncludingHistoryOffset(); >+ return OBJECT_OFFSETOF(Structure, m_blob) + StructureIDBlob::indexingModeIncludingHistoryOffset(); > } > > static ptrdiff_t propertyTableUnsafeOffset() >diff --git a/Source/JavaScriptCore/runtime/StructureIDBlob.h b/Source/JavaScriptCore/runtime/StructureIDBlob.h >index 51564ca4028bcec8ded711c53ebad8f5ce815c87..066c8adf468e07b81a7daeb604126725acf67401 100644 >--- a/Source/JavaScriptCore/runtime/StructureIDBlob.h >+++ b/Source/JavaScriptCore/runtime/StructureIDBlob.h >@@ -40,10 +40,10 @@ public: > u.doubleWord = 0xbbadbeef; > } > >- StructureIDBlob(StructureID structureID, IndexingType indexingTypeIncludingHistory, const TypeInfo& typeInfo) >+ StructureIDBlob(StructureID structureID, IndexingType indexingModeIncludingHistory, const TypeInfo& typeInfo) > { > u.fields.structureID = structureID; >- u.fields.indexingTypeIncludingHistory = indexingTypeIncludingHistory; >+ u.fields.indexingModeIncludingHistory = indexingModeIncludingHistory; > u.fields.type = typeInfo.type(); > u.fields.inlineTypeFlags = typeInfo.inlineTypeFlags(); > u.fields.defaultCellState = CellState::DefinitelyWhite; >@@ -52,8 +52,8 @@ public: > void operator=(const StructureIDBlob& other) { u.doubleWord = other.u.doubleWord; } > > StructureID structureID() const { return u.fields.structureID; } >- IndexingType indexingTypeIncludingHistory() const { return u.fields.indexingTypeIncludingHistory; } >- void setIndexingTypeIncludingHistory(IndexingType indexingTypeIncludingHistory) { u.fields.indexingTypeIncludingHistory = indexingTypeIncludingHistory; } >+ IndexingType indexingModeIncludingHistory() const { return u.fields.indexingModeIncludingHistory; } >+ void setIndexingModeIncludingHistory(IndexingType indexingModeIncludingHistory) { u.fields.indexingModeIncludingHistory = indexingModeIncludingHistory; } > JSType type() const { return u.fields.type; } > TypeInfo::InlineTypeFlags inlineTypeFlags() const { return u.fields.inlineTypeFlags; } > >@@ -67,16 +67,16 @@ public: > return OBJECT_OFFSETOF(StructureIDBlob, u.fields.structureID); > } > >- static ptrdiff_t indexingTypeIncludingHistoryOffset() >+ static ptrdiff_t indexingModeIncludingHistoryOffset() > { >- return OBJECT_OFFSETOF(StructureIDBlob, u.fields.indexingTypeIncludingHistory); >+ return OBJECT_OFFSETOF(StructureIDBlob, u.fields.indexingModeIncludingHistory); > } > > private: > union { > struct { > StructureID structureID; >- IndexingType indexingTypeIncludingHistory; >+ IndexingType indexingModeIncludingHistory; > JSType type; > TypeInfo::InlineTypeFlags inlineTypeFlags; > CellState defaultCellState; >diff --git a/Source/JavaScriptCore/runtime/StructureTransitionTable.h b/Source/JavaScriptCore/runtime/StructureTransitionTable.h >index 68a4689d0c91e881bad79cae8ea0eaa77114ba9a..437641e5ecb91efbe59cd1261fc96f1a2ed82234 100644 >--- a/Source/JavaScriptCore/runtime/StructureTransitionTable.h >+++ b/Source/JavaScriptCore/runtime/StructureTransitionTable.h >@@ -83,23 +83,23 @@ inline IndexingType newIndexingType(IndexingType oldType, NonPropertyTransition > ASSERT(!hasIndexedProperties(oldType)); > return oldType | UndecidedShape; > case NonPropertyTransition::AllocateInt32: >- ASSERT(!hasIndexedProperties(oldType) || hasUndecided(oldType)); >- return (oldType & ~IndexingShapeMask) | Int32Shape; >+ ASSERT(!hasIndexedProperties(oldType) || hasUndecided(oldType) || oldType == CopyOnWriteArrayWithInt32); >+ return (oldType & ~IndexingShapeAndWritabilityMask) | Int32Shape; > case NonPropertyTransition::AllocateDouble: >- ASSERT(!hasIndexedProperties(oldType) || hasUndecided(oldType) || hasInt32(oldType)); >- return (oldType & ~IndexingShapeMask) | DoubleShape; >+ ASSERT(!hasIndexedProperties(oldType) || hasUndecided(oldType) || hasInt32(oldType) || oldType == CopyOnWriteArrayWithDouble); >+ return (oldType & ~IndexingShapeAndWritabilityMask) | DoubleShape; > case NonPropertyTransition::AllocateContiguous: >- ASSERT(!hasIndexedProperties(oldType) || hasUndecided(oldType) || hasInt32(oldType) || hasDouble(oldType)); >- return (oldType & ~IndexingShapeMask) | ContiguousShape; >+ ASSERT(!hasIndexedProperties(oldType) || hasUndecided(oldType) || hasInt32(oldType) || hasDouble(oldType) || oldType == CopyOnWriteArrayWithContiguous); >+ return (oldType & ~IndexingShapeAndWritabilityMask) | ContiguousShape; > case NonPropertyTransition::AllocateArrayStorage: > ASSERT(!hasIndexedProperties(oldType) || hasUndecided(oldType) || hasInt32(oldType) || hasDouble(oldType) || hasContiguous(oldType)); >- return (oldType & ~IndexingShapeMask) | ArrayStorageShape; >+ return (oldType & ~IndexingShapeAndWritabilityMask) | ArrayStorageShape; > case NonPropertyTransition::AllocateSlowPutArrayStorage: >- ASSERT(!hasIndexedProperties(oldType) || hasUndecided(oldType) || hasInt32(oldType) || hasDouble(oldType) || hasContiguous(oldType) || hasContiguous(oldType)); >- return (oldType & ~IndexingShapeMask) | SlowPutArrayStorageShape; >+ ASSERT(!hasIndexedProperties(oldType) || hasUndecided(oldType) || hasInt32(oldType) || hasDouble(oldType) || hasContiguous(oldType)); >+ return (oldType & ~IndexingShapeAndWritabilityMask) | SlowPutArrayStorageShape; > case NonPropertyTransition::SwitchToSlowPutArrayStorage: > ASSERT(hasArrayStorage(oldType)); >- return (oldType & ~IndexingShapeMask) | SlowPutArrayStorageShape; >+ return (oldType & ~IndexingShapeAndWritabilityMask) | SlowPutArrayStorageShape; > case NonPropertyTransition::AddIndexedAccessors: > return oldType | MayHaveIndexedAccessors; > default: >diff --git a/Source/JavaScriptCore/runtime/VM.cpp b/Source/JavaScriptCore/runtime/VM.cpp >index 7d366d6d524fc4bffdb41218c4ad66da57ae838d..639ef1e2b59f6251938b74cd608a7aca7d7b4005 100644 >--- a/Source/JavaScriptCore/runtime/VM.cpp >+++ b/Source/JavaScriptCore/runtime/VM.cpp >@@ -85,6 +85,7 @@ > #include "JSFixedArray.h" > #include "JSFunction.h" > #include "JSGlobalObjectFunctions.h" >+#include "JSImmutableButterfly.h" > #include "JSInternalPromiseDeferred.h" > #include "JSLock.h" > #include "JSMap.h" >@@ -380,6 +381,11 @@ VM::VM(VMType vmType, HeapType heapType) > symbolStructure.set(*this, Symbol::createStructure(*this, 0, jsNull())); > symbolTableStructure.set(*this, SymbolTable::createStructure(*this, 0, jsNull())); > fixedArrayStructure.set(*this, JSFixedArray::createStructure(*this, 0, jsNull())); >+ >+ immutableButterflyStructures[arrayIndexFromIndexingType(CopyOnWriteArrayWithInt32) - NumberOfIndexingShapes].set(*this, JSImmutableButterfly::createStructure(*this, 0, jsNull(), CopyOnWriteArrayWithInt32)); >+ immutableButterflyStructures[arrayIndexFromIndexingType(CopyOnWriteArrayWithDouble) - NumberOfIndexingShapes].set(*this, JSImmutableButterfly::createStructure(*this, 0, jsNull(), CopyOnWriteArrayWithDouble)); >+ immutableButterflyStructures[arrayIndexFromIndexingType(CopyOnWriteArrayWithContiguous) - NumberOfIndexingShapes].set(*this, JSImmutableButterfly::createStructure(*this, 0, jsNull(), CopyOnWriteArrayWithContiguous)); >+ > sourceCodeStructure.set(*this, JSSourceCode::createStructure(*this, 0, jsNull())); > scriptFetcherStructure.set(*this, JSScriptFetcher::createStructure(*this, 0, jsNull())); > scriptFetchParametersStructure.set(*this, JSScriptFetchParameters::createStructure(*this, 0, jsNull())); >diff --git a/Source/JavaScriptCore/runtime/VM.h b/Source/JavaScriptCore/runtime/VM.h >index 267f7376944bc591b5ecc0af9ef160b85d8b8885..6256af820e91231e91ddc243722127269ef70a92 100644 >--- a/Source/JavaScriptCore/runtime/VM.h >+++ b/Source/JavaScriptCore/runtime/VM.h >@@ -465,6 +465,7 @@ public: > Strong<Structure> symbolStructure; > Strong<Structure> symbolTableStructure; > Strong<Structure> fixedArrayStructure; >+ Strong<Structure> immutableButterflyStructures[NumberOfCopyOnWriteIndexingModes]; > Strong<Structure> sourceCodeStructure; > Strong<Structure> scriptFetcherStructure; > Strong<Structure> scriptFetchParametersStructure; >diff --git a/Source/WebCore/bindings/js/JSDOMConvertSequences.h b/Source/WebCore/bindings/js/JSDOMConvertSequences.h >index 2b3da229fbf9bf8ca4cfb8a2ca9aa89996f4b34e..0e7488af554ccb4a377ebc367bd63f9d23ac378b 100644 >--- a/Source/WebCore/bindings/js/JSDOMConvertSequences.h >+++ b/Source/WebCore/bindings/js/JSDOMConvertSequences.h >@@ -92,7 +92,7 @@ struct NumericSequenceConverter { > { > if (indexingType == JSC::Int32Shape) { > for (unsigned i = 0; i < length; i++) { >- auto indexValue = array->butterfly()->contiguousInt32().at(i).get(); >+ auto indexValue = array->butterfly()->contiguousInt32().at(array, i).get(); > ASSERT(!indexValue || indexValue.isInt32()); > if (!indexValue) > result.uncheckedAppend(0); >@@ -104,7 +104,7 @@ struct NumericSequenceConverter { > > ASSERT(indexingType == JSC::DoubleShape); > for (unsigned i = 0; i < length; i++) { >- auto doubleValue = array->butterfly()->contiguousDouble().at(i); >+ auto doubleValue = array->butterfly()->contiguousDouble().at(array, i); > if (std::isnan(doubleValue)) > result.uncheckedAppend(0); > else { >@@ -210,7 +210,7 @@ struct SequenceConverter { > > if (indexingType == JSC::ContiguousShape) { > for (unsigned i = 0; i < length; i++) { >- auto indexValue = array->butterfly()->contiguous().at(i).get(); >+ auto indexValue = array->butterfly()->contiguous().at(array, i).get(); > if (!indexValue) > indexValue = JSC::jsUndefined(); > >diff --git a/JSTests/ChangeLog b/JSTests/ChangeLog >index 90a0f3db1deebfa4d6a51d2b6d8d10aabbb84275..9287ac9287a9b59c4fc49f05217007ffef4423f9 100644 >--- a/JSTests/ChangeLog >+++ b/JSTests/ChangeLog >@@ -1,3 +1,12 @@ >+2018-05-18 Keith Miller <keith_miller@apple.com> >+ >+ We should have a CoW storage for NewArrayBuffer arrays. >+ https://bugs.webkit.org/show_bug.cgi?id=185003 >+ >+ Reviewed by NOBODY (OOPS!). >+ >+ * stress/new-array-buffer-with-nan.js: Added. >+ > 2018-04-29 Commit Queue <commit-queue@webkit.org> > > Unreviewed, rolling out r231137. >diff --git a/JSTests/stress/new-array-buffer-with-nan.js b/JSTests/stress/new-array-buffer-with-nan.js >new file mode 100644 >index 0000000000000000000000000000000000000000..d796ad769c38db3ec035e09e160e9e177d0ad9cf >--- /dev/null >+++ b/JSTests/stress/new-array-buffer-with-nan.js >@@ -0,0 +1,3 @@ >+// TODO: Make sure I test NaN with DoubleShape >+ >+let a = [NaN, 1];
You cannot view the attachment while viewing its details because your browser does not support IFRAMEs.
View the attachment on a separate page
.
View Attachment As Diff
View Attachment As Raw
Actions:
View
|
Formatted Diff
|
Diff
Attachments on
bug 185003
:
340710
|
340771
|
340776
|
340778
|
340780
|
340781
|
340782
|
340893
|
340894
|
340900
|
340929
|
340942
|
340989
|
340993