Inline property storage should not be wasted when it is exhausted
https://bugs.webkit.org/show_bug.cgi?id=90347
Reviewed by Gavin Barraclough.
Previously, if we switched an object from using inline storage to out-of-line
storage, we would abandon the inline storage. This would have two main implications:
(i) all accesses to the object, even for properties that were previously in inline
storage, must now take an extra indirection; and (ii) we waste a non-trivial amount
of space since we must allocate additional out-of-line storage to hold properties
that would have fit in the inline storage. There's also the copying cost when
switching to out-of-line storage - we must copy all inline properties into ouf-of-line
storage.
This patch changes the way that object property storage works so that we can use both
inline and out-of-line storage concurrently. This is accomplished by introducing a
new notion of property offset. This PropertyOffset is a 32-bit signed integer and it
behaves as follows:
offset == -1: invalid offset, indicating a property that does not exist.
0 <= offset <= inlineStorageCapacity: offset into inline storage.
inlineStorageCapacity < offset: offset into out-of-line storage.
Because non-final objects don't have inline storage, the only valid PropertyOffsets
for those objects' properties are -1 or > inlineStorageCapacity.
This now means that the decision to use inline or out-of-line storage for an access is
made based on the offset, rather than the structure. It also means that any access
where the offset is a variable must have an extra branch, unless the type of the
object is also known (if it's known to be a non-final object then we can just assert
that the offset is >= inlineStorageCapacity).
This looks like a big Kraken speed-up and a slight V8 speed-up.
* GNUmakefile.list.am:
* JavaScriptCore.vcproj/JavaScriptCore/JavaScriptCore.def:
* JavaScriptCore.vcproj/JavaScriptCore/JavaScriptCore.vcproj:
* JavaScriptCore.xcodeproj/project.pbxproj:
* assembler/ARMv7Assembler.h:
(ARMv7Assembler):
(JSC::ARMv7Assembler::ldrWide8BitImmediate):
(JSC::ARMv7Assembler::replaceWithLoad):
(JSC::ARMv7Assembler::replaceWithAddressComputation):
* assembler/AbstractMacroAssembler.h:
(AbstractMacroAssembler):
(ConvertibleLoadLabel):
(JSC::AbstractMacroAssembler::ConvertibleLoadLabel::ConvertibleLoadLabel):
(JSC::AbstractMacroAssembler::ConvertibleLoadLabel::isSet):
(JSC::AbstractMacroAssembler::labelIgnoringWatchpoints):
(JSC::AbstractMacroAssembler::replaceWithLoad):
(JSC::AbstractMacroAssembler::replaceWithAddressComputation):
* assembler/CodeLocation.h:
(JSC):
(CodeLocationCommon):
(CodeLocationConvertibleLoad):
(JSC::CodeLocationConvertibleLoad::CodeLocationConvertibleLoad):
(JSC::CodeLocationCommon::convertibleLoadAtOffset):
* assembler/LinkBuffer.cpp:
(JSC::LinkBuffer::finalizeCodeWithDisassembly):
* assembler/LinkBuffer.h:
(LinkBuffer):
(JSC::LinkBuffer::locationOf):
* assembler/MacroAssemblerARMv7.h:
(MacroAssemblerARMv7):
(JSC::MacroAssemblerARMv7::convertibleLoadPtr):
* assembler/MacroAssemblerX86.h:
(JSC::MacroAssemblerX86::convertibleLoadPtr):
(MacroAssemblerX86):
* assembler/MacroAssemblerX86_64.h:
(JSC::MacroAssemblerX86_64::convertibleLoadPtr):
(MacroAssemblerX86_64):
* assembler/RepatchBuffer.h:
(RepatchBuffer):
(JSC::RepatchBuffer::replaceWithLoad):
(JSC::RepatchBuffer::replaceWithAddressComputation):
(JSC::RepatchBuffer::setLoadInstructionIsActive):
* assembler/X86Assembler.h:
(JSC::X86Assembler::replaceWithLoad):
(X86Assembler):
(JSC::X86Assembler::replaceWithAddressComputation):
* bytecode/CodeBlock.cpp:
(JSC::CodeBlock::printGetByIdOp):
(JSC::CodeBlock::dump):
(JSC::CodeBlock::finalizeUnconditionally):
* bytecode/GetByIdStatus.cpp:
(JSC::GetByIdStatus::computeFromLLInt):
(JSC::GetByIdStatus::computeForChain):
(JSC::GetByIdStatus::computeFor):
* bytecode/GetByIdStatus.h:
(JSC::GetByIdStatus::GetByIdStatus):
(JSC::GetByIdStatus::offset):
(GetByIdStatus):
* bytecode/Opcode.h:
(JSC):
(JSC::padOpcodeName):
* bytecode/PutByIdStatus.cpp:
(JSC::PutByIdStatus::computeFromLLInt):
(JSC::PutByIdStatus::computeFor):
* bytecode/PutByIdStatus.h:
(JSC::PutByIdStatus::PutByIdStatus):
(JSC::PutByIdStatus::offset):
(PutByIdStatus):
* bytecode/ResolveGlobalStatus.cpp:
(JSC):
(JSC::computeForStructure):
* bytecode/ResolveGlobalStatus.h:
(JSC::ResolveGlobalStatus::ResolveGlobalStatus):
(JSC::ResolveGlobalStatus::offset):
(ResolveGlobalStatus):
* bytecode/StructureSet.h:
(StructureSet):
* bytecode/StructureStubInfo.h:
* dfg/DFGByteCodeParser.cpp:
(ByteCodeParser):
(JSC::DFG::ByteCodeParser::handleGetByOffset):
(JSC::DFG::ByteCodeParser::handleGetById):
(JSC::DFG::ByteCodeParser::parseBlock):
* dfg/DFGCapabilities.h:
(JSC::DFG::canCompileOpcode):
* dfg/DFGJITCompiler.cpp:
(JSC::DFG::JITCompiler::link):
* dfg/DFGJITCompiler.h:
(JSC::DFG::PropertyAccessRecord::PropertyAccessRecord):
(PropertyAccessRecord):
* dfg/DFGRepatch.cpp:
(JSC::DFG::dfgRepatchByIdSelfAccess):
(JSC::DFG::generateProtoChainAccessStub):
(JSC::DFG::tryCacheGetByID):
(JSC::DFG::tryBuildGetByIDList):
(JSC::DFG::tryBuildGetByIDProtoList):
(JSC::DFG::emitPutReplaceStub):
(JSC::DFG::emitPutTransitionStub):
(JSC::DFG::tryCachePutByID):
(JSC::DFG::tryBuildPutByIdList):
* dfg/DFGSpeculativeJIT.h:
(JSC::DFG::SpeculativeJIT::emitAllocateBasicJSObject):
* dfg/DFGSpeculativeJIT32_64.cpp:
(JSC::DFG::SpeculativeJIT::cachedGetById):
(JSC::DFG::SpeculativeJIT::cachedPutById):
(JSC::DFG::SpeculativeJIT::compile):
* dfg/DFGSpeculativeJIT64.cpp:
(JSC::DFG::SpeculativeJIT::cachedGetById):
(JSC::DFG::SpeculativeJIT::cachedPutById):
(JSC::DFG::SpeculativeJIT::compile):
* heap/MarkStack.cpp:
(JSC::visitChildren):
* interpreter/Interpreter.cpp:
(JSC::Interpreter::tryCacheGetByID):
(JSC::Interpreter::privateExecute):
* jit/JIT.cpp:
(JSC::JIT::privateCompileMainPass):
(JSC::JIT::privateCompileSlowCases):
(JSC::PropertyStubCompilationInfo::copyToStubInfo):
* jit/JIT.h:
(JSC::PropertyStubCompilationInfo::PropertyStubCompilationInfo):
(JSC::JIT::compileGetByIdProto):
(JSC::JIT::compileGetByIdSelfList):
(JSC::JIT::compileGetByIdProtoList):
(JSC::JIT::compileGetByIdChainList):
(JSC::JIT::compileGetByIdChain):
(JSC::JIT::compilePutByIdTransition):
(JIT):
* jit/JITInlineMethods.h:
(JSC::JIT::emitAllocateBasicJSObject):
* jit/JITOpcodes.cpp:
(JSC::JIT::emit_op_resolve_global):
* jit/JITOpcodes32_64.cpp:
(JSC::JIT::emit_op_resolve_global):
* jit/JITPropertyAccess.cpp:
(JSC::JIT::compileGetDirectOffset):
(JSC::JIT::emit_op_method_check):
(JSC::JIT::compileGetByIdHotPath):
(JSC::JIT::emit_op_put_by_id):
(JSC::JIT::compilePutDirectOffset):
(JSC::JIT::privateCompilePutByIdTransition):
(JSC::JIT::patchGetByIdSelf):
(JSC::JIT::patchPutByIdReplace):
(JSC::JIT::privateCompileGetByIdProto):
(JSC::JIT::privateCompileGetByIdSelfList):
(JSC::JIT::privateCompileGetByIdProtoList):
(JSC::JIT::privateCompileGetByIdChainList):
(JSC::JIT::privateCompileGetByIdChain):
* jit/JITPropertyAccess32_64.cpp:
(JSC::JIT::emit_op_method_check):
(JSC::JIT::compileGetByIdHotPath):
(JSC::JIT::emit_op_put_by_id):
(JSC::JIT::compilePutDirectOffset):
(JSC::JIT::compileGetDirectOffset):
(JSC::JIT::privateCompilePutByIdTransition):
(JSC::JIT::patchGetByIdSelf):
(JSC::JIT::patchPutByIdReplace):
(JSC::JIT::privateCompileGetByIdProto):
(JSC::JIT::privateCompileGetByIdSelfList):
(JSC::JIT::privateCompileGetByIdProtoList):
(JSC::JIT::privateCompileGetByIdChainList):
(JSC::JIT::privateCompileGetByIdChain):
(JSC::JIT::emit_op_get_by_pname):
* jit/JITStubs.cpp:
(JSC::JITThunks::tryCacheGetByID):
(JSC::DEFINE_STUB_FUNCTION):
* llint/LLIntSlowPaths.cpp:
(JSC::LLInt::LLINT_SLOW_PATH_DECL):
* llint/LowLevelInterpreter.asm:
* llint/LowLevelInterpreter32_64.asm:
* llint/LowLevelInterpreter64.asm:
* offlineasm/x86.rb:
* runtime/JSGlobalObject.h:
(JSGlobalObject):
(JSC::JSGlobalObject::functionNameOffset):
* runtime/JSObject.cpp:
(JSC::JSObject::visitChildren):
(JSC):
(JSC::JSFinalObject::visitChildren):
(JSC::JSObject::put):
(JSC::JSObject::deleteProperty):
(JSC::JSObject::getPropertySpecificValue):
(JSC::JSObject::removeDirect):
(JSC::JSObject::growOutOfLineStorage):
(JSC::JSObject::getOwnPropertyDescriptor):
* runtime/JSObject.h:
(JSObject):
(JSC::JSObject::getDirect):
(JSC::JSObject::getDirectLocation):
(JSC::JSObject::hasInlineStorage):
(JSC::JSObject::inlineStorageUnsafe):
(JSC::JSObject::inlineStorage):
(JSC::JSObject::outOfLineStorage):
(JSC::JSObject::locationForOffset):
(JSC::JSObject::offsetForLocation):
(JSC::JSObject::getDirectOffset):
(JSC::JSObject::putDirectOffset):
(JSC::JSObject::putUndefinedAtDirectOffset):
(JSC::JSObject::addressOfOutOfLineStorage):
(JSC::JSObject::finishCreation):
(JSC::JSNonFinalObject::JSNonFinalObject):
(JSC::JSNonFinalObject::finishCreation):
(JSFinalObject):
(JSC::JSFinalObject::finishCreation):
(JSC::JSFinalObject::JSFinalObject):
(JSC::JSObject::offsetOfOutOfLineStorage):
(JSC::JSObject::setOutOfLineStorage):
(JSC::JSObject::JSObject):
(JSC):
(JSC::JSCell::fastGetOwnProperty):
(JSC::JSObject::putDirectInternal):
(JSC::JSObject::setStructureAndReallocateStorageIfNecessary):
(JSC::JSObject::putDirectWithoutTransition):
(JSC::offsetRelativeToPatchedStorage):
(JSC::indexRelativeToBase):
(JSC::offsetRelativeToBase):
* runtime/JSPropertyNameIterator.cpp:
(JSC::JSPropertyNameIterator::create):
* runtime/JSPropertyNameIterator.h:
(JSPropertyNameIterator):
(JSC::JSPropertyNameIterator::getOffset):
(JSC::JSPropertyNameIterator::finishCreation):
* runtime/JSValue.cpp:
(JSC::JSValue::putToPrimitive):
* runtime/Operations.h:
(JSC::normalizePrototypeChain):
* runtime/Options.cpp:
(JSC):
(JSC::Options::initialize):
* runtime/PropertyMapHashTable.h:
(PropertyMapEntry):
(JSC::PropertyMapEntry::PropertyMapEntry):
(PropertyTable):
(JSC::PropertyTable::PropertyTable):
(JSC::PropertyTable::getDeletedOffset):
(JSC::PropertyTable::addDeletedOffset):
(JSC::PropertyTable::nextOffset):
(JSC):
(JSC::PropertyTable::sizeInMemory):
* runtime/PropertyOffset.h: Added.
(JSC):
(JSC::checkOffset):
(JSC::validateOffset):
(JSC::isValidOffset):
(JSC::isInlineOffset):
(JSC::isOutOfLineOffset):
(JSC::offsetInInlineStorage):
(JSC::offsetInOutOfLineStorage):
(JSC::offsetInRespectiveStorage):
(JSC::numberOfOutOfLineSlotsForLastOffset):
(JSC::numberOfSlotsForLastOffset):
(JSC::nextPropertyOffsetFor):
(JSC::firstPropertyOffsetFor):
* runtime/PropertySlot.h:
(JSC::PropertySlot::cachedOffset):
(JSC::PropertySlot::setValue):
(JSC::PropertySlot::setCacheableGetterSlot):
(JSC::PropertySlot::clearOffset):
* runtime/PutPropertySlot.h:
(JSC::PutPropertySlot::setExistingProperty):
(JSC::PutPropertySlot::setNewProperty):
(JSC::PutPropertySlot::cachedOffset):
(PutPropertySlot):
* runtime/Structure.cpp:
(JSC::Structure::Structure):
(JSC::Structure::materializePropertyMap):
(JSC::nextOutOfLineStorageCapacity):
(JSC::Structure::growOutOfLineCapacity):
(JSC::Structure::suggestedNewOutOfLineStorageCapacity):
(JSC::Structure::addPropertyTransitionToExistingStructure):
(JSC::Structure::addPropertyTransition):
(JSC::Structure::removePropertyTransition):
(JSC::Structure::flattenDictionaryStructure):
(JSC::Structure::addPropertyWithoutTransition):
(JSC::Structure::removePropertyWithoutTransition):
(JSC::Structure::copyPropertyTableForPinning):
(JSC::Structure::get):
(JSC::Structure::putSpecificValue):
(JSC::Structure::remove):
* runtime/Structure.h:
(Structure):
(JSC::Structure::putWillGrowOutOfLineStorage):
(JSC::Structure::previousID):
(JSC::Structure::outOfLineCapacity):
(JSC::Structure::outOfLineSizeForKnownFinalObject):
(JSC::Structure::outOfLineSizeForKnownNonFinalObject):
(JSC::Structure::outOfLineSize):
(JSC::Structure::hasInlineStorage):
(JSC::Structure::inlineCapacity):
(JSC::Structure::inlineSizeForKnownFinalObject):
(JSC::Structure::inlineSize):
(JSC::Structure::totalStorageSize):
(JSC::Structure::totalStorageCapacity):
(JSC::Structure::firstValidOffset):
(JSC::Structure::lastValidOffset):
(JSC::Structure::isValidOffset):
(JSC::Structure::isEmpty):
(JSC::Structure::transitionCount):
(JSC::Structure::get):
git-svn-id: http://svn.webkit.org/repository/webkit/trunk@121925 268f45cc-cd09-0410-ab3c-d52691b4dbfc
diff --git a/Source/JavaScriptCore/ChangeLog b/Source/JavaScriptCore/ChangeLog
index e6e9639..8373d91 100644
--- a/Source/JavaScriptCore/ChangeLog
+++ b/Source/JavaScriptCore/ChangeLog
@@ -1,3 +1,341 @@
+2012-07-04 Filip Pizlo <fpizlo@apple.com>
+
+ Inline property storage should not be wasted when it is exhausted
+ https://bugs.webkit.org/show_bug.cgi?id=90347
+
+ Reviewed by Gavin Barraclough.
+
+ Previously, if we switched an object from using inline storage to out-of-line
+ storage, we would abandon the inline storage. This would have two main implications:
+ (i) all accesses to the object, even for properties that were previously in inline
+ storage, must now take an extra indirection; and (ii) we waste a non-trivial amount
+ of space since we must allocate additional out-of-line storage to hold properties
+ that would have fit in the inline storage. There's also the copying cost when
+ switching to out-of-line storage - we must copy all inline properties into ouf-of-line
+ storage.
+
+ This patch changes the way that object property storage works so that we can use both
+ inline and out-of-line storage concurrently. This is accomplished by introducing a
+ new notion of property offset. This PropertyOffset is a 32-bit signed integer and it
+ behaves as follows:
+
+ offset == -1: invalid offset, indicating a property that does not exist.
+
+ 0 <= offset <= inlineStorageCapacity: offset into inline storage.
+
+ inlineStorageCapacity < offset: offset into out-of-line storage.
+
+ Because non-final objects don't have inline storage, the only valid PropertyOffsets
+ for those objects' properties are -1 or > inlineStorageCapacity.
+
+ This now means that the decision to use inline or out-of-line storage for an access is
+ made based on the offset, rather than the structure. It also means that any access
+ where the offset is a variable must have an extra branch, unless the type of the
+ object is also known (if it's known to be a non-final object then we can just assert
+ that the offset is >= inlineStorageCapacity).
+
+ This looks like a big Kraken speed-up and a slight V8 speed-up.
+
+ * GNUmakefile.list.am:
+ * JavaScriptCore.vcproj/JavaScriptCore/JavaScriptCore.def:
+ * JavaScriptCore.vcproj/JavaScriptCore/JavaScriptCore.vcproj:
+ * JavaScriptCore.xcodeproj/project.pbxproj:
+ * assembler/ARMv7Assembler.h:
+ (ARMv7Assembler):
+ (JSC::ARMv7Assembler::ldrWide8BitImmediate):
+ (JSC::ARMv7Assembler::replaceWithLoad):
+ (JSC::ARMv7Assembler::replaceWithAddressComputation):
+ * assembler/AbstractMacroAssembler.h:
+ (AbstractMacroAssembler):
+ (ConvertibleLoadLabel):
+ (JSC::AbstractMacroAssembler::ConvertibleLoadLabel::ConvertibleLoadLabel):
+ (JSC::AbstractMacroAssembler::ConvertibleLoadLabel::isSet):
+ (JSC::AbstractMacroAssembler::labelIgnoringWatchpoints):
+ (JSC::AbstractMacroAssembler::replaceWithLoad):
+ (JSC::AbstractMacroAssembler::replaceWithAddressComputation):
+ * assembler/CodeLocation.h:
+ (JSC):
+ (CodeLocationCommon):
+ (CodeLocationConvertibleLoad):
+ (JSC::CodeLocationConvertibleLoad::CodeLocationConvertibleLoad):
+ (JSC::CodeLocationCommon::convertibleLoadAtOffset):
+ * assembler/LinkBuffer.cpp:
+ (JSC::LinkBuffer::finalizeCodeWithDisassembly):
+ * assembler/LinkBuffer.h:
+ (LinkBuffer):
+ (JSC::LinkBuffer::locationOf):
+ * assembler/MacroAssemblerARMv7.h:
+ (MacroAssemblerARMv7):
+ (JSC::MacroAssemblerARMv7::convertibleLoadPtr):
+ * assembler/MacroAssemblerX86.h:
+ (JSC::MacroAssemblerX86::convertibleLoadPtr):
+ (MacroAssemblerX86):
+ * assembler/MacroAssemblerX86_64.h:
+ (JSC::MacroAssemblerX86_64::convertibleLoadPtr):
+ (MacroAssemblerX86_64):
+ * assembler/RepatchBuffer.h:
+ (RepatchBuffer):
+ (JSC::RepatchBuffer::replaceWithLoad):
+ (JSC::RepatchBuffer::replaceWithAddressComputation):
+ (JSC::RepatchBuffer::setLoadInstructionIsActive):
+ * assembler/X86Assembler.h:
+ (JSC::X86Assembler::replaceWithLoad):
+ (X86Assembler):
+ (JSC::X86Assembler::replaceWithAddressComputation):
+ * bytecode/CodeBlock.cpp:
+ (JSC::CodeBlock::printGetByIdOp):
+ (JSC::CodeBlock::dump):
+ (JSC::CodeBlock::finalizeUnconditionally):
+ * bytecode/GetByIdStatus.cpp:
+ (JSC::GetByIdStatus::computeFromLLInt):
+ (JSC::GetByIdStatus::computeForChain):
+ (JSC::GetByIdStatus::computeFor):
+ * bytecode/GetByIdStatus.h:
+ (JSC::GetByIdStatus::GetByIdStatus):
+ (JSC::GetByIdStatus::offset):
+ (GetByIdStatus):
+ * bytecode/Opcode.h:
+ (JSC):
+ (JSC::padOpcodeName):
+ * bytecode/PutByIdStatus.cpp:
+ (JSC::PutByIdStatus::computeFromLLInt):
+ (JSC::PutByIdStatus::computeFor):
+ * bytecode/PutByIdStatus.h:
+ (JSC::PutByIdStatus::PutByIdStatus):
+ (JSC::PutByIdStatus::offset):
+ (PutByIdStatus):
+ * bytecode/ResolveGlobalStatus.cpp:
+ (JSC):
+ (JSC::computeForStructure):
+ * bytecode/ResolveGlobalStatus.h:
+ (JSC::ResolveGlobalStatus::ResolveGlobalStatus):
+ (JSC::ResolveGlobalStatus::offset):
+ (ResolveGlobalStatus):
+ * bytecode/StructureSet.h:
+ (StructureSet):
+ * bytecode/StructureStubInfo.h:
+ * dfg/DFGByteCodeParser.cpp:
+ (ByteCodeParser):
+ (JSC::DFG::ByteCodeParser::handleGetByOffset):
+ (JSC::DFG::ByteCodeParser::handleGetById):
+ (JSC::DFG::ByteCodeParser::parseBlock):
+ * dfg/DFGCapabilities.h:
+ (JSC::DFG::canCompileOpcode):
+ * dfg/DFGJITCompiler.cpp:
+ (JSC::DFG::JITCompiler::link):
+ * dfg/DFGJITCompiler.h:
+ (JSC::DFG::PropertyAccessRecord::PropertyAccessRecord):
+ (PropertyAccessRecord):
+ * dfg/DFGRepatch.cpp:
+ (JSC::DFG::dfgRepatchByIdSelfAccess):
+ (JSC::DFG::generateProtoChainAccessStub):
+ (JSC::DFG::tryCacheGetByID):
+ (JSC::DFG::tryBuildGetByIDList):
+ (JSC::DFG::tryBuildGetByIDProtoList):
+ (JSC::DFG::emitPutReplaceStub):
+ (JSC::DFG::emitPutTransitionStub):
+ (JSC::DFG::tryCachePutByID):
+ (JSC::DFG::tryBuildPutByIdList):
+ * dfg/DFGSpeculativeJIT.h:
+ (JSC::DFG::SpeculativeJIT::emitAllocateBasicJSObject):
+ * dfg/DFGSpeculativeJIT32_64.cpp:
+ (JSC::DFG::SpeculativeJIT::cachedGetById):
+ (JSC::DFG::SpeculativeJIT::cachedPutById):
+ (JSC::DFG::SpeculativeJIT::compile):
+ * dfg/DFGSpeculativeJIT64.cpp:
+ (JSC::DFG::SpeculativeJIT::cachedGetById):
+ (JSC::DFG::SpeculativeJIT::cachedPutById):
+ (JSC::DFG::SpeculativeJIT::compile):
+ * heap/MarkStack.cpp:
+ (JSC::visitChildren):
+ * interpreter/Interpreter.cpp:
+ (JSC::Interpreter::tryCacheGetByID):
+ (JSC::Interpreter::privateExecute):
+ * jit/JIT.cpp:
+ (JSC::JIT::privateCompileMainPass):
+ (JSC::JIT::privateCompileSlowCases):
+ (JSC::PropertyStubCompilationInfo::copyToStubInfo):
+ * jit/JIT.h:
+ (JSC::PropertyStubCompilationInfo::PropertyStubCompilationInfo):
+ (JSC::JIT::compileGetByIdProto):
+ (JSC::JIT::compileGetByIdSelfList):
+ (JSC::JIT::compileGetByIdProtoList):
+ (JSC::JIT::compileGetByIdChainList):
+ (JSC::JIT::compileGetByIdChain):
+ (JSC::JIT::compilePutByIdTransition):
+ (JIT):
+ * jit/JITInlineMethods.h:
+ (JSC::JIT::emitAllocateBasicJSObject):
+ * jit/JITOpcodes.cpp:
+ (JSC::JIT::emit_op_resolve_global):
+ * jit/JITOpcodes32_64.cpp:
+ (JSC::JIT::emit_op_resolve_global):
+ * jit/JITPropertyAccess.cpp:
+ (JSC::JIT::compileGetDirectOffset):
+ (JSC::JIT::emit_op_method_check):
+ (JSC::JIT::compileGetByIdHotPath):
+ (JSC::JIT::emit_op_put_by_id):
+ (JSC::JIT::compilePutDirectOffset):
+ (JSC::JIT::privateCompilePutByIdTransition):
+ (JSC::JIT::patchGetByIdSelf):
+ (JSC::JIT::patchPutByIdReplace):
+ (JSC::JIT::privateCompileGetByIdProto):
+ (JSC::JIT::privateCompileGetByIdSelfList):
+ (JSC::JIT::privateCompileGetByIdProtoList):
+ (JSC::JIT::privateCompileGetByIdChainList):
+ (JSC::JIT::privateCompileGetByIdChain):
+ * jit/JITPropertyAccess32_64.cpp:
+ (JSC::JIT::emit_op_method_check):
+ (JSC::JIT::compileGetByIdHotPath):
+ (JSC::JIT::emit_op_put_by_id):
+ (JSC::JIT::compilePutDirectOffset):
+ (JSC::JIT::compileGetDirectOffset):
+ (JSC::JIT::privateCompilePutByIdTransition):
+ (JSC::JIT::patchGetByIdSelf):
+ (JSC::JIT::patchPutByIdReplace):
+ (JSC::JIT::privateCompileGetByIdProto):
+ (JSC::JIT::privateCompileGetByIdSelfList):
+ (JSC::JIT::privateCompileGetByIdProtoList):
+ (JSC::JIT::privateCompileGetByIdChainList):
+ (JSC::JIT::privateCompileGetByIdChain):
+ (JSC::JIT::emit_op_get_by_pname):
+ * jit/JITStubs.cpp:
+ (JSC::JITThunks::tryCacheGetByID):
+ (JSC::DEFINE_STUB_FUNCTION):
+ * llint/LLIntSlowPaths.cpp:
+ (JSC::LLInt::LLINT_SLOW_PATH_DECL):
+ * llint/LowLevelInterpreter.asm:
+ * llint/LowLevelInterpreter32_64.asm:
+ * llint/LowLevelInterpreter64.asm:
+ * offlineasm/x86.rb:
+ * runtime/JSGlobalObject.h:
+ (JSGlobalObject):
+ (JSC::JSGlobalObject::functionNameOffset):
+ * runtime/JSObject.cpp:
+ (JSC::JSObject::visitChildren):
+ (JSC):
+ (JSC::JSFinalObject::visitChildren):
+ (JSC::JSObject::put):
+ (JSC::JSObject::deleteProperty):
+ (JSC::JSObject::getPropertySpecificValue):
+ (JSC::JSObject::removeDirect):
+ (JSC::JSObject::growOutOfLineStorage):
+ (JSC::JSObject::getOwnPropertyDescriptor):
+ * runtime/JSObject.h:
+ (JSObject):
+ (JSC::JSObject::getDirect):
+ (JSC::JSObject::getDirectLocation):
+ (JSC::JSObject::hasInlineStorage):
+ (JSC::JSObject::inlineStorageUnsafe):
+ (JSC::JSObject::inlineStorage):
+ (JSC::JSObject::outOfLineStorage):
+ (JSC::JSObject::locationForOffset):
+ (JSC::JSObject::offsetForLocation):
+ (JSC::JSObject::getDirectOffset):
+ (JSC::JSObject::putDirectOffset):
+ (JSC::JSObject::putUndefinedAtDirectOffset):
+ (JSC::JSObject::addressOfOutOfLineStorage):
+ (JSC::JSObject::finishCreation):
+ (JSC::JSNonFinalObject::JSNonFinalObject):
+ (JSC::JSNonFinalObject::finishCreation):
+ (JSFinalObject):
+ (JSC::JSFinalObject::finishCreation):
+ (JSC::JSFinalObject::JSFinalObject):
+ (JSC::JSObject::offsetOfOutOfLineStorage):
+ (JSC::JSObject::setOutOfLineStorage):
+ (JSC::JSObject::JSObject):
+ (JSC):
+ (JSC::JSCell::fastGetOwnProperty):
+ (JSC::JSObject::putDirectInternal):
+ (JSC::JSObject::setStructureAndReallocateStorageIfNecessary):
+ (JSC::JSObject::putDirectWithoutTransition):
+ (JSC::offsetRelativeToPatchedStorage):
+ (JSC::indexRelativeToBase):
+ (JSC::offsetRelativeToBase):
+ * runtime/JSPropertyNameIterator.cpp:
+ (JSC::JSPropertyNameIterator::create):
+ * runtime/JSPropertyNameIterator.h:
+ (JSPropertyNameIterator):
+ (JSC::JSPropertyNameIterator::getOffset):
+ (JSC::JSPropertyNameIterator::finishCreation):
+ * runtime/JSValue.cpp:
+ (JSC::JSValue::putToPrimitive):
+ * runtime/Operations.h:
+ (JSC::normalizePrototypeChain):
+ * runtime/Options.cpp:
+ (JSC):
+ (JSC::Options::initialize):
+ * runtime/PropertyMapHashTable.h:
+ (PropertyMapEntry):
+ (JSC::PropertyMapEntry::PropertyMapEntry):
+ (PropertyTable):
+ (JSC::PropertyTable::PropertyTable):
+ (JSC::PropertyTable::getDeletedOffset):
+ (JSC::PropertyTable::addDeletedOffset):
+ (JSC::PropertyTable::nextOffset):
+ (JSC):
+ (JSC::PropertyTable::sizeInMemory):
+ * runtime/PropertyOffset.h: Added.
+ (JSC):
+ (JSC::checkOffset):
+ (JSC::validateOffset):
+ (JSC::isValidOffset):
+ (JSC::isInlineOffset):
+ (JSC::isOutOfLineOffset):
+ (JSC::offsetInInlineStorage):
+ (JSC::offsetInOutOfLineStorage):
+ (JSC::offsetInRespectiveStorage):
+ (JSC::numberOfOutOfLineSlotsForLastOffset):
+ (JSC::numberOfSlotsForLastOffset):
+ (JSC::nextPropertyOffsetFor):
+ (JSC::firstPropertyOffsetFor):
+ * runtime/PropertySlot.h:
+ (JSC::PropertySlot::cachedOffset):
+ (JSC::PropertySlot::setValue):
+ (JSC::PropertySlot::setCacheableGetterSlot):
+ (JSC::PropertySlot::clearOffset):
+ * runtime/PutPropertySlot.h:
+ (JSC::PutPropertySlot::setExistingProperty):
+ (JSC::PutPropertySlot::setNewProperty):
+ (JSC::PutPropertySlot::cachedOffset):
+ (PutPropertySlot):
+ * runtime/Structure.cpp:
+ (JSC::Structure::Structure):
+ (JSC::Structure::materializePropertyMap):
+ (JSC::nextOutOfLineStorageCapacity):
+ (JSC::Structure::growOutOfLineCapacity):
+ (JSC::Structure::suggestedNewOutOfLineStorageCapacity):
+ (JSC::Structure::addPropertyTransitionToExistingStructure):
+ (JSC::Structure::addPropertyTransition):
+ (JSC::Structure::removePropertyTransition):
+ (JSC::Structure::flattenDictionaryStructure):
+ (JSC::Structure::addPropertyWithoutTransition):
+ (JSC::Structure::removePropertyWithoutTransition):
+ (JSC::Structure::copyPropertyTableForPinning):
+ (JSC::Structure::get):
+ (JSC::Structure::putSpecificValue):
+ (JSC::Structure::remove):
+ * runtime/Structure.h:
+ (Structure):
+ (JSC::Structure::putWillGrowOutOfLineStorage):
+ (JSC::Structure::previousID):
+ (JSC::Structure::outOfLineCapacity):
+ (JSC::Structure::outOfLineSizeForKnownFinalObject):
+ (JSC::Structure::outOfLineSizeForKnownNonFinalObject):
+ (JSC::Structure::outOfLineSize):
+ (JSC::Structure::hasInlineStorage):
+ (JSC::Structure::inlineCapacity):
+ (JSC::Structure::inlineSizeForKnownFinalObject):
+ (JSC::Structure::inlineSize):
+ (JSC::Structure::totalStorageSize):
+ (JSC::Structure::totalStorageCapacity):
+ (JSC::Structure::firstValidOffset):
+ (JSC::Structure::lastValidOffset):
+ (JSC::Structure::isValidOffset):
+ (JSC::Structure::isEmpty):
+ (JSC::Structure::transitionCount):
+ (JSC::Structure::get):
+
2012-07-05 Oliver Hunt <oliver@apple.com>
JSObjectCallAsFunction should thisConvert the provided thisObject
diff --git a/Source/JavaScriptCore/GNUmakefile.list.am b/Source/JavaScriptCore/GNUmakefile.list.am
index 26dc79e..7619f64 100644
--- a/Source/JavaScriptCore/GNUmakefile.list.am
+++ b/Source/JavaScriptCore/GNUmakefile.list.am
@@ -582,6 +582,7 @@
Source/JavaScriptCore/runtime/PropertyName.h \
Source/JavaScriptCore/runtime/PropertyNameArray.cpp \
Source/JavaScriptCore/runtime/PropertyNameArray.h \
+ Source/JavaScriptCore/runtime/PropertyOffset.h \
Source/JavaScriptCore/runtime/PropertySlot.cpp \
Source/JavaScriptCore/runtime/PropertySlot.h \
Source/JavaScriptCore/runtime/Protect.h \
diff --git a/Source/JavaScriptCore/JavaScriptCore.vcproj/JavaScriptCore/JavaScriptCore.def b/Source/JavaScriptCore/JavaScriptCore.vcproj/JavaScriptCore/JavaScriptCore.def
index 6fc1d43..c50013a 100755
--- a/Source/JavaScriptCore/JavaScriptCore.vcproj/JavaScriptCore/JavaScriptCore.def
+++ b/Source/JavaScriptCore/JavaScriptCore.vcproj/JavaScriptCore/JavaScriptCore.def
@@ -61,9 +61,9 @@
?addBytes@SHA1@WTF@@QAEXPBEI@Z
?addCurrentThread@MachineThreads@JSC@@QAEXXZ
?addFinalizer@Heap@JSC@@QAEXPAVJSCell@2@P6AX0@Z@Z
- ?addPropertyTransition@Structure@JSC@@SAPAV12@AAVJSGlobalData@2@PAV12@VPropertyName@2@IPAVJSCell@2@AAI@Z
- ?addPropertyTransitionToExistingStructure@Structure@JSC@@SAPAV12@PAV12@VPropertyName@2@IPAVJSCell@2@AAI@Z
- ?addPropertyWithoutTransition@Structure@JSC@@QAEIAAVJSGlobalData@2@VPropertyName@2@IPAVJSCell@2@@Z
+ ?addPropertyTransition@Structure@JSC@@SAPAV12@AAVJSGlobalData@2@PAV12@VPropertyName@2@IPAVJSCell@2@AAH@Z
+ ?addPropertyTransitionToExistingStructure@Structure@JSC@@SAPAV12@PAV12@VPropertyName@2@IPAVJSCell@2@AAH@Z
+ ?addPropertyWithoutTransition@Structure@JSC@@QAEHAAVJSGlobalData@2@VPropertyName@2@IPAVJSCell@2@@Z
?addSlowCase@Identifier@JSC@@CA?AV?$PassRefPtr@VStringImpl@WTF@@@WTF@@PAVExecState@2@PAVStringImpl@4@@Z
?addSlowCase@Identifier@JSC@@CA?AV?$PassRefPtr@VStringImpl@WTF@@@WTF@@PAVJSGlobalData@2@PAVStringImpl@4@@Z
?addStaticGlobals@JSGlobalObject@JSC@@IAEXPAUGlobalPropertyInfo@12@H@Z
@@ -192,7 +192,6 @@
?from@Identifier@JSC@@SA?AV12@PAVExecState@2@I@Z
?functionGetter@PropertySlot@JSC@@ABE?AVJSValue@2@PAVExecState@2@@Z
?functionName@DebuggerCallFrame@JSC@@QBEPBVUString@2@XZ
- ?get@Structure@JSC@@QAEIAAVJSGlobalData@2@VPropertyName@2@AAIAAPAVJSCell@2@@Z
?getCalculatedDisplayName@JSC@@YA?AVUString@1@PAVExecState@1@PAVJSObject@1@@Z
?getCallData@JSCell@JSC@@SA?AW4CallType@2@PAV12@AATCallData@2@@Z
?getCallableObjectSlow@JSC@@YAPAVJSCell@1@PAV21@@Z
@@ -211,11 +210,12 @@
?getStackTrace@Interpreter@JSC@@SAXPAVJSGlobalData@2@AAV?$Vector@UStackFrame@JSC@@$0A@@WTF@@@Z
?getString@JSCell@JSC@@QBE?AVUString@2@PAVExecState@2@@Z
?getString@JSCell@JSC@@QBE_NPAVExecState@2@AAVUString@2@@Z
+ ?get@Structure@JSC@@QAEHAAVJSGlobalData@2@VPropertyName@2@AAIAAPAVJSCell@2@@Z
?getter@PropertyDescriptor@JSC@@QBE?AVJSValue@2@XZ
?globalExec@JSGlobalObject@JSC@@QAEPAVExecState@2@XZ
?globalObjectCount@Heap@JSC@@QAEIXZ
+ ?growOutOfLineStorage@JSObject@JSC@@QAEPAV?$WriteBarrierBase@W4Unknown@JSC@@@2@AAVJSGlobalData@2@II@Z
?grow@HandleSet@JSC@@AAEXXZ
- ?growPropertyStorage@JSObject@JSC@@QAEPAV?$WriteBarrierBase@W4Unknown@JSC@@@2@AAVJSGlobalData@2@II@Z
?hasInstance@JSObject@JSC@@SA_NPAV12@PAVExecState@2@VJSValue@2@2@Z
?hasProperty@JSObject@JSC@@QBE_NPAVExecState@2@I@Z
?hasProperty@JSObject@JSC@@QBE_NPAVExecState@2@VPropertyName@2@@Z
@@ -328,7 +328,7 @@
?stopProfiling@Profiler@JSC@@QAE?AV?$PassRefPtr@VProfile@JSC@@@WTF@@PAVExecState@2@ABVUString@2@@Z
?stopSampling@JSGlobalData@JSC@@QAEXXZ
?substringSharingImpl@UString@JSC@@QBE?AV12@II@Z
- ?suggestedNewPropertyStorageSize@Structure@JSC@@QAEIXZ
+ ?suggestedNewOutOfLineStorageCapacity@Structure@JSC@@QAEIXZ
?sweeper@Heap@JSC@@QAEPAVIncrementalSweeper@2@XZ
?synthesizePrototype@JSValue@JSC@@QBEPAVJSObject@2@PAVExecState@2@@Z
?thisObject@DebuggerCallFrame@JSC@@QBEPAVJSObject@2@XZ
diff --git a/Source/JavaScriptCore/JavaScriptCore.vcproj/JavaScriptCore/JavaScriptCore.vcproj b/Source/JavaScriptCore/JavaScriptCore.vcproj/JavaScriptCore/JavaScriptCore.vcproj
index 534f8bf..a0e32f8 100644
--- a/Source/JavaScriptCore/JavaScriptCore.vcproj/JavaScriptCore/JavaScriptCore.vcproj
+++ b/Source/JavaScriptCore/JavaScriptCore.vcproj/JavaScriptCore/JavaScriptCore.vcproj
@@ -1094,6 +1094,10 @@
>
</File>
<File
+ RelativePath="..\..\runtime\PropertyOffset.h"
+ >
+ </File>
+ <File
RelativePath="..\..\runtime\PropertySlot.cpp"
>
</File>
diff --git a/Source/JavaScriptCore/JavaScriptCore.xcodeproj/project.pbxproj b/Source/JavaScriptCore/JavaScriptCore.xcodeproj/project.pbxproj
index 7b3454c..12a310d 100644
--- a/Source/JavaScriptCore/JavaScriptCore.xcodeproj/project.pbxproj
+++ b/Source/JavaScriptCore/JavaScriptCore.xcodeproj/project.pbxproj
@@ -223,6 +223,7 @@
0FF427651591A1CE004CB9FF /* DFGDisassembler.h in Headers */ = {isa = PBXBuildFile; fileRef = 0FF427621591A1C9004CB9FF /* DFGDisassembler.h */; settings = {ATTRIBUTES = (Private, ); }; };
0FF42771159275D5004CB9FF /* ResolveGlobalStatus.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 0FF4276E159275D2004CB9FF /* ResolveGlobalStatus.cpp */; };
0FF42772159275D8004CB9FF /* ResolveGlobalStatus.h in Headers */ = {isa = PBXBuildFile; fileRef = 0FF4276F159275D2004CB9FF /* ResolveGlobalStatus.h */; settings = {ATTRIBUTES = (Private, ); }; };
+ 0FF7168C15A3B235008F5DAA /* PropertyOffset.h in Headers */ = {isa = PBXBuildFile; fileRef = 0FF7168A15A3B231008F5DAA /* PropertyOffset.h */; settings = {ATTRIBUTES = (Private, ); }; };
0FF922D414F46B410041A24E /* LLIntOffsetsExtractor.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 0F4680A114BA7F8200BFE272 /* LLIntOffsetsExtractor.cpp */; };
0FFFC95714EF90A000C72532 /* DFGCFAPhase.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 0FFFC94B14EF909500C72532 /* DFGCFAPhase.cpp */; };
0FFFC95814EF90A200C72532 /* DFGCFAPhase.h in Headers */ = {isa = PBXBuildFile; fileRef = 0FFFC94C14EF909500C72532 /* DFGCFAPhase.h */; settings = {ATTRIBUTES = (Private, ); }; };
@@ -957,6 +958,7 @@
0FF427621591A1C9004CB9FF /* DFGDisassembler.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = DFGDisassembler.h; path = dfg/DFGDisassembler.h; sourceTree = "<group>"; };
0FF4276E159275D2004CB9FF /* ResolveGlobalStatus.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = ResolveGlobalStatus.cpp; sourceTree = "<group>"; };
0FF4276F159275D2004CB9FF /* ResolveGlobalStatus.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ResolveGlobalStatus.h; sourceTree = "<group>"; };
+ 0FF7168A15A3B231008F5DAA /* PropertyOffset.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = PropertyOffset.h; sourceTree = "<group>"; };
0FF922CF14F46B130041A24E /* JSCLLIntOffsetsExtractor */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = JSCLLIntOffsetsExtractor; sourceTree = BUILT_PRODUCTS_DIR; };
0FFFC94B14EF909500C72532 /* DFGCFAPhase.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = DFGCFAPhase.cpp; path = dfg/DFGCFAPhase.cpp; sourceTree = "<group>"; };
0FFFC94C14EF909500C72532 /* DFGCFAPhase.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = DFGCFAPhase.h; path = dfg/DFGCFAPhase.h; sourceTree = "<group>"; };
@@ -2107,6 +2109,7 @@
86158AB2155C8B3F00B45C9C /* PropertyName.h */,
65400C0F0A69BAF200509887 /* PropertyNameArray.cpp */,
65400C100A69BAF200509887 /* PropertyNameArray.h */,
+ 0FF7168A15A3B231008F5DAA /* PropertyOffset.h */,
65621E6B089E859700760F35 /* PropertySlot.cpp */,
65621E6C089E859700760F35 /* PropertySlot.h */,
65C02FBB0637462A003E7EE6 /* Protect.h */,
@@ -2811,6 +2814,7 @@
0FF4274B158EBE91004CB9FF /* udis86.h in Headers */,
0FF427651591A1CE004CB9FF /* DFGDisassembler.h in Headers */,
0FF42772159275D8004CB9FF /* ResolveGlobalStatus.h in Headers */,
+ 0FF7168C15A3B235008F5DAA /* PropertyOffset.h in Headers */,
);
runOnlyForDeploymentPostprocessing = 0;
};
diff --git a/Source/JavaScriptCore/assembler/ARMv7Assembler.h b/Source/JavaScriptCore/assembler/ARMv7Assembler.h
index 81977e2..eef0ba8 100644
--- a/Source/JavaScriptCore/assembler/ARMv7Assembler.h
+++ b/Source/JavaScriptCore/assembler/ARMv7Assembler.h
@@ -1018,6 +1018,12 @@
else
m_formatter.twoWordOp12Reg4Reg4Imm12(OP_LDR_imm_T3, rn, rt, imm.getUInt12());
}
+
+ ALWAYS_INLINE void ldrWide8BitImmediate(RegisterID rt, RegisterID rn, uint8_t immediate)
+ {
+ ASSERT(rn != ARMRegisters::pc);
+ m_formatter.twoWordOp12Reg4Reg4Imm12(OP_LDR_imm_T3, rn, rt, immediate);
+ }
ALWAYS_INLINE void ldrCompact(RegisterID rt, RegisterID rn, ARMThumbImmediate imm)
{
@@ -2117,6 +2123,46 @@
{
return 6;
}
+
+ static void replaceWithLoad(void* instructionStart)
+ {
+ ASSERT(!(bitwise_cast<uintptr_t>(instructionStart) & 1));
+ uint16_t* ptr = reinterpret_cast<uint16_t*>(instructionStart);
+ switch (ptr[0] & 0xFFF0) {
+ case OP_LDR_imm_T3:
+ break;
+ case OP_ADD_imm_T3:
+ ASSERT(!(ptr[1] & 0xF000));
+ ptr[0] &= 0x000F;
+ ptr[0] |= OP_LDR_imm_T3;
+ ptr[1] |= (ptr[1] & 0x0F00) << 4;
+ ptr[1] &= 0xF0FF;
+ break;
+ default:
+ ASSERT_NOT_REACHED();
+ }
+ cacheFlush(ptr, sizeof(uint16_t) * 2);
+ }
+
+ static void replaceWithAddressComputation(void* instructionStart)
+ {
+ ASSERT(!(bitwise_cast<uintptr_t>(instructionStart) & 1));
+ uint16_t* ptr = reinterpret_cast<uint16_t*>(instructionStart);
+ switch (ptr[0] & 0xFFF0) {
+ case OP_LDR_imm_T3:
+ ASSERT(!(ptr[1] & 0x0F00));
+ ptr[0] &= 0x000F;
+ ptr[0] |= OP_ADD_imm_T3;
+ ptr[1] |= (ptr[1] & 0xF000) >> 4;
+ ptr[1] &= 0x0FFF;
+ break;
+ case OP_ADD_imm_T3:
+ break;
+ default:
+ ASSERT_NOT_REACHED();
+ }
+ cacheFlush(ptr, sizeof(uint16_t) * 2);
+ }
unsigned debugOffset() { return m_formatter.debugOffset(); }
diff --git a/Source/JavaScriptCore/assembler/AbstractMacroAssembler.h b/Source/JavaScriptCore/assembler/AbstractMacroAssembler.h
index 0080446..a24f757 100644
--- a/Source/JavaScriptCore/assembler/AbstractMacroAssembler.h
+++ b/Source/JavaScriptCore/assembler/AbstractMacroAssembler.h
@@ -295,6 +295,36 @@
private:
AssemblerLabel m_label;
};
+
+ // ConvertibleLoadLabel:
+ //
+ // A ConvertibleLoadLabel records a loadPtr instruction that can be patched to an addPtr
+ // so that:
+ //
+ // loadPtr(Address(a, i), b)
+ //
+ // becomes:
+ //
+ // addPtr(TrustedImmPtr(i), a, b)
+ class ConvertibleLoadLabel {
+ template<class TemplateAssemblerType>
+ friend class AbstractMacroAssembler;
+ friend class LinkBuffer;
+
+ public:
+ ConvertibleLoadLabel()
+ {
+ }
+
+ ConvertibleLoadLabel(AbstractMacroAssembler<AssemblerType>* masm)
+ : m_label(masm->m_assembler.labelIgnoringWatchpoints())
+ {
+ }
+
+ bool isSet() const { return m_label.isSet(); }
+ private:
+ AssemblerLabel m_label;
+ };
// DataLabelPtr:
//
@@ -562,6 +592,11 @@
result.m_label = m_assembler.labelIgnoringWatchpoints();
return result;
}
+#else
+ Label labelIgnoringWatchpoints()
+ {
+ return label();
+ }
#endif
Label label()
@@ -672,6 +707,16 @@
{
return AssemblerType::readPointer(dataLabelPtr.dataLocation());
}
+
+ static void replaceWithLoad(CodeLocationConvertibleLoad label)
+ {
+ AssemblerType::replaceWithLoad(label.dataLocation());
+ }
+
+ static void replaceWithAddressComputation(CodeLocationConvertibleLoad label)
+ {
+ AssemblerType::replaceWithAddressComputation(label.dataLocation());
+ }
};
} // namespace JSC
diff --git a/Source/JavaScriptCore/assembler/CodeLocation.h b/Source/JavaScriptCore/assembler/CodeLocation.h
index 9500b1e..86d1f2b 100644
--- a/Source/JavaScriptCore/assembler/CodeLocation.h
+++ b/Source/JavaScriptCore/assembler/CodeLocation.h
@@ -40,6 +40,7 @@
class CodeLocationDataLabelCompact;
class CodeLocationDataLabel32;
class CodeLocationDataLabelPtr;
+class CodeLocationConvertibleLoad;
// The CodeLocation* types are all pretty much do-nothing wrappers around
// CodePtr (or MacroAssemblerCodePtr, to give it its full name). These
@@ -62,6 +63,7 @@
CodeLocationDataLabelPtr dataLabelPtrAtOffset(int offset);
CodeLocationDataLabel32 dataLabel32AtOffset(int offset);
CodeLocationDataLabelCompact dataLabelCompactAtOffset(int offset);
+ CodeLocationConvertibleLoad convertibleLoadAtOffset(int offset);
protected:
CodeLocationCommon()
@@ -146,6 +148,15 @@
: CodeLocationCommon(MacroAssemblerCodePtr(location)) {}
};
+class CodeLocationConvertibleLoad : public CodeLocationCommon {
+public:
+ CodeLocationConvertibleLoad() { }
+ explicit CodeLocationConvertibleLoad(MacroAssemblerCodePtr location)
+ : CodeLocationCommon(location) { }
+ explicit CodeLocationConvertibleLoad(void* location)
+ : CodeLocationCommon(MacroAssemblerCodePtr(location)) { }
+};
+
inline CodeLocationInstruction CodeLocationCommon::instructionAtOffset(int offset)
{
ASSERT_VALID_CODE_OFFSET(offset);
@@ -194,6 +205,12 @@
return CodeLocationDataLabelCompact(reinterpret_cast<char*>(dataLocation()) + offset);
}
+inline CodeLocationConvertibleLoad CodeLocationCommon::convertibleLoadAtOffset(int offset)
+{
+ ASSERT_VALID_CODE_OFFSET(offset);
+ return CodeLocationConvertibleLoad(reinterpret_cast<char*>(dataLocation()) + offset);
+}
+
} // namespace JSC
#endif // ENABLE(ASSEMBLER)
diff --git a/Source/JavaScriptCore/assembler/LinkBuffer.cpp b/Source/JavaScriptCore/assembler/LinkBuffer.cpp
index b21b527..0176e43 100644
--- a/Source/JavaScriptCore/assembler/LinkBuffer.cpp
+++ b/Source/JavaScriptCore/assembler/LinkBuffer.cpp
@@ -54,7 +54,7 @@
dataLog(" Code at [%p, %p):\n", result.code().executableAddress(), static_cast<char*>(result.code().executableAddress()) + result.size());
if (!tryToDisassemble(result.code(), m_size, " ", WTF::dataFile()))
- dataLog(" <no disassembly available>");
+ dataLog(" <no disassembly available>\n");
return result;
}
diff --git a/Source/JavaScriptCore/assembler/LinkBuffer.h b/Source/JavaScriptCore/assembler/LinkBuffer.h
index a58d6af..484d3a7 100644
--- a/Source/JavaScriptCore/assembler/LinkBuffer.h
+++ b/Source/JavaScriptCore/assembler/LinkBuffer.h
@@ -69,6 +69,7 @@
typedef MacroAssembler::DataLabelCompact DataLabelCompact;
typedef MacroAssembler::DataLabel32 DataLabel32;
typedef MacroAssembler::DataLabelPtr DataLabelPtr;
+ typedef MacroAssembler::ConvertibleLoadLabel ConvertibleLoadLabel;
#if ENABLE(BRANCH_COMPACTION)
typedef MacroAssembler::LinkRecord LinkRecord;
typedef MacroAssembler::JumpLinkType JumpLinkType;
@@ -180,6 +181,11 @@
return CodeLocationDataLabelCompact(MacroAssembler::getLinkerAddress(code(), applyOffset(label.m_label)));
}
+ CodeLocationConvertibleLoad locationOf(ConvertibleLoadLabel label)
+ {
+ return CodeLocationConvertibleLoad(MacroAssembler::getLinkerAddress(code(), applyOffset(label.m_label)));
+ }
+
// This method obtains the return address of the call, given as an offset from
// the start of the code.
unsigned returnAddressOffset(Call call)
diff --git a/Source/JavaScriptCore/assembler/MacroAssemblerARMv7.h b/Source/JavaScriptCore/assembler/MacroAssemblerARMv7.h
index 6c0feff..8e8b753 100644
--- a/Source/JavaScriptCore/assembler/MacroAssemblerARMv7.h
+++ b/Source/JavaScriptCore/assembler/MacroAssemblerARMv7.h
@@ -600,6 +600,14 @@
move(TrustedImmPtr(address), addressTempRegister);
m_assembler.ldr(dest, addressTempRegister, ARMThumbImmediate::makeUInt16(0));
}
+
+ ConvertibleLoadLabel convertibleLoadPtr(Address address, RegisterID dest)
+ {
+ ConvertibleLoadLabel result(this);
+ ASSERT(address.offset >=0 && address.offset <= 255);
+ m_assembler.ldrWide8BitImmediate(dest, address.base, address.offset);
+ return result;
+ }
void load8(ImplicitAddress address, RegisterID dest)
{
diff --git a/Source/JavaScriptCore/assembler/MacroAssemblerX86.h b/Source/JavaScriptCore/assembler/MacroAssemblerX86.h
index 3ea40c9..45de813 100644
--- a/Source/JavaScriptCore/assembler/MacroAssemblerX86.h
+++ b/Source/JavaScriptCore/assembler/MacroAssemblerX86.h
@@ -89,6 +89,13 @@
m_assembler.movl_mr(address, dest);
}
+ ConvertibleLoadLabel convertibleLoadPtr(Address address, RegisterID dest)
+ {
+ ConvertibleLoadLabel result = ConvertibleLoadLabel(this);
+ m_assembler.movl_mr(address.offset, address.base, dest);
+ return result;
+ }
+
void addDouble(AbsoluteAddress address, FPRegisterID dest)
{
m_assembler.addsd_mr(address.m_ptr, dest);
diff --git a/Source/JavaScriptCore/assembler/MacroAssemblerX86_64.h b/Source/JavaScriptCore/assembler/MacroAssemblerX86_64.h
index fa95b33..1fb574b 100644
--- a/Source/JavaScriptCore/assembler/MacroAssemblerX86_64.h
+++ b/Source/JavaScriptCore/assembler/MacroAssemblerX86_64.h
@@ -258,6 +258,13 @@
m_assembler.movq_mr(address.offset, address.base, dest);
}
+ ConvertibleLoadLabel convertibleLoadPtr(Address address, RegisterID dest)
+ {
+ ConvertibleLoadLabel result = ConvertibleLoadLabel(this);
+ m_assembler.movq_mr(address.offset, address.base, dest);
+ return result;
+ }
+
void loadPtr(BaseIndex address, RegisterID dest)
{
m_assembler.movq_mr(address.offset, address.base, address.index, address.scale, dest);
diff --git a/Source/JavaScriptCore/assembler/RepatchBuffer.h b/Source/JavaScriptCore/assembler/RepatchBuffer.h
index a87294b..531dda9 100644
--- a/Source/JavaScriptCore/assembler/RepatchBuffer.h
+++ b/Source/JavaScriptCore/assembler/RepatchBuffer.h
@@ -122,6 +122,24 @@
{
relinkNearCallerToTrampoline(returnAddress, CodeLocationLabel(newCalleeFunction));
}
+
+ void replaceWithLoad(CodeLocationConvertibleLoad label)
+ {
+ MacroAssembler::replaceWithLoad(label);
+ }
+
+ void replaceWithAddressComputation(CodeLocationConvertibleLoad label)
+ {
+ MacroAssembler::replaceWithAddressComputation(label);
+ }
+
+ void setLoadInstructionIsActive(CodeLocationConvertibleLoad label, bool isActive)
+ {
+ if (isActive)
+ replaceWithLoad(label);
+ else
+ replaceWithAddressComputation(label);
+ }
private:
void* m_start;
diff --git a/Source/JavaScriptCore/assembler/X86Assembler.h b/Source/JavaScriptCore/assembler/X86Assembler.h
index 9c35be8..cf81332 100644
--- a/Source/JavaScriptCore/assembler/X86Assembler.h
+++ b/Source/JavaScriptCore/assembler/X86Assembler.h
@@ -1839,6 +1839,42 @@
return 5;
}
+ static void replaceWithLoad(void* instructionStart)
+ {
+ uint8_t* ptr = reinterpret_cast<uint8_t*>(instructionStart);
+#if CPU(X86_64)
+ if ((*ptr & ~15) == PRE_REX)
+ ptr++;
+#endif
+ switch (*ptr) {
+ case OP_MOV_GvEv:
+ break;
+ case OP_LEA:
+ *ptr = OP_MOV_GvEv;
+ break;
+ default:
+ ASSERT_NOT_REACHED();
+ }
+ }
+
+ static void replaceWithAddressComputation(void* instructionStart)
+ {
+ uint8_t* ptr = reinterpret_cast<uint8_t*>(instructionStart);
+#if CPU(X86_64)
+ if ((*ptr & ~15) == PRE_REX)
+ ptr++;
+#endif
+ switch (*ptr) {
+ case OP_MOV_GvEv:
+ *ptr = OP_LEA;
+ break;
+ case OP_LEA:
+ break;
+ default:
+ ASSERT_NOT_REACHED();
+ }
+ }
+
static unsigned getCallReturnOffset(AssemblerLabel call)
{
ASSERT(call.isSet());
diff --git a/Source/JavaScriptCore/bytecode/CodeBlock.cpp b/Source/JavaScriptCore/bytecode/CodeBlock.cpp
index a7eabbd..48d0fe7 100644
--- a/Source/JavaScriptCore/bytecode/CodeBlock.cpp
+++ b/Source/JavaScriptCore/bytecode/CodeBlock.cpp
@@ -197,6 +197,9 @@
case op_get_by_id:
op = "get_by_id";
break;
+ case op_get_by_id_out_of_line:
+ op = "get_by_id_out_of_line";
+ break;
case op_get_by_id_self:
op = "get_by_id_self";
break;
@@ -1033,6 +1036,7 @@
break;
}
case op_get_by_id:
+ case op_get_by_id_out_of_line:
case op_get_by_id_self:
case op_get_by_id_proto:
case op_get_by_id_chain:
@@ -1059,6 +1063,10 @@
printPutByIdOp(exec, location, it, "put_by_id");
break;
}
+ case op_put_by_id_out_of_line: {
+ printPutByIdOp(exec, location, it, "put_by_id_out_of_line");
+ break;
+ }
case op_put_by_id_replace: {
printPutByIdOp(exec, location, it, "put_by_id_replace");
break;
@@ -1071,10 +1079,18 @@
printPutByIdOp(exec, location, it, "put_by_id_transition_direct");
break;
}
+ case op_put_by_id_transition_direct_out_of_line: {
+ printPutByIdOp(exec, location, it, "put_by_id_transition_direct_out_of_line");
+ break;
+ }
case op_put_by_id_transition_normal: {
printPutByIdOp(exec, location, it, "put_by_id_transition_normal");
break;
}
+ case op_put_by_id_transition_normal_out_of_line: {
+ printPutByIdOp(exec, location, it, "put_by_id_transition_normal_out_of_line");
+ break;
+ }
case op_put_by_id_generic: {
printPutByIdOp(exec, location, it, "put_by_id_generic");
break;
@@ -2029,7 +2045,9 @@
Instruction* curInstruction = &instructions()[m_propertyAccessInstructions[i]];
switch (interpreter->getOpcodeID(curInstruction[0].u.opcode)) {
case op_get_by_id:
+ case op_get_by_id_out_of_line:
case op_put_by_id:
+ case op_put_by_id_out_of_line:
if (!curInstruction[4].u.structure || Heap::isMarked(curInstruction[4].u.structure.get()))
break;
if (verboseUnlinking)
@@ -2039,6 +2057,8 @@
break;
case op_put_by_id_transition_direct:
case op_put_by_id_transition_normal:
+ case op_put_by_id_transition_direct_out_of_line:
+ case op_put_by_id_transition_normal_out_of_line:
if (Heap::isMarked(curInstruction[4].u.structure.get())
&& Heap::isMarked(curInstruction[6].u.structure.get())
&& Heap::isMarked(curInstruction[7].u.structureChain.get()))
diff --git a/Source/JavaScriptCore/bytecode/GetByIdStatus.cpp b/Source/JavaScriptCore/bytecode/GetByIdStatus.cpp
index a62a43f..cb3e8e8 100644
--- a/Source/JavaScriptCore/bytecode/GetByIdStatus.cpp
+++ b/Source/JavaScriptCore/bytecode/GetByIdStatus.cpp
@@ -48,9 +48,9 @@
unsigned attributesIgnored;
JSCell* specificValue;
- size_t offset = structure->get(
+ PropertyOffset offset = structure->get(
*profiledBlock->globalData(), ident, attributesIgnored, specificValue);
- if (offset == notFound)
+ if (!isValidOffset(offset))
return GetByIdStatus(NoInformation, false);
return GetByIdStatus(Simple, false, StructureSet(structure), offset, specificValue);
@@ -88,7 +88,7 @@
result.m_offset = currentStructure->get(
*profiledBlock->globalData(), ident, attributesIgnored, specificValue);
- if (result.m_offset == notFound)
+ if (!isValidOffset(result.m_offset))
return;
result.m_structureSet.add(structure);
@@ -156,12 +156,12 @@
result.m_offset = structure->get(
*profiledBlock->globalData(), ident, attributesIgnored, specificValue);
- if (result.m_offset != notFound) {
+ if (isValidOffset(result.m_offset)) {
result.m_structureSet.add(structure);
result.m_specificValue = JSValue(specificValue);
}
- if (result.m_offset != notFound)
+ if (isValidOffset(result.m_offset))
ASSERT(result.m_structureSet.size());
break;
}
@@ -176,11 +176,11 @@
unsigned attributesIgnored;
JSCell* specificValue;
- size_t myOffset = structure->get(
+ PropertyOffset myOffset = structure->get(
*profiledBlock->globalData(), ident, attributesIgnored, specificValue);
- if (myOffset == notFound) {
- result.m_offset = notFound;
+ if (!isValidOffset(myOffset)) {
+ result.m_offset = invalidOffset;
break;
}
@@ -188,7 +188,7 @@
result.m_offset = myOffset;
result.m_specificValue = JSValue(specificValue);
} else if (result.m_offset != myOffset) {
- result.m_offset = notFound;
+ result.m_offset = invalidOffset;
break;
} else if (result.m_specificValue != JSValue(specificValue))
result.m_specificValue = JSValue();
@@ -196,7 +196,7 @@
result.m_structureSet.add(structure);
}
- if (result.m_offset != notFound)
+ if (isValidOffset(result.m_offset))
ASSERT(result.m_structureSet.size());
break;
}
@@ -223,11 +223,11 @@
}
default:
- ASSERT(result.m_offset == notFound);
+ ASSERT(!isValidOffset(result.m_offset));
break;
}
- if (result.m_offset == notFound) {
+ if (!isValidOffset(result.m_offset)) {
result.m_state = TakesSlowPath;
result.m_structureSet.clear();
result.m_chain.clear();
diff --git a/Source/JavaScriptCore/bytecode/GetByIdStatus.h b/Source/JavaScriptCore/bytecode/GetByIdStatus.h
index 42eadfd..297ec33 100644
--- a/Source/JavaScriptCore/bytecode/GetByIdStatus.h
+++ b/Source/JavaScriptCore/bytecode/GetByIdStatus.h
@@ -26,6 +26,7 @@
#ifndef GetByIdStatus_h
#define GetByIdStatus_h
+#include "PropertyOffset.h"
#include "StructureSet.h"
#include <wtf/NotFound.h>
@@ -46,13 +47,13 @@
GetByIdStatus()
: m_state(NoInformation)
- , m_offset(notFound)
+ , m_offset(invalidOffset)
{
}
GetByIdStatus(
State state, bool wasSeenInJIT, const StructureSet& structureSet = StructureSet(),
- size_t offset = notFound, JSValue specificValue = JSValue(), Vector<Structure*> chain = Vector<Structure*>())
+ size_t offset = invalidOffset, JSValue specificValue = JSValue(), Vector<Structure*> chain = Vector<Structure*>())
: m_state(state)
, m_structureSet(structureSet)
, m_chain(chain)
@@ -76,7 +77,7 @@
const StructureSet& structureSet() const { return m_structureSet; }
const Vector<Structure*>& chain() const { return m_chain; } // Returns empty vector if this is a direct access.
JSValue specificValue() const { return m_specificValue; } // Returns JSValue() if there is no specific value.
- size_t offset() const { return m_offset; }
+ PropertyOffset offset() const { return m_offset; }
bool wasSeenInJIT() const { return m_wasSeenInJIT; }
@@ -88,7 +89,7 @@
StructureSet m_structureSet;
Vector<Structure*> m_chain;
JSValue m_specificValue;
- size_t m_offset;
+ PropertyOffset m_offset;
bool m_wasSeenInJIT;
};
diff --git a/Source/JavaScriptCore/bytecode/Opcode.h b/Source/JavaScriptCore/bytecode/Opcode.h
index e0cff16..14cefb9 100644
--- a/Source/JavaScriptCore/bytecode/Opcode.h
+++ b/Source/JavaScriptCore/bytecode/Opcode.h
@@ -108,6 +108,7 @@
macro(op_resolve_with_base, 5) /* has value profiling */ \
macro(op_resolve_with_this, 5) /* has value profiling */ \
macro(op_get_by_id, 9) /* has value profiling */ \
+ macro(op_get_by_id_out_of_line, 9) /* has value profiling */ \
macro(op_get_by_id_self, 9) /* has value profiling */ \
macro(op_get_by_id_proto, 9) /* has value profiling */ \
macro(op_get_by_id_chain, 9) /* has value profiling */ \
@@ -122,9 +123,12 @@
macro(op_get_string_length, 9) /* has value profiling */ \
macro(op_get_arguments_length, 4) \
macro(op_put_by_id, 9) \
+ macro(op_put_by_id_out_of_line, 9) \
macro(op_put_by_id_transition, 9) \
macro(op_put_by_id_transition_direct, 9) \
+ macro(op_put_by_id_transition_direct_out_of_line, 9) \
macro(op_put_by_id_transition_normal, 9) \
+ macro(op_put_by_id_transition_normal_out_of_line, 9) \
macro(op_put_by_id_replace, 9) \
macro(op_put_by_id_generic, 9) \
macro(op_del_by_id, 4) \
diff --git a/Source/JavaScriptCore/bytecode/PutByIdStatus.cpp b/Source/JavaScriptCore/bytecode/PutByIdStatus.cpp
index 3715606..ce25a52 100644
--- a/Source/JavaScriptCore/bytecode/PutByIdStatus.cpp
+++ b/Source/JavaScriptCore/bytecode/PutByIdStatus.cpp
@@ -43,12 +43,13 @@
Structure* structure = instruction[4].u.structure.get();
if (!structure)
- return PutByIdStatus(NoInformation, 0, 0, 0, notFound);
+ return PutByIdStatus(NoInformation, 0, 0, 0, invalidOffset);
- if (instruction[0].u.opcode == llint_op_put_by_id) {
- size_t offset = structure->get(*profiledBlock->globalData(), ident);
- if (offset == notFound)
- return PutByIdStatus(NoInformation, 0, 0, 0, notFound);
+ if (instruction[0].u.opcode == llint_op_put_by_id
+ || instruction[0].u.opcode == llint_op_put_by_id_out_of_line) {
+ PropertyOffset offset = structure->get(*profiledBlock->globalData(), ident);
+ if (!isValidOffset(offset))
+ return PutByIdStatus(NoInformation, 0, 0, 0, invalidOffset);
return PutByIdStatus(SimpleReplace, structure, 0, 0, offset);
}
@@ -56,16 +57,18 @@
ASSERT(structure->transitionWatchpointSetHasBeenInvalidated());
ASSERT(instruction[0].u.opcode == llint_op_put_by_id_transition_direct
- || instruction[0].u.opcode == llint_op_put_by_id_transition_normal);
+ || instruction[0].u.opcode == llint_op_put_by_id_transition_normal
+ || instruction[0].u.opcode == llint_op_put_by_id_transition_direct_out_of_line
+ || instruction[0].u.opcode == llint_op_put_by_id_transition_normal_out_of_line);
Structure* newStructure = instruction[6].u.structure.get();
StructureChain* chain = instruction[7].u.structureChain.get();
ASSERT(newStructure);
ASSERT(chain);
- size_t offset = newStructure->get(*profiledBlock->globalData(), ident);
- if (offset == notFound)
- return PutByIdStatus(NoInformation, 0, 0, 0, notFound);
+ PropertyOffset offset = newStructure->get(*profiledBlock->globalData(), ident);
+ if (!isValidOffset(offset))
+ return PutByIdStatus(NoInformation, 0, 0, 0, invalidOffset);
return PutByIdStatus(SimpleTransition, structure, newStructure, chain, offset);
#else
@@ -83,7 +86,7 @@
return computeFromLLInt(profiledBlock, bytecodeIndex, ident);
if (profiledBlock->likelyToTakeSlowCase(bytecodeIndex))
- return PutByIdStatus(TakesSlowPath, 0, 0, 0, notFound);
+ return PutByIdStatus(TakesSlowPath, 0, 0, 0, invalidOffset);
StructureStubInfo& stubInfo = profiledBlock->getStubInfo(bytecodeIndex);
if (!stubInfo.seen)
@@ -94,24 +97,24 @@
return computeFromLLInt(profiledBlock, bytecodeIndex, ident);
case access_put_by_id_replace: {
- size_t offset = stubInfo.u.putByIdReplace.baseObjectStructure->get(
+ PropertyOffset offset = stubInfo.u.putByIdReplace.baseObjectStructure->get(
*profiledBlock->globalData(), ident);
- if (offset != notFound) {
+ if (isValidOffset(offset)) {
return PutByIdStatus(
SimpleReplace,
stubInfo.u.putByIdReplace.baseObjectStructure.get(),
0, 0,
offset);
}
- return PutByIdStatus(TakesSlowPath, 0, 0, 0, notFound);
+ return PutByIdStatus(TakesSlowPath, 0, 0, 0, invalidOffset);
}
case access_put_by_id_transition_normal:
case access_put_by_id_transition_direct: {
ASSERT(stubInfo.u.putByIdTransition.previousStructure->transitionWatchpointSetHasBeenInvalidated());
- size_t offset = stubInfo.u.putByIdTransition.structure->get(
+ PropertyOffset offset = stubInfo.u.putByIdTransition.structure->get(
*profiledBlock->globalData(), ident);
- if (offset != notFound) {
+ if (isValidOffset(offset)) {
return PutByIdStatus(
SimpleTransition,
stubInfo.u.putByIdTransition.previousStructure.get(),
@@ -119,14 +122,14 @@
stubInfo.u.putByIdTransition.chain.get(),
offset);
}
- return PutByIdStatus(TakesSlowPath, 0, 0, 0, notFound);
+ return PutByIdStatus(TakesSlowPath, 0, 0, 0, invalidOffset);
}
default:
- return PutByIdStatus(TakesSlowPath, 0, 0, 0, notFound);
+ return PutByIdStatus(TakesSlowPath, 0, 0, 0, invalidOffset);
}
#else // ENABLE(JIT)
- return PutByIdStatus(NoInformation, 0, 0, 0, notFound);
+ return PutByIdStatus(NoInformation, 0, 0, 0, invalidOffset);
#endif // ENABLE(JIT)
}
diff --git a/Source/JavaScriptCore/bytecode/PutByIdStatus.h b/Source/JavaScriptCore/bytecode/PutByIdStatus.h
index a6d95a4..6949152 100644
--- a/Source/JavaScriptCore/bytecode/PutByIdStatus.h
+++ b/Source/JavaScriptCore/bytecode/PutByIdStatus.h
@@ -26,6 +26,7 @@
#ifndef PutByIdStatus_h
#define PutByIdStatus_h
+#include "PropertyOffset.h"
#include <wtf/NotFound.h>
namespace JSC {
@@ -55,7 +56,7 @@
, m_oldStructure(0)
, m_newStructure(0)
, m_structureChain(0)
- , m_offset(notFound)
+ , m_offset(invalidOffset)
{
}
@@ -64,7 +65,7 @@
Structure* oldStructure,
Structure* newStructure,
StructureChain* structureChain,
- size_t offset)
+ PropertyOffset offset)
: m_state(state)
, m_oldStructure(oldStructure)
, m_newStructure(newStructure)
@@ -74,7 +75,7 @@
ASSERT((m_state == NoInformation || m_state == TakesSlowPath) == !m_oldStructure);
ASSERT((m_state != SimpleTransition) == !m_newStructure);
ASSERT((m_state != SimpleTransition) == !m_structureChain);
- ASSERT((m_state == NoInformation || m_state == TakesSlowPath) == (m_offset == notFound));
+ ASSERT((m_state == NoInformation || m_state == TakesSlowPath) == (m_offset == invalidOffset));
}
static PutByIdStatus computeFor(CodeBlock*, unsigned bytecodeIndex, Identifier&);
@@ -90,7 +91,7 @@
Structure* oldStructure() const { return m_oldStructure; }
Structure* newStructure() const { return m_newStructure; }
StructureChain* structureChain() const { return m_structureChain; }
- size_t offset() const { return m_offset; }
+ PropertyOffset offset() const { return m_offset; }
private:
static PutByIdStatus computeFromLLInt(CodeBlock*, unsigned bytecodeIndex, Identifier&);
@@ -99,7 +100,7 @@
Structure* m_oldStructure;
Structure* m_newStructure;
StructureChain* m_structureChain;
- size_t m_offset;
+ PropertyOffset m_offset;
};
} // namespace JSC
diff --git a/Source/JavaScriptCore/bytecode/ResolveGlobalStatus.cpp b/Source/JavaScriptCore/bytecode/ResolveGlobalStatus.cpp
index ff13870..4afee24 100644
--- a/Source/JavaScriptCore/bytecode/ResolveGlobalStatus.cpp
+++ b/Source/JavaScriptCore/bytecode/ResolveGlobalStatus.cpp
@@ -32,17 +32,19 @@
namespace JSC {
+#if ENABLE(LLINT) || ENABLE(JIT)
static ResolveGlobalStatus computeForStructure(CodeBlock* codeBlock, Structure* structure, Identifier& identifier)
{
unsigned attributesIgnored;
JSCell* specificValue;
- size_t offset = structure->get(
+ PropertyOffset offset = structure->get(
*codeBlock->globalData(), identifier, attributesIgnored, specificValue);
- if (offset == notFound)
+ if (!isValidOffset(offset))
return ResolveGlobalStatus();
return ResolveGlobalStatus(ResolveGlobalStatus::Simple, structure, offset, specificValue);
}
+#endif // ENABLE(LLINT) || ENABLE(JIT)
static ResolveGlobalStatus computeForLLInt(CodeBlock* codeBlock, unsigned bytecodeIndex, Identifier& identifier)
{
diff --git a/Source/JavaScriptCore/bytecode/ResolveGlobalStatus.h b/Source/JavaScriptCore/bytecode/ResolveGlobalStatus.h
index 4698332..cbe4d3b 100644
--- a/Source/JavaScriptCore/bytecode/ResolveGlobalStatus.h
+++ b/Source/JavaScriptCore/bytecode/ResolveGlobalStatus.h
@@ -27,6 +27,7 @@
#define ResolveGlobalStatus_h
#include "JSValue.h"
+#include "PropertyOffset.h"
#include <wtf/NotFound.h>
namespace JSC {
@@ -46,12 +47,12 @@
ResolveGlobalStatus()
: m_state(NoInformation)
, m_structure(0)
- , m_offset(notFound)
+ , m_offset(invalidOffset)
{
}
ResolveGlobalStatus(
- State state, Structure* structure = 0, size_t offset = notFound,
+ State state, Structure* structure = 0, PropertyOffset offset = invalidOffset,
JSValue specificValue = JSValue())
: m_state(state)
, m_structure(structure)
@@ -70,13 +71,13 @@
bool takesSlowPath() const { return m_state == TakesSlowPath; }
Structure* structure() const { return m_structure; }
- size_t offset() const { return m_offset; }
+ PropertyOffset offset() const { return m_offset; }
JSValue specificValue() const { return m_specificValue; }
private:
State m_state;
Structure* m_structure;
- size_t m_offset;
+ PropertyOffset m_offset;
JSValue m_specificValue;
}; // class ResolveGlobalStatus
diff --git a/Source/JavaScriptCore/bytecode/StructureSet.h b/Source/JavaScriptCore/bytecode/StructureSet.h
index 2bbc50c..ebde977 100644
--- a/Source/JavaScriptCore/bytecode/StructureSet.h
+++ b/Source/JavaScriptCore/bytecode/StructureSet.h
@@ -113,15 +113,6 @@
size_t size() const { return m_structures.size(); }
- bool allAreUsingInlinePropertyStorage() const
- {
- for (size_t i = 0; i < m_structures.size(); ++i) {
- if (!m_structures[i]->isUsingInlineStorage())
- return false;
- }
- return true;
- }
-
// Call this if you know that the structure set must consist of exactly
// one structure.
Structure* singletonStructure() const
diff --git a/Source/JavaScriptCore/bytecode/StructureStubInfo.h b/Source/JavaScriptCore/bytecode/StructureStubInfo.h
index 573f6e9..2ed0e4a 100644
--- a/Source/JavaScriptCore/bytecode/StructureStubInfo.h
+++ b/Source/JavaScriptCore/bytecode/StructureStubInfo.h
@@ -204,6 +204,7 @@
int8_t valueGPR;
int8_t scratchGPR;
int32_t deltaCallToDone;
+ int32_t deltaCallToStorageLoad;
int32_t deltaCallToStructCheck;
int32_t deltaCallToSlowCase;
int32_t deltaCheckImmToCall;
@@ -219,6 +220,7 @@
struct {
int16_t structureToCompare;
int16_t structureCheck;
+ int16_t propertyStorageLoad;
#if USE(JSVALUE64)
int16_t displacementLabel;
#else
@@ -230,6 +232,7 @@
} get;
struct {
int16_t structureToCompare;
+ int16_t propertyStorageLoad;
#if USE(JSVALUE64)
int16_t displacementLabel;
#else
diff --git a/Source/JavaScriptCore/dfg/DFGByteCodeParser.cpp b/Source/JavaScriptCore/dfg/DFGByteCodeParser.cpp
index c7765f7..2574dee 100644
--- a/Source/JavaScriptCore/dfg/DFGByteCodeParser.cpp
+++ b/Source/JavaScriptCore/dfg/DFGByteCodeParser.cpp
@@ -99,7 +99,7 @@
bool handleConstantInternalFunction(bool usesResult, int resultOperand, InternalFunction*, int registerOffset, int argumentCountIncludingThis, SpeculatedType prediction, CodeSpecializationKind);
void handleGetByOffset(
int destinationOperand, SpeculatedType, NodeIndex base, unsigned identifierNumber,
- bool useInlineStorage, size_t offset);
+ PropertyOffset);
void handleGetById(
int destinationOperand, SpeculatedType, NodeIndex base, unsigned identifierNumber,
const GetByIdStatus&);
@@ -1630,25 +1630,20 @@
void ByteCodeParser::handleGetByOffset(
int destinationOperand, SpeculatedType prediction, NodeIndex base, unsigned identifierNumber,
- bool useInlineStorage, size_t offset)
+ PropertyOffset offset)
{
NodeIndex propertyStorage;
- size_t offsetOffset;
- if (useInlineStorage) {
+ if (isInlineOffset(offset))
propertyStorage = base;
- ASSERT(!(sizeof(JSObject) % sizeof(EncodedJSValue)));
- offsetOffset = sizeof(JSObject) / sizeof(EncodedJSValue);
- } else {
+ else
propertyStorage = addToGraph(GetPropertyStorage, base);
- offsetOffset = 0;
- }
set(destinationOperand,
addToGraph(
GetByOffset, OpInfo(m_graph.m_storageAccessData.size()), OpInfo(prediction),
propertyStorage));
StorageAccessData storageAccessData;
- storageAccessData.offset = offset + offsetOffset;
+ storageAccessData.offset = indexRelativeToBase(offset);
storageAccessData.identifierNumber = identifierNumber;
m_graph.m_storageAccessData.append(storageAccessData);
}
@@ -1677,7 +1672,6 @@
addToGraph(CheckStructure, OpInfo(m_graph.addStructureSet(getByIdStatus.structureSet())), base);
- bool useInlineStorage;
if (!getByIdStatus.chain().isEmpty()) {
Structure* currentStructure = getByIdStatus.structureSet().singletonStructure();
JSObject* currentObject = 0;
@@ -1686,9 +1680,7 @@
currentStructure = getByIdStatus.chain()[i];
base = addStructureTransitionCheck(currentObject, currentStructure);
}
- useInlineStorage = currentStructure->isUsingInlineStorage();
- } else
- useInlineStorage = getByIdStatus.structureSet().allAreUsingInlinePropertyStorage();
+ }
// Unless we want bugs like https://bugs.webkit.org/show_bug.cgi?id=88783, we need to
// ensure that the base of the original get_by_id is kept alive until we're done with
@@ -1707,8 +1699,7 @@
}
handleGetByOffset(
- destinationOperand, prediction, base, identifierNumber, useInlineStorage,
- getByIdStatus.offset());
+ destinationOperand, prediction, base, identifierNumber, getByIdStatus.offset());
}
void ByteCodeParser::prepareToParseBlock()
@@ -2172,7 +2163,8 @@
SpeculatedType prediction = getPrediction();
- ASSERT(interpreter->getOpcodeID(getInstruction->u.opcode) == op_get_by_id);
+ ASSERT(interpreter->getOpcodeID(getInstruction->u.opcode) == op_get_by_id
+ || interpreter->getOpcodeID(getInstruction->u.opcode) == op_get_by_id_out_of_line);
NodeIndex base = get(getInstruction[2].u.operand);
unsigned identifier = m_inlineStackTop->m_identifierRemap[getInstruction[3].u.operand];
@@ -2225,7 +2217,8 @@
addToGraph(PutScopedVar, OpInfo(slot), getScopeChain, get(source));
NEXT_OPCODE(op_put_scoped_var);
}
- case op_get_by_id: {
+ case op_get_by_id:
+ case op_get_by_id_out_of_line: {
SpeculatedType prediction = getPredictionWithoutOSRExit();
NodeIndex base = get(currentInstruction[2].u.operand);
@@ -2241,8 +2234,11 @@
NEXT_OPCODE(op_get_by_id);
}
case op_put_by_id:
+ case op_put_by_id_out_of_line:
case op_put_by_id_transition_direct:
- case op_put_by_id_transition_normal: {
+ case op_put_by_id_transition_normal:
+ case op_put_by_id_transition_direct_out_of_line:
+ case op_put_by_id_transition_normal_out_of_line: {
NodeIndex value = get(currentInstruction[3].u.operand);
NodeIndex base = get(currentInstruction[1].u.operand);
unsigned identifierNumber = m_inlineStackTop->m_identifierRemap[currentInstruction[2].u.operand];
@@ -2259,25 +2255,20 @@
if (!hasExitSite && putByIdStatus.isSimpleReplace()) {
addToGraph(CheckStructure, OpInfo(m_graph.addStructureSet(putByIdStatus.oldStructure())), base);
- size_t offsetOffset;
NodeIndex propertyStorage;
- if (putByIdStatus.oldStructure()->isUsingInlineStorage()) {
+ if (isInlineOffset(putByIdStatus.offset()))
propertyStorage = base;
- ASSERT(!(sizeof(JSObject) % sizeof(EncodedJSValue)));
- offsetOffset = sizeof(JSObject) / sizeof(EncodedJSValue);
- } else {
+ else
propertyStorage = addToGraph(GetPropertyStorage, base);
- offsetOffset = 0;
- }
addToGraph(PutByOffset, OpInfo(m_graph.m_storageAccessData.size()), propertyStorage, base, value);
StorageAccessData storageAccessData;
- storageAccessData.offset = putByIdStatus.offset() + offsetOffset;
+ storageAccessData.offset = indexRelativeToBase(putByIdStatus.offset());
storageAccessData.identifierNumber = identifierNumber;
m_graph.m_storageAccessData.append(storageAccessData);
} else if (!hasExitSite
&& putByIdStatus.isSimpleTransition()
- && putByIdStatus.oldStructure()->propertyStorageCapacity() == putByIdStatus.newStructure()->propertyStorageCapacity()
+ && putByIdStatus.oldStructure()->outOfLineCapacity() == putByIdStatus.newStructure()->outOfLineCapacity()
&& structureChainIsStillValid(
direct,
putByIdStatus.oldStructure(),
@@ -2308,16 +2299,11 @@
putByIdStatus.newStructure()))),
base);
- size_t offsetOffset;
NodeIndex propertyStorage;
- if (putByIdStatus.newStructure()->isUsingInlineStorage()) {
+ if (isInlineOffset(putByIdStatus.offset()))
propertyStorage = base;
- ASSERT(!(sizeof(JSObject) % sizeof(EncodedJSValue)));
- offsetOffset = sizeof(JSObject) / sizeof(EncodedJSValue);
- } else {
+ else
propertyStorage = addToGraph(GetPropertyStorage, base);
- offsetOffset = 0;
- }
addToGraph(
PutByOffset,
OpInfo(m_graph.m_storageAccessData.size()),
@@ -2326,7 +2312,7 @@
value);
StorageAccessData storageAccessData;
- storageAccessData.offset = putByIdStatus.offset() + offsetOffset;
+ storageAccessData.offset = indexRelativeToBase(putByIdStatus.offset());
storageAccessData.identifierNumber = identifierNumber;
m_graph.m_storageAccessData.append(storageAccessData);
} else {
@@ -2738,8 +2724,7 @@
} else {
handleGetByOffset(
currentInstruction[1].u.operand, prediction, globalObject,
- identifierNumber, status.structure()->isUsingInlineStorage(),
- status.offset());
+ identifierNumber, status.offset());
}
m_globalResolveNumber++; // Skip over the unused global resolve info.
diff --git a/Source/JavaScriptCore/dfg/DFGCapabilities.h b/Source/JavaScriptCore/dfg/DFGCapabilities.h
index 8c51491..2bc9b29 100644
--- a/Source/JavaScriptCore/dfg/DFGCapabilities.h
+++ b/Source/JavaScriptCore/dfg/DFGCapabilities.h
@@ -119,9 +119,13 @@
case op_get_scoped_var:
case op_put_scoped_var:
case op_get_by_id:
+ case op_get_by_id_out_of_line:
case op_put_by_id:
+ case op_put_by_id_out_of_line:
case op_put_by_id_transition_direct:
+ case op_put_by_id_transition_direct_out_of_line:
case op_put_by_id_transition_normal:
+ case op_put_by_id_transition_normal_out_of_line:
case op_get_global_var:
case op_get_global_var_watchable:
case op_put_global_var:
diff --git a/Source/JavaScriptCore/dfg/DFGJITCompiler.cpp b/Source/JavaScriptCore/dfg/DFGJITCompiler.cpp
index 9cd60c5..497fc34 100644
--- a/Source/JavaScriptCore/dfg/DFGJITCompiler.cpp
+++ b/Source/JavaScriptCore/dfg/DFGJITCompiler.cpp
@@ -172,6 +172,7 @@
#endif
info.patch.dfg.deltaCallToSlowCase = differenceBetweenCodePtr(callReturnLocation, linkBuffer.locationOf(m_propertyAccesses[i].m_slowPathGenerator->label()));
info.patch.dfg.deltaCallToDone = differenceBetweenCodePtr(callReturnLocation, linkBuffer.locationOf(m_propertyAccesses[i].m_done));
+ info.patch.dfg.deltaCallToStorageLoad = differenceBetweenCodePtr(callReturnLocation, linkBuffer.locationOf(m_propertyAccesses[i].m_propertyStorageLoad));
info.patch.dfg.baseGPR = m_propertyAccesses[i].m_baseGPR;
#if USE(JSVALUE64)
info.patch.dfg.valueGPR = m_propertyAccesses[i].m_valueGPR;
diff --git a/Source/JavaScriptCore/dfg/DFGJITCompiler.h b/Source/JavaScriptCore/dfg/DFGJITCompiler.h
index ed16459..24dbbdc 100644
--- a/Source/JavaScriptCore/dfg/DFGJITCompiler.h
+++ b/Source/JavaScriptCore/dfg/DFGJITCompiler.h
@@ -136,6 +136,7 @@
CodeOrigin codeOrigin,
MacroAssembler::DataLabelPtr structureImm,
MacroAssembler::PatchableJump structureCheck,
+ MacroAssembler::ConvertibleLoadLabel propertyStorageLoad,
MacroAssembler::DataLabelCompact loadOrStore,
SlowPathGenerator* slowPathGenerator,
MacroAssembler::Label done,
@@ -148,6 +149,7 @@
CodeOrigin codeOrigin,
MacroAssembler::DataLabelPtr structureImm,
MacroAssembler::PatchableJump structureCheck,
+ MacroAssembler::ConvertibleLoadLabel propertyStorageLoad,
MacroAssembler::DataLabelCompact tagLoadOrStore,
MacroAssembler::DataLabelCompact payloadLoadOrStore,
SlowPathGenerator* slowPathGenerator,
@@ -161,6 +163,7 @@
: m_codeOrigin(codeOrigin)
, m_structureImm(structureImm)
, m_structureCheck(structureCheck)
+ , m_propertyStorageLoad(propertyStorageLoad)
#if USE(JSVALUE64)
, m_loadOrStore(loadOrStore)
#elif USE(JSVALUE32_64)
@@ -182,6 +185,7 @@
CodeOrigin m_codeOrigin;
MacroAssembler::DataLabelPtr m_structureImm;
MacroAssembler::PatchableJump m_structureCheck;
+ MacroAssembler::ConvertibleLoadLabel m_propertyStorageLoad;
#if USE(JSVALUE64)
MacroAssembler::DataLabelCompact m_loadOrStore;
#elif USE(JSVALUE32_64)
diff --git a/Source/JavaScriptCore/dfg/DFGRepatch.cpp b/Source/JavaScriptCore/dfg/DFGRepatch.cpp
index 9c3391b..060e5fc 100644
--- a/Source/JavaScriptCore/dfg/DFGRepatch.cpp
+++ b/Source/JavaScriptCore/dfg/DFGRepatch.cpp
@@ -43,7 +43,7 @@
repatchBuffer.relink(call, newCalleeFunction);
}
-static void dfgRepatchByIdSelfAccess(CodeBlock* codeBlock, StructureStubInfo& stubInfo, Structure* structure, size_t offset, const FunctionPtr &slowPathFunction, bool compact)
+static void dfgRepatchByIdSelfAccess(CodeBlock* codeBlock, StructureStubInfo& stubInfo, Structure* structure, PropertyOffset offset, const FunctionPtr &slowPathFunction, bool compact)
{
RepatchBuffer repatchBuffer(codeBlock);
@@ -52,18 +52,19 @@
// Patch the structure check & the offset of the load.
repatchBuffer.repatch(stubInfo.callReturnLocation.dataLabelPtrAtOffset(-(intptr_t)stubInfo.patch.dfg.deltaCheckImmToCall), structure);
+ repatchBuffer.setLoadInstructionIsActive(stubInfo.callReturnLocation.convertibleLoadAtOffset(stubInfo.patch.dfg.deltaCallToStorageLoad), isOutOfLineOffset(offset));
#if USE(JSVALUE64)
if (compact)
- repatchBuffer.repatch(stubInfo.callReturnLocation.dataLabelCompactAtOffset(stubInfo.patch.dfg.deltaCallToLoadOrStore), sizeof(JSValue) * offset);
+ repatchBuffer.repatch(stubInfo.callReturnLocation.dataLabelCompactAtOffset(stubInfo.patch.dfg.deltaCallToLoadOrStore), offsetRelativeToPatchedStorage(offset));
else
- repatchBuffer.repatch(stubInfo.callReturnLocation.dataLabel32AtOffset(stubInfo.patch.dfg.deltaCallToLoadOrStore), sizeof(JSValue) * offset);
+ repatchBuffer.repatch(stubInfo.callReturnLocation.dataLabel32AtOffset(stubInfo.patch.dfg.deltaCallToLoadOrStore), offsetRelativeToPatchedStorage(offset));
#elif USE(JSVALUE32_64)
if (compact) {
- repatchBuffer.repatch(stubInfo.callReturnLocation.dataLabelCompactAtOffset(stubInfo.patch.dfg.deltaCallToTagLoadOrStore), sizeof(JSValue) * offset + OBJECT_OFFSETOF(EncodedValueDescriptor, asBits.tag));
- repatchBuffer.repatch(stubInfo.callReturnLocation.dataLabelCompactAtOffset(stubInfo.patch.dfg.deltaCallToPayloadLoadOrStore), sizeof(JSValue) * offset + OBJECT_OFFSETOF(EncodedValueDescriptor, asBits.payload));
+ repatchBuffer.repatch(stubInfo.callReturnLocation.dataLabelCompactAtOffset(stubInfo.patch.dfg.deltaCallToTagLoadOrStore), offsetRelativeToPatchedStorage(offset) + OBJECT_OFFSETOF(EncodedValueDescriptor, asBits.tag));
+ repatchBuffer.repatch(stubInfo.callReturnLocation.dataLabelCompactAtOffset(stubInfo.patch.dfg.deltaCallToPayloadLoadOrStore), offsetRelativeToPatchedStorage(offset) + OBJECT_OFFSETOF(EncodedValueDescriptor, asBits.payload));
} else {
- repatchBuffer.repatch(stubInfo.callReturnLocation.dataLabel32AtOffset(stubInfo.patch.dfg.deltaCallToTagLoadOrStore), sizeof(JSValue) * offset + OBJECT_OFFSETOF(EncodedValueDescriptor, asBits.tag));
- repatchBuffer.repatch(stubInfo.callReturnLocation.dataLabel32AtOffset(stubInfo.patch.dfg.deltaCallToPayloadLoadOrStore), sizeof(JSValue) * offset + OBJECT_OFFSETOF(EncodedValueDescriptor, asBits.payload));
+ repatchBuffer.repatch(stubInfo.callReturnLocation.dataLabel32AtOffset(stubInfo.patch.dfg.deltaCallToTagLoadOrStore), offsetRelativeToPatchedStorage(offset) + OBJECT_OFFSETOF(EncodedValueDescriptor, asBits.tag));
+ repatchBuffer.repatch(stubInfo.callReturnLocation.dataLabel32AtOffset(stubInfo.patch.dfg.deltaCallToPayloadLoadOrStore), offsetRelativeToPatchedStorage(offset) + OBJECT_OFFSETOF(EncodedValueDescriptor, asBits.payload));
}
#endif
}
@@ -105,7 +106,7 @@
linkRestoreScratch(patchBuffer, needToRestoreScratch, success, fail, failureCases, stubInfo.callReturnLocation.labelAtOffset(stubInfo.patch.dfg.deltaCallToDone), stubInfo.callReturnLocation.labelAtOffset(stubInfo.patch.dfg.deltaCallToSlowCase));
}
-static void generateProtoChainAccessStub(ExecState* exec, StructureStubInfo& stubInfo, StructureChain* chain, size_t count, size_t offset, Structure* structure, CodeLocationLabel successLabel, CodeLocationLabel slowCaseLabel, MacroAssemblerCodeRef& stubRoutine)
+static void generateProtoChainAccessStub(ExecState* exec, StructureStubInfo& stubInfo, StructureChain* chain, size_t count, PropertyOffset offset, Structure* structure, CodeLocationLabel successLabel, CodeLocationLabel slowCaseLabel, MacroAssemblerCodeRef& stubRoutine)
{
JSGlobalData* globalData = &exec->globalData();
@@ -139,13 +140,23 @@
currStructure = it->get();
}
- stubJit.loadPtr(protoObject->addressOfPropertyStorage(), resultGPR);
+ if (isInlineOffset(offset)) {
#if USE(JSVALUE64)
- stubJit.loadPtr(MacroAssembler::Address(resultGPR, offset * sizeof(WriteBarrier<Unknown>)), resultGPR);
+ stubJit.loadPtr(protoObject->locationForOffset(offset), resultGPR);
#elif USE(JSVALUE32_64)
- stubJit.load32(MacroAssembler::Address(resultGPR, offset * sizeof(WriteBarrier<Unknown>) + OBJECT_OFFSETOF(EncodedValueDescriptor, asBits.tag)), resultTagGPR);
- stubJit.load32(MacroAssembler::Address(resultGPR, offset * sizeof(WriteBarrier<Unknown>) + OBJECT_OFFSETOF(EncodedValueDescriptor, asBits.payload)), resultGPR);
+ stubJit.move(MacroAssembler::TrustedImmPtr(protoObject->locationForOffset(offset)), resultGPR);
+ stubJit.load32(MacroAssembler::Address(resultGPR, OBJECT_OFFSETOF(EncodedValueDescriptor, asBits.tag)), resultTagGPR);
+ stubJit.load32(MacroAssembler::Address(resultGPR, OBJECT_OFFSETOF(EncodedValueDescriptor, asBits.payload)), resultGPR);
#endif
+ } else {
+ stubJit.loadPtr(protoObject->addressOfOutOfLineStorage(), resultGPR);
+#if USE(JSVALUE64)
+ stubJit.loadPtr(MacroAssembler::Address(resultGPR, offsetInOutOfLineStorage(offset) * sizeof(WriteBarrier<Unknown>)), resultGPR);
+#elif USE(JSVALUE32_64)
+ stubJit.load32(MacroAssembler::Address(resultGPR, offsetInOutOfLineStorage(offset) * sizeof(WriteBarrier<Unknown>) + OBJECT_OFFSETOF(EncodedValueDescriptor, asBits.tag)), resultTagGPR);
+ stubJit.load32(MacroAssembler::Address(resultGPR, offsetInOutOfLineStorage(offset) * sizeof(WriteBarrier<Unknown>) + OBJECT_OFFSETOF(EncodedValueDescriptor, asBits.payload)), resultGPR);
+#endif
+ }
MacroAssembler::Jump success, fail;
@@ -253,7 +264,7 @@
if (slot.cachedPropertyType() != PropertySlot::Value)
return false;
- size_t offset = slot.cachedOffset();
+ PropertyOffset offset = slot.cachedOffset();
size_t count = normalizePrototypeChain(exec, baseValue, slot.slotBase(), propertyName, offset);
if (!count)
return false;
@@ -349,12 +360,20 @@
|| slot.cachedPropertyType() == PropertySlot::Custom) {
if (slot.cachedPropertyType() == PropertySlot::Getter) {
ASSERT(baseGPR != scratchGPR);
- stubJit.loadPtr(MacroAssembler::Address(baseGPR, JSObject::offsetOfPropertyStorage()), scratchGPR);
+ if (isInlineOffset(slot.cachedOffset())) {
#if USE(JSVALUE64)
- stubJit.loadPtr(MacroAssembler::Address(scratchGPR, slot.cachedOffset() * sizeof(JSValue)), scratchGPR);
-#elif USE(JSVALUE32_64)
- stubJit.load32(MacroAssembler::Address(scratchGPR, slot.cachedOffset() * sizeof(JSValue) + OBJECT_OFFSETOF(EncodedValueDescriptor, asBits.payload)), scratchGPR);
+ stubJit.loadPtr(MacroAssembler::Address(baseGPR, offsetRelativeToBase(slot.cachedOffset())), scratchGPR);
+#else
+ stubJit.load32(MacroAssembler::Address(baseGPR, offsetRelativeToBase(slot.cachedOffset())), scratchGPR);
#endif
+ } else {
+ stubJit.loadPtr(MacroAssembler::Address(baseGPR, JSObject::offsetOfOutOfLineStorage()), scratchGPR);
+#if USE(JSVALUE64)
+ stubJit.loadPtr(MacroAssembler::Address(scratchGPR, offsetRelativeToBase(slot.cachedOffset())), scratchGPR);
+#else
+ stubJit.load32(MacroAssembler::Address(scratchGPR, offsetRelativeToBase(slot.cachedOffset())), scratchGPR);
+#endif
+ }
stubJit.setupArgumentsWithExecState(baseGPR, scratchGPR);
operationFunction = operationCallGetter;
} else {
@@ -385,13 +404,27 @@
handlerCall = stubJit.call();
stubJit.jump(GPRInfo::returnValueGPR2);
} else {
- stubJit.loadPtr(MacroAssembler::Address(baseGPR, JSObject::offsetOfPropertyStorage()), resultGPR);
+ if (isInlineOffset(slot.cachedOffset())) {
#if USE(JSVALUE64)
- stubJit.loadPtr(MacroAssembler::Address(resultGPR, slot.cachedOffset() * sizeof(JSValue)), resultGPR);
-#elif USE(JSVALUE32_64)
- stubJit.load32(MacroAssembler::Address(resultGPR, slot.cachedOffset() * sizeof(JSValue) + OBJECT_OFFSETOF(EncodedValueDescriptor, asBits.tag)), resultTagGPR);
- stubJit.load32(MacroAssembler::Address(resultGPR, slot.cachedOffset() * sizeof(JSValue) + OBJECT_OFFSETOF(EncodedValueDescriptor, asBits.payload)), resultGPR);
+ stubJit.loadPtr(MacroAssembler::Address(baseGPR, offsetRelativeToBase(slot.cachedOffset())), resultGPR);
+#else
+ if (baseGPR == resultTagGPR) {
+ stubJit.load32(MacroAssembler::Address(baseGPR, offsetRelativeToBase(slot.cachedOffset()) + OBJECT_OFFSETOF(EncodedValueDescriptor, asBits.payload)), resultGPR);
+ stubJit.load32(MacroAssembler::Address(baseGPR, offsetRelativeToBase(slot.cachedOffset()) + OBJECT_OFFSETOF(EncodedValueDescriptor, asBits.tag)), resultTagGPR);
+ } else {
+ stubJit.load32(MacroAssembler::Address(baseGPR, offsetRelativeToBase(slot.cachedOffset()) + OBJECT_OFFSETOF(EncodedValueDescriptor, asBits.tag)), resultTagGPR);
+ stubJit.load32(MacroAssembler::Address(baseGPR, offsetRelativeToBase(slot.cachedOffset()) + OBJECT_OFFSETOF(EncodedValueDescriptor, asBits.payload)), resultGPR);
+ }
#endif
+ } else {
+ stubJit.loadPtr(MacroAssembler::Address(baseGPR, JSObject::offsetOfOutOfLineStorage()), resultGPR);
+#if USE(JSVALUE64)
+ stubJit.loadPtr(MacroAssembler::Address(resultGPR, offsetRelativeToBase(slot.cachedOffset())), resultGPR);
+#else
+ stubJit.load32(MacroAssembler::Address(resultGPR, offsetRelativeToBase(slot.cachedOffset()) + OBJECT_OFFSETOF(EncodedValueDescriptor, asBits.tag)), resultTagGPR);
+ stubJit.load32(MacroAssembler::Address(resultGPR, offsetRelativeToBase(slot.cachedOffset()) + OBJECT_OFFSETOF(EncodedValueDescriptor, asBits.payload)), resultGPR);
+#endif
+ }
success = stubJit.jump();
isDirect = true;
}
@@ -450,7 +483,7 @@
ASSERT(slot.slotBase().isObject());
- size_t offset = slot.cachedOffset();
+ PropertyOffset offset = slot.cachedOffset();
size_t count = normalizePrototypeChain(exec, baseValue, slot.slotBase(), propertyName, offset);
if (!count)
return false;
@@ -567,7 +600,7 @@
MacroAssembler stubJit;
- if (scratchGPR == InvalidGPRReg && (writeBarrierNeeded || !structure->isUsingInlineStorage())) {
+ if (scratchGPR == InvalidGPRReg && (writeBarrierNeeded || isOutOfLineOffset(slot.cachedOffset()))) {
scratchGPR = SpeculativeJIT::selectScratchGPR(baseGPR, valueGPR);
needToRestoreScratch = true;
stubJit.push(scratchGPR);
@@ -586,20 +619,20 @@
#endif
#if USE(JSVALUE64)
- if (structure->isUsingInlineStorage())
- stubJit.storePtr(valueGPR, MacroAssembler::Address(baseGPR, JSObject::offsetOfInlineStorage() + slot.cachedOffset() * sizeof(JSValue)));
+ if (isInlineOffset(slot.cachedOffset()))
+ stubJit.storePtr(valueGPR, MacroAssembler::Address(baseGPR, JSObject::offsetOfInlineStorage() + offsetInInlineStorage(slot.cachedOffset()) * sizeof(JSValue)));
else {
- stubJit.loadPtr(MacroAssembler::Address(baseGPR, JSObject::offsetOfPropertyStorage()), scratchGPR);
- stubJit.storePtr(valueGPR, MacroAssembler::Address(scratchGPR, slot.cachedOffset() * sizeof(JSValue)));
+ stubJit.loadPtr(MacroAssembler::Address(baseGPR, JSObject::offsetOfOutOfLineStorage()), scratchGPR);
+ stubJit.storePtr(valueGPR, MacroAssembler::Address(scratchGPR, offsetInOutOfLineStorage(slot.cachedOffset()) * sizeof(JSValue)));
}
#elif USE(JSVALUE32_64)
- if (structure->isUsingInlineStorage()) {
- stubJit.store32(valueGPR, MacroAssembler::Address(baseGPR, JSObject::offsetOfInlineStorage() + slot.cachedOffset() * sizeof(JSValue) + OBJECT_OFFSETOF(EncodedValueDescriptor, asBits.payload)));
- stubJit.store32(valueTagGPR, MacroAssembler::Address(baseGPR, JSObject::offsetOfInlineStorage() + slot.cachedOffset() * sizeof(JSValue) + OBJECT_OFFSETOF(EncodedValueDescriptor, asBits.tag)));
+ if (isInlineOffset(slot.cachedOffset())) {
+ stubJit.store32(valueGPR, MacroAssembler::Address(baseGPR, JSObject::offsetOfInlineStorage() + offsetInInlineStorage(slot.cachedOffset()) * sizeof(JSValue) + OBJECT_OFFSETOF(EncodedValueDescriptor, asBits.payload)));
+ stubJit.store32(valueTagGPR, MacroAssembler::Address(baseGPR, JSObject::offsetOfInlineStorage() + offsetInInlineStorage(slot.cachedOffset()) * sizeof(JSValue) + OBJECT_OFFSETOF(EncodedValueDescriptor, asBits.tag)));
} else {
- stubJit.loadPtr(MacroAssembler::Address(baseGPR, JSObject::offsetOfPropertyStorage()), scratchGPR);
- stubJit.store32(valueGPR, MacroAssembler::Address(scratchGPR, slot.cachedOffset() * sizeof(JSValue) + OBJECT_OFFSETOF(EncodedValueDescriptor, asBits.payload)));
- stubJit.store32(valueTagGPR, MacroAssembler::Address(scratchGPR, slot.cachedOffset() * sizeof(JSValue) + OBJECT_OFFSETOF(EncodedValueDescriptor, asBits.tag)));
+ stubJit.loadPtr(MacroAssembler::Address(baseGPR, JSObject::offsetOfOutOfLineStorage()), scratchGPR);
+ stubJit.store32(valueGPR, MacroAssembler::Address(scratchGPR, offsetInOutOfLineStorage(slot.cachedOffset()) * sizeof(JSValue) + OBJECT_OFFSETOF(EncodedValueDescriptor, asBits.payload)));
+ stubJit.store32(valueTagGPR, MacroAssembler::Address(scratchGPR, offsetInOutOfLineStorage(slot.cachedOffset()) * sizeof(JSValue) + OBJECT_OFFSETOF(EncodedValueDescriptor, asBits.tag)));
}
#endif
@@ -685,20 +718,20 @@
stubJit.storePtr(MacroAssembler::TrustedImmPtr(structure), MacroAssembler::Address(baseGPR, JSCell::structureOffset()));
#if USE(JSVALUE64)
- if (structure->isUsingInlineStorage())
- stubJit.storePtr(valueGPR, MacroAssembler::Address(baseGPR, JSObject::offsetOfInlineStorage() + slot.cachedOffset() * sizeof(JSValue)));
+ if (isInlineOffset(slot.cachedOffset()))
+ stubJit.storePtr(valueGPR, MacroAssembler::Address(baseGPR, JSObject::offsetOfInlineStorage() + offsetInInlineStorage(slot.cachedOffset()) * sizeof(JSValue)));
else {
- stubJit.loadPtr(MacroAssembler::Address(baseGPR, JSObject::offsetOfPropertyStorage()), scratchGPR);
- stubJit.storePtr(valueGPR, MacroAssembler::Address(scratchGPR, slot.cachedOffset() * sizeof(JSValue)));
+ stubJit.loadPtr(MacroAssembler::Address(baseGPR, JSObject::offsetOfOutOfLineStorage()), scratchGPR);
+ stubJit.storePtr(valueGPR, MacroAssembler::Address(scratchGPR, offsetInOutOfLineStorage(slot.cachedOffset()) * sizeof(JSValue)));
}
#elif USE(JSVALUE32_64)
- if (structure->isUsingInlineStorage()) {
- stubJit.store32(valueGPR, MacroAssembler::Address(baseGPR, JSObject::offsetOfInlineStorage() + slot.cachedOffset() * sizeof(JSValue) + OBJECT_OFFSETOF(EncodedValueDescriptor, asBits.payload)));
- stubJit.store32(valueTagGPR, MacroAssembler::Address(baseGPR, JSObject::offsetOfInlineStorage() + slot.cachedOffset() * sizeof(JSValue) + OBJECT_OFFSETOF(EncodedValueDescriptor, asBits.tag)));
+ if (isInlineOffset(slot.cachedOffset())) {
+ stubJit.store32(valueGPR, MacroAssembler::Address(baseGPR, JSObject::offsetOfInlineStorage() + offsetInInlineStorage(slot.cachedOffset()) * sizeof(JSValue) + OBJECT_OFFSETOF(EncodedValueDescriptor, asBits.payload)));
+ stubJit.store32(valueTagGPR, MacroAssembler::Address(baseGPR, JSObject::offsetOfInlineStorage() + offsetInInlineStorage(slot.cachedOffset()) * sizeof(JSValue) + OBJECT_OFFSETOF(EncodedValueDescriptor, asBits.tag)));
} else {
- stubJit.loadPtr(MacroAssembler::Address(baseGPR, JSObject::offsetOfPropertyStorage()), scratchGPR);
- stubJit.store32(valueGPR, MacroAssembler::Address(scratchGPR, slot.cachedOffset() * sizeof(JSValue) + OBJECT_OFFSETOF(EncodedValueDescriptor, asBits.payload)));
- stubJit.store32(valueTagGPR, MacroAssembler::Address(scratchGPR, slot.cachedOffset() * sizeof(JSValue) + OBJECT_OFFSETOF(EncodedValueDescriptor, asBits.tag)));
+ stubJit.loadPtr(MacroAssembler::Address(baseGPR, JSObject::offsetOfOutOfLineStorage()), scratchGPR);
+ stubJit.store32(valueGPR, MacroAssembler::Address(scratchGPR, offsetInOutOfLineStorage(slot.cachedOffset()) * sizeof(JSValue) + OBJECT_OFFSETOF(EncodedValueDescriptor, asBits.payload)));
+ stubJit.store32(valueTagGPR, MacroAssembler::Address(scratchGPR, offsetInOutOfLineStorage(slot.cachedOffset()) * sizeof(JSValue) + OBJECT_OFFSETOF(EncodedValueDescriptor, asBits.tag)));
}
#endif
@@ -752,7 +785,7 @@
return false;
// skip optimizing the case where we need a realloc
- if (oldStructure->propertyStorageCapacity() != structure->propertyStorageCapacity())
+ if (oldStructure->outOfLineCapacity() != structure->outOfLineCapacity())
return false;
normalizePrototypeChain(exec, baseCell);
@@ -815,7 +848,7 @@
return false;
// skip optimizing the case where we need a realloc
- if (oldStructure->propertyStorageCapacity() != structure->propertyStorageCapacity())
+ if (oldStructure->outOfLineCapacity() != structure->outOfLineCapacity())
return false;
normalizePrototypeChain(exec, baseCell);
diff --git a/Source/JavaScriptCore/dfg/DFGSpeculativeJIT.h b/Source/JavaScriptCore/dfg/DFGSpeculativeJIT.h
index 14316ac..57bc84a 100644
--- a/Source/JavaScriptCore/dfg/DFGSpeculativeJIT.h
+++ b/Source/JavaScriptCore/dfg/DFGSpeculativeJIT.h
@@ -2103,8 +2103,7 @@
m_jit.storePtr(MacroAssembler::TrustedImmPtr(0), MacroAssembler::Address(resultGPR, JSObject::offsetOfInheritorID()));
// Initialize the object's property storage pointer.
- m_jit.addPtr(MacroAssembler::TrustedImm32(sizeof(JSObject)), resultGPR, scratchGPR);
- m_jit.storePtr(scratchGPR, MacroAssembler::Address(resultGPR, ClassType::offsetOfPropertyStorage()));
+ m_jit.storePtr(MacroAssembler::TrustedImmPtr(0), MacroAssembler::Address(resultGPR, ClassType::offsetOfOutOfLineStorage()));
}
// It is acceptable to have structure be equal to scratch, so long as you're fine
diff --git a/Source/JavaScriptCore/dfg/DFGSpeculativeJIT32_64.cpp b/Source/JavaScriptCore/dfg/DFGSpeculativeJIT32_64.cpp
index df543a9..09bc334 100644
--- a/Source/JavaScriptCore/dfg/DFGSpeculativeJIT32_64.cpp
+++ b/Source/JavaScriptCore/dfg/DFGSpeculativeJIT32_64.cpp
@@ -508,7 +508,7 @@
JITCompiler::DataLabelPtr structureToCompare;
JITCompiler::PatchableJump structureCheck = m_jit.patchableBranchPtrWithPatch(JITCompiler::NotEqual, JITCompiler::Address(basePayloadGPR, JSCell::structureOffset()), structureToCompare, JITCompiler::TrustedImmPtr(reinterpret_cast<void*>(-1)));
- m_jit.loadPtr(JITCompiler::Address(basePayloadGPR, JSObject::offsetOfPropertyStorage()), resultPayloadGPR);
+ JITCompiler::ConvertibleLoadLabel propertyStorageLoad = m_jit.convertibleLoadPtr(JITCompiler::Address(basePayloadGPR, JSObject::offsetOfOutOfLineStorage()), resultPayloadGPR);
JITCompiler::DataLabelCompact tagLoadWithPatch = m_jit.load32WithCompactAddressOffsetPatch(JITCompiler::Address(resultPayloadGPR, OBJECT_OFFSETOF(EncodedValueDescriptor, asBits.tag)), resultTagGPR);
JITCompiler::DataLabelCompact payloadLoadWithPatch = m_jit.load32WithCompactAddressOffsetPatch(JITCompiler::Address(resultPayloadGPR, OBJECT_OFFSETOF(EncodedValueDescriptor, asBits.payload)), resultPayloadGPR);
@@ -550,7 +550,7 @@
}
m_jit.addPropertyAccess(
PropertyAccessRecord(
- codeOrigin, structureToCompare, structureCheck,
+ codeOrigin, structureToCompare, structureCheck, propertyStorageLoad,
tagLoadWithPatch, payloadLoadWithPatch, slowPath.get(), doneLabel,
safeCast<int8_t>(basePayloadGPR), safeCast<int8_t>(resultTagGPR),
safeCast<int8_t>(resultPayloadGPR), safeCast<int8_t>(scratchGPR),
@@ -565,7 +565,7 @@
writeBarrier(basePayloadGPR, valueTagGPR, valueUse, WriteBarrierForPropertyAccess, scratchGPR);
- m_jit.loadPtr(JITCompiler::Address(basePayloadGPR, JSObject::offsetOfPropertyStorage()), scratchGPR);
+ JITCompiler::ConvertibleLoadLabel propertyStorageLoad = m_jit.convertibleLoadPtr(JITCompiler::Address(basePayloadGPR, JSObject::offsetOfOutOfLineStorage()), scratchGPR);
JITCompiler::DataLabel32 tagStoreWithPatch = m_jit.store32WithAddressOffsetPatch(valueTagGPR, JITCompiler::Address(scratchGPR, OBJECT_OFFSETOF(EncodedValueDescriptor, asBits.tag)));
JITCompiler::DataLabel32 payloadStoreWithPatch = m_jit.store32WithAddressOffsetPatch(valuePayloadGPR, JITCompiler::Address(scratchGPR, OBJECT_OFFSETOF(EncodedValueDescriptor, asBits.payload)));
@@ -597,7 +597,7 @@
}
m_jit.addPropertyAccess(
PropertyAccessRecord(
- codeOrigin, structureToCompare, structureCheck,
+ codeOrigin, structureToCompare, structureCheck, propertyStorageLoad,
JITCompiler::DataLabelCompact(tagStoreWithPatch.label()),
JITCompiler::DataLabelCompact(payloadStoreWithPatch.label()),
slowPath.get(), doneLabel, safeCast<int8_t>(basePayloadGPR),
@@ -3550,7 +3550,7 @@
GPRReg baseGPR = base.gpr();
GPRReg resultGPR = result.gpr();
- m_jit.loadPtr(JITCompiler::Address(baseGPR, JSObject::offsetOfPropertyStorage()), resultGPR);
+ m_jit.loadPtr(JITCompiler::Address(baseGPR, JSObject::offsetOfOutOfLineStorage()), resultGPR);
storageResult(resultGPR, m_compileIndex);
break;
@@ -3891,8 +3891,13 @@
JITCompiler::Jump structuresNotMatch = m_jit.branchPtr(JITCompiler::NotEqual, resultPayloadGPR, JITCompiler::Address(globalObjectGPR, JSCell::structureOffset()));
// Fast case
- m_jit.loadPtr(JITCompiler::Address(globalObjectGPR, JSObject::offsetOfPropertyStorage()), resultPayloadGPR);
+ m_jit.loadPtr(JITCompiler::Address(globalObjectGPR, JSObject::offsetOfOutOfLineStorage()), resultPayloadGPR);
m_jit.load32(JITCompiler::Address(resolveInfoGPR, OBJECT_OFFSETOF(GlobalResolveInfo, offset)), resolveInfoGPR);
+#if DFG_ENABLE(JIT_ASSERT)
+ JITCompiler::Jump isOutOfLine = m_jit.branch32(JITCompiler::GreaterThanOrEqual, resolveInfoGPR, TrustedImm32(inlineStorageCapacity));
+ m_jit.breakpoint();
+ isOutOfLine.link(&m_jit);
+#endif
m_jit.load32(JITCompiler::BaseIndex(resultPayloadGPR, resolveInfoGPR, JITCompiler::TimesEight, OBJECT_OFFSETOF(EncodedValueDescriptor, asBits.tag)), resultTagGPR);
m_jit.load32(JITCompiler::BaseIndex(resultPayloadGPR, resolveInfoGPR, JITCompiler::TimesEight, OBJECT_OFFSETOF(EncodedValueDescriptor, asBits.payload)), resultPayloadGPR);
diff --git a/Source/JavaScriptCore/dfg/DFGSpeculativeJIT64.cpp b/Source/JavaScriptCore/dfg/DFGSpeculativeJIT64.cpp
index 54575aa..27eb28f 100644
--- a/Source/JavaScriptCore/dfg/DFGSpeculativeJIT64.cpp
+++ b/Source/JavaScriptCore/dfg/DFGSpeculativeJIT64.cpp
@@ -497,7 +497,8 @@
JITCompiler::DataLabelPtr structureToCompare;
JITCompiler::PatchableJump structureCheck = m_jit.patchableBranchPtrWithPatch(JITCompiler::NotEqual, JITCompiler::Address(baseGPR, JSCell::structureOffset()), structureToCompare, JITCompiler::TrustedImmPtr(reinterpret_cast<void*>(-1)));
- m_jit.loadPtr(JITCompiler::Address(baseGPR, JSObject::offsetOfPropertyStorage()), resultGPR);
+ JITCompiler::ConvertibleLoadLabel propertyStorageLoad =
+ m_jit.convertibleLoadPtr(JITCompiler::Address(baseGPR, JSObject::offsetOfOutOfLineStorage()), resultGPR);
JITCompiler::DataLabelCompact loadWithPatch = m_jit.loadPtrWithCompactAddressOffsetPatch(JITCompiler::Address(resultGPR, 0), resultGPR);
JITCompiler::Label doneLabel = m_jit.label();
@@ -517,8 +518,8 @@
}
m_jit.addPropertyAccess(
PropertyAccessRecord(
- codeOrigin, structureToCompare, structureCheck, loadWithPatch, slowPath.get(),
- doneLabel, safeCast<int8_t>(baseGPR), safeCast<int8_t>(resultGPR),
+ codeOrigin, structureToCompare, structureCheck, propertyStorageLoad, loadWithPatch,
+ slowPath.get(), doneLabel, safeCast<int8_t>(baseGPR), safeCast<int8_t>(resultGPR),
safeCast<int8_t>(scratchGPR),
spillMode == NeedToSpill ? PropertyAccessRecord::RegistersInUse : PropertyAccessRecord::RegistersFlushed));
addSlowPathGenerator(slowPath.release());
@@ -536,7 +537,8 @@
writeBarrier(baseGPR, valueGPR, valueUse, WriteBarrierForPropertyAccess, scratchGPR);
- m_jit.loadPtr(JITCompiler::Address(baseGPR, JSObject::offsetOfPropertyStorage()), scratchGPR);
+ JITCompiler::ConvertibleLoadLabel propertyStorageLoad =
+ m_jit.convertibleLoadPtr(JITCompiler::Address(baseGPR, JSObject::offsetOfOutOfLineStorage()), scratchGPR);
JITCompiler::DataLabel32 storeWithPatch = m_jit.storePtrWithAddressOffsetPatch(valueGPR, JITCompiler::Address(scratchGPR, 0));
JITCompiler::Label doneLabel = m_jit.label();
@@ -566,7 +568,11 @@
slowCases, this, optimizedCall, NoResult, valueGPR, baseGPR,
identifier(identifierNumber));
}
- m_jit.addPropertyAccess(PropertyAccessRecord(codeOrigin, structureToCompare, structureCheck, JITCompiler::DataLabelCompact(storeWithPatch.label()), slowPath.get(), doneLabel, safeCast<int8_t>(baseGPR), safeCast<int8_t>(valueGPR), safeCast<int8_t>(scratchGPR)));
+ m_jit.addPropertyAccess(
+ PropertyAccessRecord(
+ codeOrigin, structureToCompare, structureCheck, propertyStorageLoad,
+ JITCompiler::DataLabelCompact(storeWithPatch.label()), slowPath.get(), doneLabel,
+ safeCast<int8_t>(baseGPR), safeCast<int8_t>(valueGPR), safeCast<int8_t>(scratchGPR)));
addSlowPathGenerator(slowPath.release());
}
@@ -3574,7 +3580,7 @@
GPRReg baseGPR = base.gpr();
GPRReg resultGPR = result.gpr();
- m_jit.loadPtr(JITCompiler::Address(baseGPR, JSObject::offsetOfPropertyStorage()), resultGPR);
+ m_jit.loadPtr(JITCompiler::Address(baseGPR, JSObject::offsetOfOutOfLineStorage()), resultGPR);
storageResult(resultGPR, m_compileIndex);
break;
@@ -3890,9 +3896,14 @@
JITCompiler::Jump structuresDontMatch = m_jit.branchPtr(JITCompiler::NotEqual, resultGPR, JITCompiler::Address(globalObjectGPR, JSCell::structureOffset()));
// Fast case
- m_jit.loadPtr(JITCompiler::Address(globalObjectGPR, JSObject::offsetOfPropertyStorage()), resultGPR);
m_jit.load32(JITCompiler::Address(resolveInfoGPR, OBJECT_OFFSETOF(GlobalResolveInfo, offset)), resolveInfoGPR);
- m_jit.loadPtr(JITCompiler::BaseIndex(resultGPR, resolveInfoGPR, JITCompiler::ScalePtr), resultGPR);
+#if DFG_ENABLE(JIT_ASSERT)
+ JITCompiler::Jump isOutOfLine = m_jit.branch32(JITCompiler::GreaterThanOrEqual, resolveInfoGPR, TrustedImm32(inlineStorageCapacity));
+ m_jit.breakpoint();
+ isOutOfLine.link(&m_jit);
+#endif
+ m_jit.loadPtr(JITCompiler::Address(globalObjectGPR, JSObject::offsetOfOutOfLineStorage()), resultGPR);
+ m_jit.loadPtr(JITCompiler::BaseIndex(resultGPR, resolveInfoGPR, JITCompiler::ScalePtr, -inlineStorageCapacity * static_cast<ptrdiff_t>(sizeof(JSValue))), resultGPR);
addSlowPathGenerator(
slowPathCall(
diff --git a/Source/JavaScriptCore/heap/MarkStack.cpp b/Source/JavaScriptCore/heap/MarkStack.cpp
index 8c0fe66..f547b31 100644
--- a/Source/JavaScriptCore/heap/MarkStack.cpp
+++ b/Source/JavaScriptCore/heap/MarkStack.cpp
@@ -354,7 +354,7 @@
}
if (isJSFinalObject(cell)) {
- JSObject::visitChildren(const_cast<JSCell*>(cell), visitor);
+ JSFinalObject::visitChildren(const_cast<JSCell*>(cell), visitor);
return;
}
diff --git a/Source/JavaScriptCore/interpreter/Interpreter.cpp b/Source/JavaScriptCore/interpreter/Interpreter.cpp
index 4fdd79a..b6072a5 100644
--- a/Source/JavaScriptCore/interpreter/Interpreter.cpp
+++ b/Source/JavaScriptCore/interpreter/Interpreter.cpp
@@ -1822,7 +1822,7 @@
ASSERT(slot.slotBase().isObject());
JSObject* baseObject = asObject(slot.slotBase());
- size_t offset = slot.cachedOffset();
+ PropertyOffset offset = slot.cachedOffset();
// Since we're accessing a prototype in a loop, it's a good bet that it
// should not be treated as a dictionary.
@@ -1851,7 +1851,7 @@
return;
}
- size_t offset = slot.cachedOffset();
+ PropertyOffset offset = slot.cachedOffset();
size_t count = normalizePrototypeChain(callFrame, baseValue, slot.slotBase(), propertyName, offset);
if (!count) {
vPC[0] = getOpcode(op_get_by_id_generic);
@@ -3045,6 +3045,7 @@
vPC += OPCODE_LENGTH(op_resolve_with_this);
NEXT_INSTRUCTION();
}
+ DEFINE_OPCODE(op_get_by_id_out_of_line)
DEFINE_OPCODE(op_get_by_id) {
/* get_by_id dst(r) base(r) property(id) structure(sID) nop(n) nop(n) nop(n)
@@ -3527,6 +3528,7 @@
skip_get_string_length:
goto *(&&skip_put_by_id);
#endif
+ DEFINE_OPCODE(op_put_by_id_out_of_line)
DEFINE_OPCODE(op_put_by_id) {
/* put_by_id base(r) property(id) value(r) nop(n) nop(n) nop(n) nop(n) direct(b)
@@ -3565,6 +3567,8 @@
#endif
DEFINE_OPCODE(op_put_by_id_transition_direct)
DEFINE_OPCODE(op_put_by_id_transition_normal)
+ DEFINE_OPCODE(op_put_by_id_transition_direct_out_of_line)
+ DEFINE_OPCODE(op_put_by_id_transition_normal_out_of_line)
DEFINE_OPCODE(op_put_by_id_transition) {
/* op_put_by_id_transition base(r) property(id) value(r) oldStructure(sID) newStructure(sID) structureChain(chain) offset(n) direct(b)
@@ -3605,7 +3609,7 @@
baseObject->setStructureAndReallocateStorageIfNecessary(*globalData, newStructure);
int value = vPC[3].u.operand;
- unsigned offset = vPC[7].u.operand;
+ int offset = vPC[7].u.operand;
ASSERT(baseObject->offsetForLocation(baseObject->getDirectLocation(*globalData, codeBlock->identifier(vPC[2].u.operand))) == offset);
baseObject->putDirectOffset(callFrame->globalData(), offset, callFrame->r(value).jsValue());
@@ -3639,7 +3643,7 @@
ASSERT(baseCell->isObject());
JSObject* baseObject = asObject(baseCell);
int value = vPC[3].u.operand;
- unsigned offset = vPC[5].u.operand;
+ int offset = vPC[5].u.operand;
ASSERT(baseObject->offsetForLocation(baseObject->getDirectLocation(*globalData, codeBlock->identifier(vPC[2].u.operand))) == offset);
baseObject->putDirectOffset(callFrame->globalData(), offset, callFrame->r(value).jsValue());
@@ -3717,7 +3721,7 @@
JSValue expectedSubscript = callFrame->r(expected).jsValue();
int index = callFrame->r(i).i() - 1;
JSValue result;
- int offset = 0;
+ PropertyOffset offset = 0;
if (subscript == expectedSubscript && baseValue.isCell() && (baseValue.asCell()->structure() == it->cachedStructure()) && it->getOffset(index, offset)) {
callFrame->uncheckedR(dst) = JSValue(asObject(baseValue)->getDirectOffset(offset));
vPC += OPCODE_LENGTH(op_get_by_pname);
diff --git a/Source/JavaScriptCore/jit/JIT.cpp b/Source/JavaScriptCore/jit/JIT.cpp
index 1bc4fff..285355f 100644
--- a/Source/JavaScriptCore/jit/JIT.cpp
+++ b/Source/JavaScriptCore/jit/JIT.cpp
@@ -255,6 +255,7 @@
DEFINE_OP(op_create_activation)
DEFINE_OP(op_eq)
DEFINE_OP(op_eq_null)
+ case op_get_by_id_out_of_line:
DEFINE_OP(op_get_by_id)
DEFINE_OP(op_get_arguments_length)
DEFINE_OP(op_get_by_val)
@@ -319,8 +320,11 @@
DEFINE_OP(op_profile_will_call)
DEFINE_OP(op_push_new_scope)
DEFINE_OP(op_push_scope)
+ case op_put_by_id_out_of_line:
case op_put_by_id_transition_direct:
case op_put_by_id_transition_normal:
+ case op_put_by_id_transition_direct_out_of_line:
+ case op_put_by_id_transition_normal_out_of_line:
DEFINE_OP(op_put_by_id)
DEFINE_OP(op_put_by_index)
DEFINE_OP(op_put_by_val)
@@ -441,6 +445,7 @@
DEFINE_SLOWCASE_OP(op_create_this)
DEFINE_SLOWCASE_OP(op_div)
DEFINE_SLOWCASE_OP(op_eq)
+ case op_get_by_id_out_of_line:
DEFINE_SLOWCASE_OP(op_get_by_id)
DEFINE_SLOWCASE_OP(op_get_arguments_length)
DEFINE_SLOWCASE_OP(op_get_by_val)
@@ -478,8 +483,11 @@
DEFINE_SLOWCASE_OP(op_post_inc)
DEFINE_SLOWCASE_OP(op_pre_dec)
DEFINE_SLOWCASE_OP(op_pre_inc)
+ case op_put_by_id_out_of_line:
case op_put_by_id_transition_direct:
case op_put_by_id_transition_normal:
+ case op_put_by_id_transition_direct_out_of_line:
+ case op_put_by_id_transition_normal_out_of_line:
DEFINE_SLOWCASE_OP(op_put_by_id)
DEFINE_SLOWCASE_OP(op_put_by_val)
DEFINE_SLOWCASE_OP(op_put_global_var_check);
@@ -537,6 +545,7 @@
CodeLocationLabel hotPathBeginLocation = linkBuffer.locationOf(hotPathBegin);
info.patch.baseline.u.get.structureToCompare = MacroAssembler::differenceBetweenCodePtr(hotPathBeginLocation, linkBuffer.locationOf(getStructureToCompare));
info.patch.baseline.u.get.structureCheck = MacroAssembler::differenceBetweenCodePtr(hotPathBeginLocation, linkBuffer.locationOf(getStructureCheck));
+ info.patch.baseline.u.get.propertyStorageLoad = MacroAssembler::differenceBetweenCodePtr(hotPathBeginLocation, linkBuffer.locationOf(propertyStorageLoad));
#if USE(JSVALUE64)
info.patch.baseline.u.get.displacementLabel = MacroAssembler::differenceBetweenCodePtr(hotPathBeginLocation, linkBuffer.locationOf(getDisplacementLabel));
#else
@@ -550,6 +559,7 @@
case PutById:
CodeLocationLabel hotPathBeginLocation = linkBuffer.locationOf(hotPathBegin);
info.patch.baseline.u.put.structureToCompare = MacroAssembler::differenceBetweenCodePtr(hotPathBeginLocation, linkBuffer.locationOf(putStructureToCompare));
+ info.patch.baseline.u.put.propertyStorageLoad = MacroAssembler::differenceBetweenCodePtr(hotPathBeginLocation, linkBuffer.locationOf(propertyStorageLoad));
#if USE(JSVALUE64)
info.patch.baseline.u.put.displacementLabel = MacroAssembler::differenceBetweenCodePtr(hotPathBeginLocation, linkBuffer.locationOf(putDisplacementLabel));
#else
diff --git a/Source/JavaScriptCore/jit/JIT.h b/Source/JavaScriptCore/jit/JIT.h
index 67aa185..987c4a1 100644
--- a/Source/JavaScriptCore/jit/JIT.h
+++ b/Source/JavaScriptCore/jit/JIT.h
@@ -157,6 +157,7 @@
MacroAssembler::Label hotPathBegin;
MacroAssembler::DataLabelPtr getStructureToCompare;
MacroAssembler::PatchableJump getStructureCheck;
+ MacroAssembler::ConvertibleLoadLabel propertyStorageLoad;
#if USE(JSVALUE64)
MacroAssembler::DataLabelCompact getDisplacementLabel;
#else
@@ -185,17 +186,24 @@
#endif
- PropertyStubCompilationInfo(PropertyStubGetById_T, unsigned bytecodeIndex, MacroAssembler::Label hotPathBegin,
+ PropertyStubCompilationInfo(
+ PropertyStubGetById_T, unsigned bytecodeIndex, MacroAssembler::Label hotPathBegin,
+ MacroAssembler::DataLabelPtr structureToCompare,
+ MacroAssembler::PatchableJump structureCheck,
+ MacroAssembler::ConvertibleLoadLabel propertyStorageLoad,
#if USE(JSVALUE64)
- MacroAssembler::DataLabelPtr structureToCompare, MacroAssembler::PatchableJump structureCheck, MacroAssembler::DataLabelCompact displacementLabel, MacroAssembler::Label putResult)
+ MacroAssembler::DataLabelCompact displacementLabel,
#else
- MacroAssembler::DataLabelPtr structureToCompare, MacroAssembler::PatchableJump structureCheck, MacroAssembler::DataLabelCompact displacementLabel1, MacroAssembler::DataLabelCompact displacementLabel2, MacroAssembler::Label putResult)
+ MacroAssembler::DataLabelCompact displacementLabel1,
+ MacroAssembler::DataLabelCompact displacementLabel2,
#endif
+ MacroAssembler::Label putResult)
: m_type(GetById)
, bytecodeIndex(bytecodeIndex)
, hotPathBegin(hotPathBegin)
, getStructureToCompare(structureToCompare)
, getStructureCheck(structureCheck)
+ , propertyStorageLoad(propertyStorageLoad)
#if USE(JSVALUE64)
, getDisplacementLabel(displacementLabel)
#else
@@ -206,15 +214,21 @@
{
}
- PropertyStubCompilationInfo(PropertyStubPutById_T, unsigned bytecodeIndex, MacroAssembler::Label hotPathBegin,
+ PropertyStubCompilationInfo(
+ PropertyStubPutById_T, unsigned bytecodeIndex, MacroAssembler::Label hotPathBegin,
+ MacroAssembler::DataLabelPtr structureToCompare,
+ MacroAssembler::ConvertibleLoadLabel propertyStorageLoad,
#if USE(JSVALUE64)
- MacroAssembler::DataLabelPtr structureToCompare, MacroAssembler::DataLabel32 displacementLabel)
+ MacroAssembler::DataLabel32 displacementLabel
#else
- MacroAssembler::DataLabelPtr structureToCompare, MacroAssembler::DataLabel32 displacementLabel1, MacroAssembler::DataLabel32 displacementLabel2)
+ MacroAssembler::DataLabel32 displacementLabel1,
+ MacroAssembler::DataLabel32 displacementLabel2
#endif
+ )
: m_type(PutById)
, bytecodeIndex(bytecodeIndex)
, hotPathBegin(hotPathBegin)
+ , propertyStorageLoad(propertyStorageLoad)
, putStructureToCompare(structureToCompare)
#if USE(JSVALUE64)
, putDisplacementLabel(displacementLabel)
@@ -295,40 +309,40 @@
return JIT(globalData, codeBlock).privateCompile(functionEntryArityCheck, effort);
}
- static void compileGetByIdProto(JSGlobalData* globalData, CallFrame* callFrame, CodeBlock* codeBlock, StructureStubInfo* stubInfo, Structure* structure, Structure* prototypeStructure, const Identifier& ident, const PropertySlot& slot, size_t cachedOffset, ReturnAddressPtr returnAddress)
+ static void compileGetByIdProto(JSGlobalData* globalData, CallFrame* callFrame, CodeBlock* codeBlock, StructureStubInfo* stubInfo, Structure* structure, Structure* prototypeStructure, const Identifier& ident, const PropertySlot& slot, PropertyOffset cachedOffset, ReturnAddressPtr returnAddress)
{
JIT jit(globalData, codeBlock);
jit.m_bytecodeOffset = stubInfo->bytecodeIndex;
jit.privateCompileGetByIdProto(stubInfo, structure, prototypeStructure, ident, slot, cachedOffset, returnAddress, callFrame);
}
- static void compileGetByIdSelfList(JSGlobalData* globalData, CodeBlock* codeBlock, StructureStubInfo* stubInfo, PolymorphicAccessStructureList* polymorphicStructures, int currentIndex, Structure* structure, const Identifier& ident, const PropertySlot& slot, size_t cachedOffset)
+ static void compileGetByIdSelfList(JSGlobalData* globalData, CodeBlock* codeBlock, StructureStubInfo* stubInfo, PolymorphicAccessStructureList* polymorphicStructures, int currentIndex, Structure* structure, const Identifier& ident, const PropertySlot& slot, PropertyOffset cachedOffset)
{
JIT jit(globalData, codeBlock);
jit.m_bytecodeOffset = stubInfo->bytecodeIndex;
jit.privateCompileGetByIdSelfList(stubInfo, polymorphicStructures, currentIndex, structure, ident, slot, cachedOffset);
}
- static void compileGetByIdProtoList(JSGlobalData* globalData, CallFrame* callFrame, CodeBlock* codeBlock, StructureStubInfo* stubInfo, PolymorphicAccessStructureList* prototypeStructureList, int currentIndex, Structure* structure, Structure* prototypeStructure, const Identifier& ident, const PropertySlot& slot, size_t cachedOffset)
+ static void compileGetByIdProtoList(JSGlobalData* globalData, CallFrame* callFrame, CodeBlock* codeBlock, StructureStubInfo* stubInfo, PolymorphicAccessStructureList* prototypeStructureList, int currentIndex, Structure* structure, Structure* prototypeStructure, const Identifier& ident, const PropertySlot& slot, PropertyOffset cachedOffset)
{
JIT jit(globalData, codeBlock);
jit.m_bytecodeOffset = stubInfo->bytecodeIndex;
jit.privateCompileGetByIdProtoList(stubInfo, prototypeStructureList, currentIndex, structure, prototypeStructure, ident, slot, cachedOffset, callFrame);
}
- static void compileGetByIdChainList(JSGlobalData* globalData, CallFrame* callFrame, CodeBlock* codeBlock, StructureStubInfo* stubInfo, PolymorphicAccessStructureList* prototypeStructureList, int currentIndex, Structure* structure, StructureChain* chain, size_t count, const Identifier& ident, const PropertySlot& slot, size_t cachedOffset)
+ static void compileGetByIdChainList(JSGlobalData* globalData, CallFrame* callFrame, CodeBlock* codeBlock, StructureStubInfo* stubInfo, PolymorphicAccessStructureList* prototypeStructureList, int currentIndex, Structure* structure, StructureChain* chain, size_t count, const Identifier& ident, const PropertySlot& slot, PropertyOffset cachedOffset)
{
JIT jit(globalData, codeBlock);
jit.m_bytecodeOffset = stubInfo->bytecodeIndex;
jit.privateCompileGetByIdChainList(stubInfo, prototypeStructureList, currentIndex, structure, chain, count, ident, slot, cachedOffset, callFrame);
}
- static void compileGetByIdChain(JSGlobalData* globalData, CallFrame* callFrame, CodeBlock* codeBlock, StructureStubInfo* stubInfo, Structure* structure, StructureChain* chain, size_t count, const Identifier& ident, const PropertySlot& slot, size_t cachedOffset, ReturnAddressPtr returnAddress)
+ static void compileGetByIdChain(JSGlobalData* globalData, CallFrame* callFrame, CodeBlock* codeBlock, StructureStubInfo* stubInfo, Structure* structure, StructureChain* chain, size_t count, const Identifier& ident, const PropertySlot& slot, PropertyOffset cachedOffset, ReturnAddressPtr returnAddress)
{
JIT jit(globalData, codeBlock);
jit.m_bytecodeOffset = stubInfo->bytecodeIndex;
jit.privateCompileGetByIdChain(stubInfo, structure, chain, count, ident, slot, cachedOffset, returnAddress, callFrame);
}
- static void compilePutByIdTransition(JSGlobalData* globalData, CodeBlock* codeBlock, StructureStubInfo* stubInfo, Structure* oldStructure, Structure* newStructure, size_t cachedOffset, StructureChain* chain, ReturnAddressPtr returnAddress, bool direct)
+ static void compilePutByIdTransition(JSGlobalData* globalData, CodeBlock* codeBlock, StructureStubInfo* stubInfo, Structure* oldStructure, Structure* newStructure, PropertyOffset cachedOffset, StructureChain* chain, ReturnAddressPtr returnAddress, bool direct)
{
JIT jit(globalData, codeBlock);
jit.m_bytecodeOffset = stubInfo->bytecodeIndex;
@@ -358,9 +372,9 @@
static void resetPatchGetById(RepatchBuffer&, StructureStubInfo*);
static void resetPatchPutById(RepatchBuffer&, StructureStubInfo*);
- static void patchGetByIdSelf(CodeBlock* codeblock, StructureStubInfo*, Structure*, size_t cachedOffset, ReturnAddressPtr returnAddress);
- static void patchPutByIdReplace(CodeBlock* codeblock, StructureStubInfo*, Structure*, size_t cachedOffset, ReturnAddressPtr returnAddress, bool direct);
- static void patchMethodCallProto(JSGlobalData&, CodeBlock* codeblock, MethodCallLinkInfo&, StructureStubInfo&, JSObject*, Structure*, JSObject*, ReturnAddressPtr);
+ static void patchGetByIdSelf(CodeBlock*, StructureStubInfo*, Structure*, PropertyOffset cachedOffset, ReturnAddressPtr);
+ static void patchPutByIdReplace(CodeBlock*, StructureStubInfo*, Structure*, PropertyOffset cachedOffset, ReturnAddressPtr, bool direct);
+ static void patchMethodCallProto(JSGlobalData&, CodeBlock*, MethodCallLinkInfo&, StructureStubInfo&, JSObject*, Structure*, JSObject*, ReturnAddressPtr);
static void compilePatchGetArrayLength(JSGlobalData* globalData, CodeBlock* codeBlock, ReturnAddressPtr returnAddress)
{
@@ -377,12 +391,12 @@
void privateCompileLinkPass();
void privateCompileSlowCases();
JITCode privateCompile(CodePtr* functionEntryArityCheck, JITCompilationEffort);
- void privateCompileGetByIdProto(StructureStubInfo*, Structure*, Structure* prototypeStructure, const Identifier&, const PropertySlot&, size_t cachedOffset, ReturnAddressPtr returnAddress, CallFrame* callFrame);
- void privateCompileGetByIdSelfList(StructureStubInfo*, PolymorphicAccessStructureList*, int, Structure*, const Identifier&, const PropertySlot&, size_t cachedOffset);
- void privateCompileGetByIdProtoList(StructureStubInfo*, PolymorphicAccessStructureList*, int, Structure*, Structure* prototypeStructure, const Identifier&, const PropertySlot&, size_t cachedOffset, CallFrame* callFrame);
- void privateCompileGetByIdChainList(StructureStubInfo*, PolymorphicAccessStructureList*, int, Structure*, StructureChain* chain, size_t count, const Identifier&, const PropertySlot&, size_t cachedOffset, CallFrame* callFrame);
- void privateCompileGetByIdChain(StructureStubInfo*, Structure*, StructureChain*, size_t count, const Identifier&, const PropertySlot&, size_t cachedOffset, ReturnAddressPtr returnAddress, CallFrame* callFrame);
- void privateCompilePutByIdTransition(StructureStubInfo*, Structure*, Structure*, size_t cachedOffset, StructureChain*, ReturnAddressPtr returnAddress, bool direct);
+ void privateCompileGetByIdProto(StructureStubInfo*, Structure*, Structure* prototypeStructure, const Identifier&, const PropertySlot&, PropertyOffset cachedOffset, ReturnAddressPtr, CallFrame*);
+ void privateCompileGetByIdSelfList(StructureStubInfo*, PolymorphicAccessStructureList*, int, Structure*, const Identifier&, const PropertySlot&, PropertyOffset cachedOffset);
+ void privateCompileGetByIdProtoList(StructureStubInfo*, PolymorphicAccessStructureList*, int, Structure*, Structure* prototypeStructure, const Identifier&, const PropertySlot&, PropertyOffset cachedOffset, CallFrame*);
+ void privateCompileGetByIdChainList(StructureStubInfo*, PolymorphicAccessStructureList*, int, Structure*, StructureChain*, size_t count, const Identifier&, const PropertySlot&, PropertyOffset cachedOffset, CallFrame*);
+ void privateCompileGetByIdChain(StructureStubInfo*, Structure*, StructureChain*, size_t count, const Identifier&, const PropertySlot&, PropertyOffset cachedOffset, ReturnAddressPtr, CallFrame*);
+ void privateCompilePutByIdTransition(StructureStubInfo*, Structure*, Structure*, PropertyOffset cachedOffset, StructureChain*, ReturnAddressPtr, bool direct);
PassRefPtr<ExecutableMemoryHandle> privateCompileCTIMachineTrampolines(JSGlobalData*, TrampolineStructure*);
Label privateCompileCTINativeCall(JSGlobalData*, bool isConstruct = false);
@@ -436,6 +450,8 @@
void emitValueProfilingSite() { }
#endif
+ enum FinalObjectMode { MayBeFinal, KnownNotFinal };
+
#if USE(JSVALUE32_64)
bool getOperandConstantImmediateInt(unsigned op1, unsigned op2, unsigned& op, int32_t& constant);
@@ -468,10 +484,10 @@
void compileGetByIdHotPath();
void compileGetByIdSlowCase(int resultVReg, int baseVReg, Identifier* ident, Vector<SlowCaseEntry>::iterator& iter, bool isMethodCheck = false);
- void compileGetDirectOffset(RegisterID base, RegisterID resultTag, RegisterID resultPayload, size_t cachedOffset);
- void compileGetDirectOffset(JSObject* base, RegisterID resultTag, RegisterID resultPayload, size_t cachedOffset);
- void compileGetDirectOffset(RegisterID base, RegisterID resultTag, RegisterID resultPayload, RegisterID offset);
- void compilePutDirectOffset(RegisterID base, RegisterID valueTag, RegisterID valuePayload, size_t cachedOffset);
+ void compileGetDirectOffset(RegisterID base, RegisterID resultTag, RegisterID resultPayload, PropertyOffset cachedOffset);
+ void compileGetDirectOffset(JSObject* base, RegisterID resultTag, RegisterID resultPayload, PropertyOffset cachedOffset);
+ void compileGetDirectOffset(RegisterID base, RegisterID resultTag, RegisterID resultPayload, RegisterID offset, FinalObjectMode = MayBeFinal);
+ void compilePutDirectOffset(RegisterID base, RegisterID valueTag, RegisterID valuePayload, PropertyOffset cachedOffset);
// Arithmetic opcode helpers
void emitAdd32Constant(unsigned dst, unsigned op, int32_t constant, ResultType opType);
@@ -547,10 +563,10 @@
void compileGetByIdHotPath(int baseVReg, Identifier*);
void compileGetByIdSlowCase(int resultVReg, int baseVReg, Identifier* ident, Vector<SlowCaseEntry>::iterator& iter, bool isMethodCheck = false);
- void compileGetDirectOffset(RegisterID base, RegisterID result, size_t cachedOffset);
- void compileGetDirectOffset(JSObject* base, RegisterID result, size_t cachedOffset);
- void compileGetDirectOffset(RegisterID base, RegisterID result, RegisterID offset, RegisterID scratch);
- void compilePutDirectOffset(RegisterID base, RegisterID value, size_t cachedOffset);
+ void compileGetDirectOffset(RegisterID base, RegisterID result, PropertyOffset cachedOffset);
+ void compileGetDirectOffset(JSObject* base, RegisterID result, PropertyOffset cachedOffset);
+ void compileGetDirectOffset(RegisterID base, RegisterID result, RegisterID offset, RegisterID scratch, FinalObjectMode = MayBeFinal);
+ void compilePutDirectOffset(RegisterID base, RegisterID value, PropertyOffset cachedOffset);
#endif // USE(JSVALUE32_64)
diff --git a/Source/JavaScriptCore/jit/JITInlineMethods.h b/Source/JavaScriptCore/jit/JITInlineMethods.h
index fdb9564..d1cee7e 100644
--- a/Source/JavaScriptCore/jit/JITInlineMethods.h
+++ b/Source/JavaScriptCore/jit/JITInlineMethods.h
@@ -429,11 +429,7 @@
storePtr(TrustedImmPtr(0), Address(result, JSObject::offsetOfInheritorID()));
// initialize the object's property storage pointer
- if (ClassType::hasInlineStorage()) {
- addPtr(TrustedImm32(sizeof(JSObject)), result, storagePtr);
- storePtr(storagePtr, Address(result, ClassType::offsetOfPropertyStorage()));
- } else
- storePtr(TrustedImmPtr(0), Address(result, ClassType::offsetOfPropertyStorage()));
+ storePtr(TrustedImmPtr(0), Address(result, ClassType::offsetOfOutOfLineStorage()));
}
template <typename T> inline void JIT::emitAllocateJSFinalObject(T structure, RegisterID result, RegisterID scratch)
diff --git a/Source/JavaScriptCore/jit/JITOpcodes.cpp b/Source/JavaScriptCore/jit/JITOpcodes.cpp
index d96cfd9..c0af6f9 100644
--- a/Source/JavaScriptCore/jit/JITOpcodes.cpp
+++ b/Source/JavaScriptCore/jit/JITOpcodes.cpp
@@ -701,9 +701,8 @@
// Load cached property
// Assume that the global object always uses external storage.
- loadPtr(Address(regT0, OBJECT_OFFSETOF(JSGlobalObject, m_propertyStorage)), regT0);
load32(Address(regT2, OBJECT_OFFSETOF(GlobalResolveInfo, offset)), regT1);
- loadPtr(BaseIndex(regT0, regT1, ScalePtr), regT0);
+ compileGetDirectOffset(regT0, regT0, regT1, regT0, KnownNotFinal);
emitValueProfilingSite();
emitPutVirtualRegister(currentInstruction[1].u.operand);
}
diff --git a/Source/JavaScriptCore/jit/JITOpcodes32_64.cpp b/Source/JavaScriptCore/jit/JITOpcodes32_64.cpp
index 4f85895..095ea57 100644
--- a/Source/JavaScriptCore/jit/JITOpcodes32_64.cpp
+++ b/Source/JavaScriptCore/jit/JITOpcodes32_64.cpp
@@ -794,16 +794,14 @@
// Verify structure.
- move(TrustedImmPtr(globalObject), regT0);
+ move(TrustedImmPtr(globalObject), regT2);
move(TrustedImmPtr(resolveInfoAddress), regT3);
loadPtr(Address(regT3, OBJECT_OFFSETOF(GlobalResolveInfo, structure)), regT1);
- addSlowCase(branchPtr(NotEqual, regT1, Address(regT0, JSCell::structureOffset())));
+ addSlowCase(branchPtr(NotEqual, regT1, Address(regT2, JSCell::structureOffset())));
// Load property.
- loadPtr(Address(regT0, OBJECT_OFFSETOF(JSGlobalObject, m_propertyStorage)), regT2);
load32(Address(regT3, OBJECT_OFFSETOF(GlobalResolveInfo, offset)), regT3);
- load32(BaseIndex(regT2, regT3, TimesEight, OBJECT_OFFSETOF(JSValue, u.asBits.payload)), regT0); // payload
- load32(BaseIndex(regT2, regT3, TimesEight, OBJECT_OFFSETOF(JSValue, u.asBits.tag)), regT1); // tag
+ compileGetDirectOffset(regT2, regT1, regT0, regT3, KnownNotFinal);
emitValueProfilingSite();
emitStore(dst, regT1, regT0);
map(m_bytecodeOffset + (dynamic ? OPCODE_LENGTH(op_resolve_global_dynamic) : OPCODE_LENGTH(op_resolve_global)), dst, regT1, regT0);
diff --git a/Source/JavaScriptCore/jit/JITPropertyAccess.cpp b/Source/JavaScriptCore/jit/JITPropertyAccess.cpp
index 7478f91..72f8d47 100644
--- a/Source/JavaScriptCore/jit/JITPropertyAccess.cpp
+++ b/Source/JavaScriptCore/jit/JITPropertyAccess.cpp
@@ -151,10 +151,26 @@
emitValueProfilingSite();
}
-void JIT::compileGetDirectOffset(RegisterID base, RegisterID result, RegisterID offset, RegisterID scratch)
+void JIT::compileGetDirectOffset(RegisterID base, RegisterID result, RegisterID offset, RegisterID scratch, FinalObjectMode finalObjectMode)
{
- loadPtr(Address(base, JSObject::offsetOfPropertyStorage()), scratch);
- loadPtr(BaseIndex(scratch, offset, ScalePtr, 0), result);
+ ASSERT(sizeof(JSValue) == 8);
+
+ if (finalObjectMode == MayBeFinal) {
+ Jump isInline = branch32(LessThan, offset, TrustedImm32(inlineStorageCapacity));
+ loadPtr(Address(base, JSObject::offsetOfOutOfLineStorage()), scratch);
+ Jump done = jump();
+ isInline.link(this);
+ addPtr(TrustedImm32(JSObject::offsetOfInlineStorage() + inlineStorageCapacity * sizeof(EncodedJSValue)), base, scratch);
+ done.link(this);
+ } else {
+#if !ASSERT_DISABLED
+ Jump isOutOfLine = branch32(GreaterThanOrEqual, offset, TrustedImm32(inlineStorageCapacity));
+ breakpoint();
+ isOutOfLine.link(this);
+#endif
+ loadPtr(Address(base, JSObject::offsetOfOutOfLineStorage()), scratch);
+ }
+ loadPtr(BaseIndex(scratch, offset, ScalePtr, -inlineStorageCapacity * static_cast<ptrdiff_t>(sizeof(JSValue))), result);
}
void JIT::emit_op_get_by_pname(Instruction* currentInstruction)
@@ -283,7 +299,8 @@
void JIT::emit_op_method_check(Instruction* currentInstruction)
{
// Assert that the following instruction is a get_by_id.
- ASSERT(m_interpreter->getOpcodeID((currentInstruction + OPCODE_LENGTH(op_method_check))->u.opcode) == op_get_by_id);
+ ASSERT(m_interpreter->getOpcodeID((currentInstruction + OPCODE_LENGTH(op_method_check))->u.opcode) == op_get_by_id
+ || m_interpreter->getOpcodeID((currentInstruction + OPCODE_LENGTH(op_method_check))->u.opcode) == op_get_by_id_out_of_line);
currentInstruction += OPCODE_LENGTH(op_method_check);
unsigned resultVReg = currentInstruction[1].u.operand;
@@ -373,14 +390,14 @@
PatchableJump structureCheck = patchableBranchPtrWithPatch(NotEqual, Address(regT0, JSCell::structureOffset()), structureToCompare, TrustedImmPtr(reinterpret_cast<void*>(patchGetByIdDefaultStructure)));
addSlowCase(structureCheck);
- loadPtr(Address(regT0, JSObject::offsetOfPropertyStorage()), regT0);
+ ConvertibleLoadLabel propertyStorageLoad = convertibleLoadPtr(Address(regT0, JSObject::offsetOfOutOfLineStorage()), regT0);
DataLabelCompact displacementLabel = loadPtrWithCompactAddressOffsetPatch(Address(regT0, patchGetByIdDefaultOffset), regT0);
Label putResult(this);
END_UNINTERRUPTED_SEQUENCE(sequenceGetByIdHotPath);
- m_propertyAccessCompilationInfo.append(PropertyStubCompilationInfo(PropertyStubGetById, m_bytecodeOffset, hotPathBegin, structureToCompare, structureCheck, displacementLabel, putResult));
+ m_propertyAccessCompilationInfo.append(PropertyStubCompilationInfo(PropertyStubGetById, m_bytecodeOffset, hotPathBegin, structureToCompare, structureCheck, propertyStorageLoad, displacementLabel, putResult));
}
void JIT::emitSlow_op_get_by_id(Instruction* currentInstruction, Vector<SlowCaseEntry>::iterator& iter)
@@ -440,14 +457,14 @@
DataLabelPtr structureToCompare;
addSlowCase(branchPtrWithPatch(NotEqual, Address(regT0, JSCell::structureOffset()), structureToCompare, TrustedImmPtr(reinterpret_cast<void*>(patchGetByIdDefaultStructure))));
- loadPtr(Address(regT0, JSObject::offsetOfPropertyStorage()), regT2);
+ ConvertibleLoadLabel propertyStorageLoad = convertibleLoadPtr(Address(regT0, JSObject::offsetOfOutOfLineStorage()), regT2);
DataLabel32 displacementLabel = storePtrWithAddressOffsetPatch(regT1, Address(regT2, patchPutByIdDefaultOffset));
END_UNINTERRUPTED_SEQUENCE(sequencePutById);
emitWriteBarrier(regT0, regT1, regT2, regT3, ShouldFilterImmediates, WriteBarrierForPropertyAccess);
- m_propertyAccessCompilationInfo.append(PropertyStubCompilationInfo(PropertyStubPutById, m_bytecodeOffset, hotPathBegin, structureToCompare, displacementLabel));
+ m_propertyAccessCompilationInfo.append(PropertyStubCompilationInfo(PropertyStubPutById, m_bytecodeOffset, hotPathBegin, structureToCompare, propertyStorageLoad, displacementLabel));
}
void JIT::emitSlow_op_put_by_id(Instruction* currentInstruction, Vector<SlowCaseEntry>::iterator& iter)
@@ -471,28 +488,41 @@
// Compile a store into an object's property storage. May overwrite the
// value in objectReg.
-void JIT::compilePutDirectOffset(RegisterID base, RegisterID value, size_t cachedOffset)
+void JIT::compilePutDirectOffset(RegisterID base, RegisterID value, PropertyOffset cachedOffset)
{
- int offset = cachedOffset * sizeof(JSValue);
- loadPtr(Address(base, JSObject::offsetOfPropertyStorage()), base);
- storePtr(value, Address(base, offset));
+ if (isInlineOffset(cachedOffset)) {
+ storePtr(value, Address(base, JSObject::offsetOfInlineStorage() + sizeof(JSValue) * offsetInInlineStorage(cachedOffset)));
+ return;
+ }
+
+ loadPtr(Address(base, JSObject::offsetOfOutOfLineStorage()), base);
+ storePtr(value, Address(base, sizeof(JSValue) * offsetInOutOfLineStorage(cachedOffset)));
}
// Compile a load from an object's property storage. May overwrite base.
-void JIT::compileGetDirectOffset(RegisterID base, RegisterID result, size_t cachedOffset)
+void JIT::compileGetDirectOffset(RegisterID base, RegisterID result, PropertyOffset cachedOffset)
{
- int offset = cachedOffset * sizeof(JSValue);
- loadPtr(Address(base, JSObject::offsetOfPropertyStorage()), result);
- loadPtr(Address(result, offset), result);
+ if (isInlineOffset(cachedOffset)) {
+ loadPtr(Address(base, JSObject::offsetOfInlineStorage() + sizeof(JSValue) * offsetInInlineStorage(cachedOffset)), result);
+ return;
+ }
+
+ loadPtr(Address(base, JSObject::offsetOfOutOfLineStorage()), result);
+ loadPtr(Address(result, sizeof(JSValue) * offsetInOutOfLineStorage(cachedOffset)), result);
}
-void JIT::compileGetDirectOffset(JSObject* base, RegisterID result, size_t cachedOffset)
+void JIT::compileGetDirectOffset(JSObject* base, RegisterID result, PropertyOffset cachedOffset)
{
- loadPtr(base->addressOfPropertyStorage(), result);
- loadPtr(Address(result, cachedOffset * sizeof(WriteBarrier<Unknown>)), result);
+ if (isInlineOffset(cachedOffset)) {
+ loadPtr(base->locationForOffset(cachedOffset), result);
+ return;
+ }
+
+ loadPtr(base->addressOfOutOfLineStorage(), result);
+ loadPtr(Address(result, offsetInOutOfLineStorage(cachedOffset) * sizeof(WriteBarrier<Unknown>)), result);
}
-void JIT::privateCompilePutByIdTransition(StructureStubInfo* stubInfo, Structure* oldStructure, Structure* newStructure, size_t cachedOffset, StructureChain* chain, ReturnAddressPtr returnAddress, bool direct)
+void JIT::privateCompilePutByIdTransition(StructureStubInfo* stubInfo, Structure* oldStructure, Structure* newStructure, PropertyOffset cachedOffset, StructureChain* chain, ReturnAddressPtr returnAddress, bool direct)
{
JumpList failureCases;
// Check eax is an object of the right Structure.
@@ -522,7 +552,7 @@
#endif
// emit a call only if storage realloc is needed
- bool willNeedStorageRealloc = oldStructure->propertyStorageCapacity() != newStructure->propertyStorageCapacity();
+ bool willNeedStorageRealloc = oldStructure->outOfLineCapacity() != newStructure->outOfLineCapacity();
if (willNeedStorageRealloc) {
// This trampoline was called to like a JIT stub; before we can can call again we need to
// remove the return address from the stack, to prevent the stack from becoming misaligned.
@@ -532,7 +562,7 @@
stubCall.skipArgument(); // base
stubCall.skipArgument(); // ident
stubCall.skipArgument(); // value
- stubCall.addArgument(TrustedImm32(oldStructure->propertyStorageCapacity()));
+ stubCall.addArgument(TrustedImm32(oldStructure->outOfLineCapacity()));
stubCall.addArgument(TrustedImmPtr(newStructure));
stubCall.call(regT0);
emitGetJITStubArg(2, regT1);
@@ -572,7 +602,7 @@
repatchBuffer.relinkCallerToTrampoline(returnAddress, CodeLocationLabel(stubInfo->stubRoutine.code()));
}
-void JIT::patchGetByIdSelf(CodeBlock* codeBlock, StructureStubInfo* stubInfo, Structure* structure, size_t cachedOffset, ReturnAddressPtr returnAddress)
+void JIT::patchGetByIdSelf(CodeBlock* codeBlock, StructureStubInfo* stubInfo, Structure* structure, PropertyOffset cachedOffset, ReturnAddressPtr returnAddress)
{
RepatchBuffer repatchBuffer(codeBlock);
@@ -580,14 +610,13 @@
// Should probably go to cti_op_get_by_id_fail, but that doesn't do anything interesting right now.
repatchBuffer.relinkCallerToFunction(returnAddress, FunctionPtr(cti_op_get_by_id_self_fail));
- int offset = sizeof(JSValue) * cachedOffset;
-
// Patch the offset into the propoerty map to load from, then patch the Structure to look for.
repatchBuffer.repatch(stubInfo->hotPathBegin.dataLabelPtrAtOffset(stubInfo->patch.baseline.u.get.structureToCompare), structure);
- repatchBuffer.repatch(stubInfo->hotPathBegin.dataLabelCompactAtOffset(stubInfo->patch.baseline.u.get.displacementLabel), offset);
+ repatchBuffer.setLoadInstructionIsActive(stubInfo->hotPathBegin.convertibleLoadAtOffset(stubInfo->patch.baseline.u.get.propertyStorageLoad), isOutOfLineOffset(cachedOffset));
+ repatchBuffer.repatch(stubInfo->hotPathBegin.dataLabelCompactAtOffset(stubInfo->patch.baseline.u.get.displacementLabel), offsetRelativeToPatchedStorage(cachedOffset));
}
-void JIT::patchPutByIdReplace(CodeBlock* codeBlock, StructureStubInfo* stubInfo, Structure* structure, size_t cachedOffset, ReturnAddressPtr returnAddress, bool direct)
+void JIT::patchPutByIdReplace(CodeBlock* codeBlock, StructureStubInfo* stubInfo, Structure* structure, PropertyOffset cachedOffset, ReturnAddressPtr returnAddress, bool direct)
{
RepatchBuffer repatchBuffer(codeBlock);
@@ -595,11 +624,10 @@
// Should probably go to cti_op_put_by_id_fail, but that doesn't do anything interesting right now.
repatchBuffer.relinkCallerToFunction(returnAddress, FunctionPtr(direct ? cti_op_put_by_id_direct_generic : cti_op_put_by_id_generic));
- int offset = sizeof(JSValue) * cachedOffset;
-
// Patch the offset into the propoerty map to load from, then patch the Structure to look for.
repatchBuffer.repatch(stubInfo->hotPathBegin.dataLabelPtrAtOffset(stubInfo->patch.baseline.u.put.structureToCompare), structure);
- repatchBuffer.repatch(stubInfo->hotPathBegin.dataLabel32AtOffset(stubInfo->patch.baseline.u.put.displacementLabel), offset);
+ repatchBuffer.setLoadInstructionIsActive(stubInfo->hotPathBegin.convertibleLoadAtOffset(stubInfo->patch.baseline.u.put.propertyStorageLoad), isOutOfLineOffset(cachedOffset));
+ repatchBuffer.repatch(stubInfo->hotPathBegin.dataLabel32AtOffset(stubInfo->patch.baseline.u.put.displacementLabel), offsetRelativeToPatchedStorage(cachedOffset));
}
void JIT::privateCompilePatchGetArrayLength(ReturnAddressPtr returnAddress)
@@ -643,7 +671,7 @@
repatchBuffer.relinkCallerToFunction(returnAddress, FunctionPtr(cti_op_get_by_id_array_fail));
}
-void JIT::privateCompileGetByIdProto(StructureStubInfo* stubInfo, Structure* structure, Structure* prototypeStructure, const Identifier& ident, const PropertySlot& slot, size_t cachedOffset, ReturnAddressPtr returnAddress, CallFrame* callFrame)
+void JIT::privateCompileGetByIdProto(StructureStubInfo* stubInfo, Structure* structure, Structure* prototypeStructure, const Identifier& ident, const PropertySlot& slot, PropertyOffset cachedOffset, ReturnAddressPtr returnAddress, CallFrame* callFrame)
{
// The prototype object definitely exists (if this stub exists the CodeBlock is referencing a Structure that is
// referencing the prototype object - let's speculatively load it's table nice and early!)
@@ -710,7 +738,7 @@
repatchBuffer.relinkCallerToFunction(returnAddress, FunctionPtr(cti_op_get_by_id_proto_list));
}
-void JIT::privateCompileGetByIdSelfList(StructureStubInfo* stubInfo, PolymorphicAccessStructureList* polymorphicStructures, int currentIndex, Structure* structure, const Identifier& ident, const PropertySlot& slot, size_t cachedOffset)
+void JIT::privateCompileGetByIdSelfList(StructureStubInfo* stubInfo, PolymorphicAccessStructureList* polymorphicStructures, int currentIndex, Structure* structure, const Identifier& ident, const PropertySlot& slot, PropertyOffset cachedOffset)
{
Jump failureCase = checkStructure(regT0, structure);
bool needsStubLink = false;
@@ -770,7 +798,7 @@
repatchBuffer.relink(jumpLocation, CodeLocationLabel(stubCode.code()));
}
-void JIT::privateCompileGetByIdProtoList(StructureStubInfo* stubInfo, PolymorphicAccessStructureList* prototypeStructures, int currentIndex, Structure* structure, Structure* prototypeStructure, const Identifier& ident, const PropertySlot& slot, size_t cachedOffset, CallFrame* callFrame)
+void JIT::privateCompileGetByIdProtoList(StructureStubInfo* stubInfo, PolymorphicAccessStructureList* prototypeStructures, int currentIndex, Structure* structure, Structure* prototypeStructure, const Identifier& ident, const PropertySlot& slot, PropertyOffset cachedOffset, CallFrame* callFrame)
{
// The prototype object definitely exists (if this stub exists the CodeBlock is referencing a Structure that is
// referencing the prototype object - let's speculatively load it's table nice and early!)
@@ -839,7 +867,7 @@
repatchBuffer.relink(jumpLocation, CodeLocationLabel(stubCode.code()));
}
-void JIT::privateCompileGetByIdChainList(StructureStubInfo* stubInfo, PolymorphicAccessStructureList* prototypeStructures, int currentIndex, Structure* structure, StructureChain* chain, size_t count, const Identifier& ident, const PropertySlot& slot, size_t cachedOffset, CallFrame* callFrame)
+void JIT::privateCompileGetByIdChainList(StructureStubInfo* stubInfo, PolymorphicAccessStructureList* prototypeStructures, int currentIndex, Structure* structure, StructureChain* chain, size_t count, const Identifier& ident, const PropertySlot& slot, PropertyOffset cachedOffset, CallFrame* callFrame)
{
ASSERT(count);
JumpList bucketsOfFail;
@@ -914,7 +942,7 @@
repatchBuffer.relink(jumpLocation, CodeLocationLabel(stubRoutine.code()));
}
-void JIT::privateCompileGetByIdChain(StructureStubInfo* stubInfo, Structure* structure, StructureChain* chain, size_t count, const Identifier& ident, const PropertySlot& slot, size_t cachedOffset, ReturnAddressPtr returnAddress, CallFrame* callFrame)
+void JIT::privateCompileGetByIdChain(StructureStubInfo* stubInfo, Structure* structure, StructureChain* chain, size_t count, const Identifier& ident, const PropertySlot& slot, PropertyOffset cachedOffset, ReturnAddressPtr returnAddress, CallFrame* callFrame)
{
ASSERT(count);
diff --git a/Source/JavaScriptCore/jit/JITPropertyAccess32_64.cpp b/Source/JavaScriptCore/jit/JITPropertyAccess32_64.cpp
index a44c576..799e958 100644
--- a/Source/JavaScriptCore/jit/JITPropertyAccess32_64.cpp
+++ b/Source/JavaScriptCore/jit/JITPropertyAccess32_64.cpp
@@ -93,7 +93,8 @@
void JIT::emit_op_method_check(Instruction* currentInstruction)
{
// Assert that the following instruction is a get_by_id.
- ASSERT(m_interpreter->getOpcodeID((currentInstruction + OPCODE_LENGTH(op_method_check))->u.opcode) == op_get_by_id);
+ ASSERT(m_interpreter->getOpcodeID((currentInstruction + OPCODE_LENGTH(op_method_check))->u.opcode) == op_get_by_id
+ || m_interpreter->getOpcodeID((currentInstruction + OPCODE_LENGTH(op_method_check))->u.opcode) == op_get_by_id_out_of_line);
currentInstruction += OPCODE_LENGTH(op_method_check);
@@ -333,7 +334,7 @@
PatchableJump structureCheck = patchableBranchPtrWithPatch(NotEqual, Address(regT0, JSCell::structureOffset()), structureToCompare, TrustedImmPtr(reinterpret_cast<void*>(patchGetByIdDefaultStructure)));
addSlowCase(structureCheck);
- loadPtr(Address(regT0, JSObject::offsetOfPropertyStorage()), regT2);
+ ConvertibleLoadLabel propertyStorageLoad = convertibleLoadPtr(Address(regT0, JSObject::offsetOfOutOfLineStorage()), regT2);
DataLabelCompact displacementLabel1 = loadPtrWithCompactAddressOffsetPatch(Address(regT2, patchGetByIdDefaultOffset), regT0); // payload
DataLabelCompact displacementLabel2 = loadPtrWithCompactAddressOffsetPatch(Address(regT2, patchGetByIdDefaultOffset), regT1); // tag
@@ -341,7 +342,7 @@
END_UNINTERRUPTED_SEQUENCE(sequenceGetByIdHotPath);
- m_propertyAccessCompilationInfo.append(PropertyStubCompilationInfo(PropertyStubGetById, m_bytecodeOffset, hotPathBegin, structureToCompare, structureCheck, displacementLabel1, displacementLabel2, putResult));
+ m_propertyAccessCompilationInfo.append(PropertyStubCompilationInfo(PropertyStubGetById, m_bytecodeOffset, hotPathBegin, structureToCompare, structureCheck, propertyStorageLoad, displacementLabel1, displacementLabel2, putResult));
}
void JIT::emitSlow_op_get_by_id(Instruction* currentInstruction, Vector<SlowCaseEntry>::iterator& iter)
@@ -399,7 +400,7 @@
DataLabelPtr structureToCompare;
addSlowCase(branchPtrWithPatch(NotEqual, Address(regT0, JSCell::structureOffset()), structureToCompare, TrustedImmPtr(reinterpret_cast<void*>(patchGetByIdDefaultStructure))));
- loadPtr(Address(regT0, JSObject::offsetOfPropertyStorage()), regT1);
+ ConvertibleLoadLabel propertyStorageLoad = convertibleLoadPtr(Address(regT0, JSObject::offsetOfOutOfLineStorage()), regT1);
DataLabel32 displacementLabel1 = storePtrWithAddressOffsetPatch(regT2, Address(regT1, patchPutByIdDefaultOffset)); // payload
DataLabel32 displacementLabel2 = storePtrWithAddressOffsetPatch(regT3, Address(regT1, patchPutByIdDefaultOffset)); // tag
@@ -407,7 +408,7 @@
emitWriteBarrier(regT0, regT2, regT1, regT2, ShouldFilterImmediates, WriteBarrierForPropertyAccess);
- m_propertyAccessCompilationInfo.append(PropertyStubCompilationInfo(PropertyStubPutById, m_bytecodeOffset, hotPathBegin, structureToCompare, displacementLabel1, displacementLabel2));
+ m_propertyAccessCompilationInfo.append(PropertyStubCompilationInfo(PropertyStubPutById, m_bytecodeOffset, hotPathBegin, structureToCompare, propertyStorageLoad, displacementLabel1, displacementLabel2));
}
void JIT::emitSlow_op_put_by_id(Instruction* currentInstruction, Vector<SlowCaseEntry>::iterator& iter)
@@ -430,30 +431,41 @@
}
// Compile a store into an object's property storage. May overwrite base.
-void JIT::compilePutDirectOffset(RegisterID base, RegisterID valueTag, RegisterID valuePayload, size_t cachedOffset)
+void JIT::compilePutDirectOffset(RegisterID base, RegisterID valueTag, RegisterID valuePayload, PropertyOffset cachedOffset)
{
- int offset = cachedOffset;
- loadPtr(Address(base, JSObject::offsetOfPropertyStorage()), base);
- emitStore(offset, valueTag, valuePayload, base);
+ if (isOutOfLineOffset(cachedOffset))
+ loadPtr(Address(base, JSObject::offsetOfOutOfLineStorage()), base);
+ emitStore(indexRelativeToBase(cachedOffset), valueTag, valuePayload, base);
}
// Compile a load from an object's property storage. May overwrite base.
-void JIT::compileGetDirectOffset(RegisterID base, RegisterID resultTag, RegisterID resultPayload, size_t cachedOffset)
+void JIT::compileGetDirectOffset(RegisterID base, RegisterID resultTag, RegisterID resultPayload, PropertyOffset cachedOffset)
{
- int offset = cachedOffset;
+ if (isInlineOffset(cachedOffset)) {
+ emitLoad(indexRelativeToBase(cachedOffset), resultTag, resultPayload, base);
+ return;
+ }
+
RegisterID temp = resultPayload;
- loadPtr(Address(base, JSObject::offsetOfPropertyStorage()), temp);
- emitLoad(offset, resultTag, resultPayload, temp);
+ loadPtr(Address(base, JSObject::offsetOfOutOfLineStorage()), temp);
+ emitLoad(indexRelativeToBase(cachedOffset), resultTag, resultPayload, temp);
}
-void JIT::compileGetDirectOffset(JSObject* base, RegisterID resultTag, RegisterID resultPayload, size_t cachedOffset)
+void JIT::compileGetDirectOffset(JSObject* base, RegisterID resultTag, RegisterID resultPayload, PropertyOffset cachedOffset)
{
- loadPtr(base->addressOfPropertyStorage(), resultTag);
- load32(Address(resultTag, cachedOffset * sizeof(WriteBarrier<Unknown>) + OBJECT_OFFSETOF(JSValue, u.asBits.payload)), resultPayload);
- load32(Address(resultTag, cachedOffset * sizeof(WriteBarrier<Unknown>) + OBJECT_OFFSETOF(JSValue, u.asBits.tag)), resultTag);
+ if (isInlineOffset(cachedOffset)) {
+ move(TrustedImmPtr(base->locationForOffset(cachedOffset)), resultTag);
+ load32(Address(resultTag, OBJECT_OFFSETOF(JSValue, u.asBits.payload)), resultPayload);
+ load32(Address(resultTag, OBJECT_OFFSETOF(JSValue, u.asBits.tag)), resultTag);
+ return;
+ }
+
+ loadPtr(base->addressOfOutOfLineStorage(), resultTag);
+ load32(Address(resultTag, offsetInOutOfLineStorage(cachedOffset) * sizeof(WriteBarrier<Unknown>) + OBJECT_OFFSETOF(JSValue, u.asBits.payload)), resultPayload);
+ load32(Address(resultTag, offsetInOutOfLineStorage(cachedOffset) * sizeof(WriteBarrier<Unknown>) + OBJECT_OFFSETOF(JSValue, u.asBits.tag)), resultTag);
}
-void JIT::privateCompilePutByIdTransition(StructureStubInfo* stubInfo, Structure* oldStructure, Structure* newStructure, size_t cachedOffset, StructureChain* chain, ReturnAddressPtr returnAddress, bool direct)
+void JIT::privateCompilePutByIdTransition(StructureStubInfo* stubInfo, Structure* oldStructure, Structure* newStructure, PropertyOffset cachedOffset, StructureChain* chain, ReturnAddressPtr returnAddress, bool direct)
{
// The code below assumes that regT0 contains the basePayload and regT1 contains the baseTag. Restore them from the stack.
#if CPU(MIPS) || CPU(SH4) || CPU(ARM)
@@ -489,7 +501,7 @@
// Reallocate property storage if needed.
Call callTarget;
- bool willNeedStorageRealloc = oldStructure->propertyStorageCapacity() != newStructure->propertyStorageCapacity();
+ bool willNeedStorageRealloc = oldStructure->outOfLineCapacity() != newStructure->outOfLineCapacity();
if (willNeedStorageRealloc) {
// This trampoline was called to like a JIT stub; before we can can call again we need to
// remove the return address from the stack, to prevent the stack from becoming misaligned.
@@ -499,7 +511,7 @@
stubCall.skipArgument(); // base
stubCall.skipArgument(); // ident
stubCall.skipArgument(); // value
- stubCall.addArgument(TrustedImm32(oldStructure->propertyStorageCapacity()));
+ stubCall.addArgument(TrustedImm32(oldStructure->outOfLineCapacity()));
stubCall.addArgument(TrustedImmPtr(newStructure));
stubCall.call(regT0);
@@ -553,7 +565,7 @@
repatchBuffer.relinkCallerToTrampoline(returnAddress, CodeLocationLabel(stubInfo->stubRoutine.code()));
}
-void JIT::patchGetByIdSelf(CodeBlock* codeBlock, StructureStubInfo* stubInfo, Structure* structure, size_t cachedOffset, ReturnAddressPtr returnAddress)
+void JIT::patchGetByIdSelf(CodeBlock* codeBlock, StructureStubInfo* stubInfo, Structure* structure, PropertyOffset cachedOffset, ReturnAddressPtr returnAddress)
{
RepatchBuffer repatchBuffer(codeBlock);
@@ -561,15 +573,14 @@
// Should probably go to JITStubs::cti_op_get_by_id_fail, but that doesn't do anything interesting right now.
repatchBuffer.relinkCallerToFunction(returnAddress, FunctionPtr(cti_op_get_by_id_self_fail));
- int offset = sizeof(JSValue) * cachedOffset;
-
// Patch the offset into the propoerty map to load from, then patch the Structure to look for.
repatchBuffer.repatch(stubInfo->hotPathBegin.dataLabelPtrAtOffset(stubInfo->patch.baseline.u.get.structureToCompare), structure);
- repatchBuffer.repatch(stubInfo->hotPathBegin.dataLabelCompactAtOffset(stubInfo->patch.baseline.u.get.displacementLabel1), offset + OBJECT_OFFSETOF(JSValue, u.asBits.payload)); // payload
- repatchBuffer.repatch(stubInfo->hotPathBegin.dataLabelCompactAtOffset(stubInfo->patch.baseline.u.get.displacementLabel2), offset + OBJECT_OFFSETOF(JSValue, u.asBits.tag)); // tag
+ repatchBuffer.setLoadInstructionIsActive(stubInfo->hotPathBegin.convertibleLoadAtOffset(stubInfo->patch.baseline.u.get.propertyStorageLoad), isOutOfLineOffset(cachedOffset));
+ repatchBuffer.repatch(stubInfo->hotPathBegin.dataLabelCompactAtOffset(stubInfo->patch.baseline.u.get.displacementLabel1), offsetRelativeToPatchedStorage(cachedOffset) + OBJECT_OFFSETOF(JSValue, u.asBits.payload)); // payload
+ repatchBuffer.repatch(stubInfo->hotPathBegin.dataLabelCompactAtOffset(stubInfo->patch.baseline.u.get.displacementLabel2), offsetRelativeToPatchedStorage(cachedOffset) + OBJECT_OFFSETOF(JSValue, u.asBits.tag)); // tag
}
-void JIT::patchPutByIdReplace(CodeBlock* codeBlock, StructureStubInfo* stubInfo, Structure* structure, size_t cachedOffset, ReturnAddressPtr returnAddress, bool direct)
+void JIT::patchPutByIdReplace(CodeBlock* codeBlock, StructureStubInfo* stubInfo, Structure* structure, PropertyOffset cachedOffset, ReturnAddressPtr returnAddress, bool direct)
{
RepatchBuffer repatchBuffer(codeBlock);
@@ -577,12 +588,11 @@
// Should probably go to cti_op_put_by_id_fail, but that doesn't do anything interesting right now.
repatchBuffer.relinkCallerToFunction(returnAddress, FunctionPtr(direct ? cti_op_put_by_id_direct_generic : cti_op_put_by_id_generic));
- int offset = sizeof(JSValue) * cachedOffset;
-
// Patch the offset into the propoerty map to load from, then patch the Structure to look for.
repatchBuffer.repatch(stubInfo->hotPathBegin.dataLabelPtrAtOffset(stubInfo->patch.baseline.u.put.structureToCompare), structure);
- repatchBuffer.repatch(stubInfo->hotPathBegin.dataLabel32AtOffset(stubInfo->patch.baseline.u.put.displacementLabel1), offset + OBJECT_OFFSETOF(JSValue, u.asBits.payload)); // payload
- repatchBuffer.repatch(stubInfo->hotPathBegin.dataLabel32AtOffset(stubInfo->patch.baseline.u.put.displacementLabel2), offset + OBJECT_OFFSETOF(JSValue, u.asBits.tag)); // tag
+ repatchBuffer.setLoadInstructionIsActive(stubInfo->hotPathBegin.convertibleLoadAtOffset(stubInfo->patch.baseline.u.put.propertyStorageLoad), isOutOfLineOffset(cachedOffset));
+ repatchBuffer.repatch(stubInfo->hotPathBegin.dataLabel32AtOffset(stubInfo->patch.baseline.u.put.displacementLabel1), offsetRelativeToPatchedStorage(cachedOffset) + OBJECT_OFFSETOF(JSValue, u.asBits.payload)); // payload
+ repatchBuffer.repatch(stubInfo->hotPathBegin.dataLabel32AtOffset(stubInfo->patch.baseline.u.put.displacementLabel2), offsetRelativeToPatchedStorage(cachedOffset) + OBJECT_OFFSETOF(JSValue, u.asBits.tag)); // tag
}
void JIT::privateCompilePatchGetArrayLength(ReturnAddressPtr returnAddress)
@@ -629,7 +639,7 @@
repatchBuffer.relinkCallerToFunction(returnAddress, FunctionPtr(cti_op_get_by_id_array_fail));
}
-void JIT::privateCompileGetByIdProto(StructureStubInfo* stubInfo, Structure* structure, Structure* prototypeStructure, const Identifier& ident, const PropertySlot& slot, size_t cachedOffset, ReturnAddressPtr returnAddress, CallFrame* callFrame)
+void JIT::privateCompileGetByIdProto(StructureStubInfo* stubInfo, Structure* structure, Structure* prototypeStructure, const Identifier& ident, const PropertySlot& slot, PropertyOffset cachedOffset, ReturnAddressPtr returnAddress, CallFrame* callFrame)
{
// regT0 holds a JSCell*
@@ -700,7 +710,7 @@
}
-void JIT::privateCompileGetByIdSelfList(StructureStubInfo* stubInfo, PolymorphicAccessStructureList* polymorphicStructures, int currentIndex, Structure* structure, const Identifier& ident, const PropertySlot& slot, size_t cachedOffset)
+void JIT::privateCompileGetByIdSelfList(StructureStubInfo* stubInfo, PolymorphicAccessStructureList* polymorphicStructures, int currentIndex, Structure* structure, const Identifier& ident, const PropertySlot& slot, PropertyOffset cachedOffset)
{
// regT0 holds a JSCell*
Jump failureCase = checkStructure(regT0, structure);
@@ -760,7 +770,7 @@
repatchBuffer.relink(jumpLocation, CodeLocationLabel(stubRoutine.code()));
}
-void JIT::privateCompileGetByIdProtoList(StructureStubInfo* stubInfo, PolymorphicAccessStructureList* prototypeStructures, int currentIndex, Structure* structure, Structure* prototypeStructure, const Identifier& ident, const PropertySlot& slot, size_t cachedOffset, CallFrame* callFrame)
+void JIT::privateCompileGetByIdProtoList(StructureStubInfo* stubInfo, PolymorphicAccessStructureList* prototypeStructures, int currentIndex, Structure* structure, Structure* prototypeStructure, const Identifier& ident, const PropertySlot& slot, PropertyOffset cachedOffset, CallFrame* callFrame)
{
// regT0 holds a JSCell*
@@ -829,7 +839,7 @@
repatchBuffer.relink(jumpLocation, CodeLocationLabel(stubRoutine.code()));
}
-void JIT::privateCompileGetByIdChainList(StructureStubInfo* stubInfo, PolymorphicAccessStructureList* prototypeStructures, int currentIndex, Structure* structure, StructureChain* chain, size_t count, const Identifier& ident, const PropertySlot& slot, size_t cachedOffset, CallFrame* callFrame)
+void JIT::privateCompileGetByIdChainList(StructureStubInfo* stubInfo, PolymorphicAccessStructureList* prototypeStructures, int currentIndex, Structure* structure, StructureChain* chain, size_t count, const Identifier& ident, const PropertySlot& slot, PropertyOffset cachedOffset, CallFrame* callFrame)
{
// regT0 holds a JSCell*
ASSERT(count);
@@ -904,7 +914,7 @@
repatchBuffer.relink(jumpLocation, CodeLocationLabel(stubRoutine.code()));
}
-void JIT::privateCompileGetByIdChain(StructureStubInfo* stubInfo, Structure* structure, StructureChain* chain, size_t count, const Identifier& ident, const PropertySlot& slot, size_t cachedOffset, ReturnAddressPtr returnAddress, CallFrame* callFrame)
+void JIT::privateCompileGetByIdChain(StructureStubInfo* stubInfo, Structure* structure, StructureChain* chain, size_t count, const Identifier& ident, const PropertySlot& slot, PropertyOffset cachedOffset, ReturnAddressPtr returnAddress, CallFrame* callFrame)
{
// regT0 holds a JSCell*
ASSERT(count);
@@ -975,13 +985,27 @@
repatchBuffer.relinkCallerToFunction(returnAddress, FunctionPtr(cti_op_get_by_id_proto_list));
}
-void JIT::compileGetDirectOffset(RegisterID base, RegisterID resultTag, RegisterID resultPayload, RegisterID offset)
+void JIT::compileGetDirectOffset(RegisterID base, RegisterID resultTag, RegisterID resultPayload, RegisterID offset, FinalObjectMode finalObjectMode)
{
ASSERT(sizeof(JSValue) == 8);
- loadPtr(Address(base, JSObject::offsetOfPropertyStorage()), base);
- loadPtr(BaseIndex(base, offset, TimesEight, OBJECT_OFFSETOF(JSValue, u.asBits.payload)), resultPayload);
- loadPtr(BaseIndex(base, offset, TimesEight, OBJECT_OFFSETOF(JSValue, u.asBits.tag)), resultTag);
+ if (finalObjectMode == MayBeFinal) {
+ Jump isInline = branch32(LessThan, offset, TrustedImm32(inlineStorageCapacity));
+ loadPtr(Address(base, JSObject::offsetOfOutOfLineStorage()), base);
+ Jump done = jump();
+ isInline.link(this);
+ addPtr(TrustedImmPtr(JSObject::offsetOfInlineStorage() + inlineStorageCapacity * sizeof(EncodedJSValue)), base);
+ done.link(this);
+ } else {
+#if !ASSERT_DISABLED
+ Jump isOutOfLine = branch32(GreaterThanOrEqual, offset, TrustedImm32(inlineStorageCapacity));
+ breakpoint();
+ isOutOfLine.link(this);
+#endif
+ loadPtr(Address(base, JSObject::offsetOfOutOfLineStorage()), base);
+ }
+ load32(BaseIndex(base, offset, TimesEight, OBJECT_OFFSETOF(JSValue, u.asBits.payload) - inlineStorageCapacity * sizeof(EncodedJSValue)), resultPayload);
+ load32(BaseIndex(base, offset, TimesEight, OBJECT_OFFSETOF(JSValue, u.asBits.tag) - inlineStorageCapacity * sizeof(EncodedJSValue)), resultTag);
}
void JIT::emit_op_get_by_pname(Instruction* currentInstruction)
@@ -1006,6 +1030,7 @@
load32(addressFor(i), regT3);
sub32(TrustedImm32(1), regT3);
addSlowCase(branch32(AboveOrEqual, regT3, Address(regT1, OBJECT_OFFSETOF(JSPropertyNameIterator, m_numCacheableSlots))));
+ add32(Address(regT1, OBJECT_OFFSETOF(JSPropertyNameIterator, m_offsetBase)), regT3);
compileGetDirectOffset(regT2, regT1, regT0, regT3);
emitStore(dst, regT1, regT0);
diff --git a/Source/JavaScriptCore/jit/JITStubs.cpp b/Source/JavaScriptCore/jit/JITStubs.cpp
index 59dc5f1..72aa0dc 100644
--- a/Source/JavaScriptCore/jit/JITStubs.cpp
+++ b/Source/JavaScriptCore/jit/JITStubs.cpp
@@ -962,7 +962,7 @@
return;
}
- size_t offset = slot.cachedOffset();
+ PropertyOffset offset = slot.cachedOffset();
size_t count = normalizePrototypeChain(callFrame, baseValue, slot.slotBase(), propertyName, offset);
if (!count) {
stubInfo->accessType = access_get_by_id_generic;
@@ -1494,13 +1494,16 @@
JSValue baseValue = stackFrame.args[0].jsValue();
int32_t oldSize = stackFrame.args[3].int32();
Structure* newStructure = stackFrame.args[4].structure();
- int32_t newSize = newStructure->propertyStorageCapacity();
+ int32_t newSize = newStructure->outOfLineCapacity();
+
+ ASSERT(oldSize >= 0);
+ ASSERT(newSize > oldSize);
ASSERT(baseValue.isObject());
JSObject* base = asObject(baseValue);
JSGlobalData& globalData = *stackFrame.globalData;
- PropertyStorage newStorage = base->growPropertyStorage(globalData, oldSize, newSize);
- base->setPropertyStorage(globalData, newStorage, newStructure);
+ PropertyStorage newStorage = base->growOutOfLineStorage(globalData, oldSize, newSize);
+ base->setOutOfLineStorage(globalData, newStorage, newStructure);
return base;
}
@@ -1822,7 +1825,7 @@
ASSERT(slot.slotBase().isObject());
JSObject* slotBaseObject = asObject(slot.slotBase());
- size_t offset = slot.cachedOffset();
+ PropertyOffset offset = slot.cachedOffset();
if (slot.slotBase() == baseValue)
ctiPatchCallByReturnAddress(codeBlock, STUB_RETURN_ADDRESS, FunctionPtr(cti_op_get_by_id_proto_fail));
diff --git a/Source/JavaScriptCore/llint/LLIntSlowPaths.cpp b/Source/JavaScriptCore/llint/LLIntSlowPaths.cpp
index a7698be3..fbc0146 100644
--- a/Source/JavaScriptCore/llint/LLIntSlowPaths.cpp
+++ b/Source/JavaScriptCore/llint/LLIntSlowPaths.cpp
@@ -895,7 +895,13 @@
&& !structure->typeInfo().prohibitsPropertyCaching()) {
pc[4].u.structure.set(
globalData, codeBlock->ownerExecutable(), structure);
- pc[5].u.operand = slot.cachedOffset() * sizeof(JSValue);
+ if (isInlineOffset(slot.cachedOffset())) {
+ pc[0].u.opcode = bitwise_cast<void*>(&llint_op_get_by_id);
+ pc[5].u.operand = offsetInInlineStorage(slot.cachedOffset()) * sizeof(JSValue) + JSObject::offsetOfInlineStorage();
+ } else {
+ pc[0].u.opcode = bitwise_cast<void*>(&llint_op_get_by_id_out_of_line);
+ pc[5].u.operand = offsetInOutOfLineStorage(slot.cachedOffset()) * sizeof(JSValue);
+ }
}
}
@@ -940,7 +946,7 @@
&& baseCell == slot.base()) {
if (slot.type() == PutPropertySlot::NewProperty) {
- if (!structure->isDictionary() && structure->previousID()->propertyStorageCapacity() == structure->propertyStorageCapacity()) {
+ if (!structure->isDictionary() && structure->previousID()->outOfLineCapacity() == structure->outOfLineCapacity()) {
ASSERT(structure->previousID()->transitionWatchpointSetHasBeenInvalidated());
// This is needed because some of the methods we call
@@ -952,7 +958,10 @@
ASSERT(structure->previousID()->isObject());
pc[4].u.structure.set(
globalData, codeBlock->ownerExecutable(), structure->previousID());
- pc[5].u.operand = slot.cachedOffset() * sizeof(JSValue);
+ if (isInlineOffset(slot.cachedOffset()))
+ pc[5].u.operand = offsetInInlineStorage(slot.cachedOffset()) * sizeof(JSValue) + JSObject::offsetOfInlineStorage();
+ else
+ pc[5].u.operand = offsetInOutOfLineStorage(slot.cachedOffset()) * sizeof(JSValue);
pc[6].u.structure.set(
globalData, codeBlock->ownerExecutable(), structure);
StructureChain* chain = structure->prototypeChain(exec);
@@ -960,16 +969,28 @@
pc[7].u.structureChain.set(
globalData, codeBlock->ownerExecutable(), chain);
- if (pc[8].u.operand)
- pc[0].u.opcode = bitwise_cast<void*>(&llint_op_put_by_id_transition_direct);
- else
- pc[0].u.opcode = bitwise_cast<void*>(&llint_op_put_by_id_transition_normal);
+ if (pc[8].u.operand) {
+ if (isInlineOffset(slot.cachedOffset()))
+ pc[0].u.opcode = bitwise_cast<void*>(&llint_op_put_by_id_transition_direct);
+ else
+ pc[0].u.opcode = bitwise_cast<void*>(&llint_op_put_by_id_transition_direct_out_of_line);
+ } else {
+ if (isInlineOffset(slot.cachedOffset()))
+ pc[0].u.opcode = bitwise_cast<void*>(&llint_op_put_by_id_transition_normal);
+ else
+ pc[0].u.opcode = bitwise_cast<void*>(&llint_op_put_by_id_transition_normal_out_of_line);
+ }
}
} else {
- pc[0].u.opcode = bitwise_cast<void*>(&llint_op_put_by_id);
pc[4].u.structure.set(
globalData, codeBlock->ownerExecutable(), structure);
- pc[5].u.operand = slot.cachedOffset() * sizeof(JSValue);
+ if (isInlineOffset(slot.cachedOffset())) {
+ pc[0].u.opcode = bitwise_cast<void*>(&llint_op_put_by_id);
+ pc[5].u.operand = offsetInInlineStorage(slot.cachedOffset()) * sizeof(JSValue) + JSObject::offsetOfInlineStorage();
+ } else {
+ pc[0].u.opcode = bitwise_cast<void*>(&llint_op_put_by_id_out_of_line);
+ pc[5].u.operand = offsetInOutOfLineStorage(slot.cachedOffset()) * sizeof(JSValue);
+ }
}
}
}
diff --git a/Source/JavaScriptCore/llint/LowLevelInterpreter.asm b/Source/JavaScriptCore/llint/LowLevelInterpreter.asm
index e59ddeb..492535b 100644
--- a/Source/JavaScriptCore/llint/LowLevelInterpreter.asm
+++ b/Source/JavaScriptCore/llint/LowLevelInterpreter.asm
@@ -84,6 +84,13 @@
# String flags.
const HashFlags8BitBuffer = 64
+# Property storage constants
+if JSVALUE64
+ const InlineStorageCapacity = 4
+else
+ const InlineStorageCapacity = 6
+end
+
# Allocation constants
if JSVALUE64
const JSFinalObjectSizeClassIndex = 1
@@ -312,8 +319,7 @@
storep scratch2, [result]
storep structure, JSCell::m_structure[result]
storep 0, JSObject::m_inheritorID[result]
- addp sizeof JSObject, result, scratch1
- storep scratch1, JSObject::m_propertyStorage[result]
+ storep 0, JSObject::m_outOfLineStorage[result]
end
end
@@ -481,6 +487,21 @@
dispatch(5)
+macro withInlineStorage(object, propertyStorage, continuation)
+ # Indicate that the object is the property storage, and that the
+ # property storage register is unused.
+ continuation(object, propertyStorage)
+end
+
+macro withOutOfLineStorage(object, propertyStorage, continuation)
+ loadp JSObject::m_outOfLineStorage[object], propertyStorage
+ # Indicate that the propertyStorage register now points to the
+ # property storage, and that the object register may be reused
+ # if the object pointer is not needed anymore.
+ continuation(propertyStorage, object)
+end
+
+
_llint_op_del_by_id:
traceExecution()
callSlowPath(_llint_slow_path_del_by_id)
diff --git a/Source/JavaScriptCore/llint/LowLevelInterpreter32_64.asm b/Source/JavaScriptCore/llint/LowLevelInterpreter32_64.asm
index d27fd82..9d6304d 100644
--- a/Source/JavaScriptCore/llint/LowLevelInterpreter32_64.asm
+++ b/Source/JavaScriptCore/llint/LowLevelInterpreter32_64.asm
@@ -919,6 +919,24 @@
dispatch(3)
+macro loadPropertyAtVariableOffsetKnownNotFinal(propertyOffset, objectAndStorage, tag, payload)
+ assert(macro (ok) bigteq propertyOffset, InlineStorageCapacity, ok end)
+ loadp JSObject::m_outOfLineStorage[objectAndStorage], objectAndStorage
+ loadi TagOffset - 8 * InlineStorageCapacity[objectAndStorage, propertyOffset, 8], tag
+ loadi PayloadOffset - 8 * InlineStorageCapacity[objectAndStorage, propertyOffset, 8], payload
+end
+
+macro loadPropertyAtVariableOffset(propertyOffset, objectAndStorage, tag, payload)
+ bilt propertyOffset, InlineStorageCapacity, .isInline
+ loadp JSObject::m_outOfLineStorage[objectAndStorage], objectAndStorage
+ jmp .ready
+.isInline:
+ addp JSFinalObject::m_inlineStorage + InlineStorageCapacity * 8, objectAndStorage
+.ready:
+ loadi TagOffset - 8 * InlineStorageCapacity[objectAndStorage, propertyOffset, 8], tag
+ loadi PayloadOffset - 8 * InlineStorageCapacity[objectAndStorage, propertyOffset, 8], payload
+end
+
macro resolveGlobal(size, slow)
# Operands are as follows:
# 4[PC] Destination for the load.
@@ -930,9 +948,7 @@
loadp JSCell::m_structure[t0], t1
bpneq t1, 12[PC], slow
loadi 16[PC], t1
- loadp JSObject::m_propertyStorage[t0], t0
- loadi TagOffset[t0, t1, 8], t2
- loadi PayloadOffset[t0, t1, 8], t3
+ loadPropertyAtVariableOffsetKnownNotFinal(t1, t0, t2, t3)
loadi 4[PC], t0
storei t2, TagOffset[cfr, t0, 8]
storei t3, PayloadOffset[cfr, t0, 8]
@@ -1087,31 +1103,44 @@
dispatch(5)
-_llint_op_get_by_id:
+# We only do monomorphic get_by_id caching for now, and we do not modify the
+# opcode. We do, however, allow for the cache to change anytime if fails, since
+# ping-ponging is free. At best we get lucky and the get_by_id will continue
+# to take fast path on the new cache. At worst we take slow path, which is what
+# we would have been doing anyway.
+
+macro getById(getPropertyStorage)
traceExecution()
- # We only do monomorphic get_by_id caching for now, and we do not modify the
- # opcode. We do, however, allow for the cache to change anytime if fails, since
- # ping-ponging is free. At best we get lucky and the get_by_id will continue
- # to take fast path on the new cache. At worst we take slow path, which is what
- # we would have been doing anyway.
loadi 8[PC], t0
loadi 16[PC], t1
loadConstantOrVariablePayload(t0, CellTag, t3, .opGetByIdSlow)
loadi 20[PC], t2
- loadp JSObject::m_propertyStorage[t3], t0
- bpneq JSCell::m_structure[t3], t1, .opGetByIdSlow
- loadi 4[PC], t1
- loadi TagOffset[t0, t2], t3
- loadi PayloadOffset[t0, t2], t2
- storei t3, TagOffset[cfr, t1, 8]
- storei t2, PayloadOffset[cfr, t1, 8]
- loadi 32[PC], t1
- valueProfile(t3, t2, t1)
- dispatch(9)
+ getPropertyStorage(
+ t3,
+ t0,
+ macro (propertyStorage, scratch)
+ bpneq JSCell::m_structure[t3], t1, .opGetByIdSlow
+ loadi 4[PC], t1
+ loadi TagOffset[propertyStorage, t2], scratch
+ loadi PayloadOffset[propertyStorage, t2], t2
+ storei scratch, TagOffset[cfr, t1, 8]
+ storei t2, PayloadOffset[cfr, t1, 8]
+ loadi 32[PC], t1
+ valueProfile(scratch, t2, t1)
+ dispatch(9)
+ end)
-.opGetByIdSlow:
- callSlowPath(_llint_slow_path_get_by_id)
- dispatch(9)
+ .opGetByIdSlow:
+ callSlowPath(_llint_slow_path_get_by_id)
+ dispatch(9)
+end
+
+_llint_op_get_by_id:
+ getById(withInlineStorage)
+
+
+_llint_op_get_by_id_out_of_line:
+ getById(withOutOfLineStorage)
_llint_op_get_arguments_length:
@@ -1130,68 +1159,96 @@
dispatch(4)
-_llint_op_put_by_id:
+macro putById(getPropertyStorage)
traceExecution()
loadi 4[PC], t3
loadi 16[PC], t1
loadConstantOrVariablePayload(t3, CellTag, t0, .opPutByIdSlow)
loadi 12[PC], t2
- loadp JSObject::m_propertyStorage[t0], t3
- bpneq JSCell::m_structure[t0], t1, .opPutByIdSlow
- loadi 20[PC], t1
- loadConstantOrVariable2Reg(t2, t0, t2)
- writeBarrier(t0, t2)
- storei t0, TagOffset[t3, t1]
- storei t2, PayloadOffset[t3, t1]
- dispatch(9)
+ getPropertyStorage(
+ t0,
+ t3,
+ macro (propertyStorage, scratch)
+ bpneq JSCell::m_structure[t0], t1, .opPutByIdSlow
+ loadi 20[PC], t1
+ loadConstantOrVariable2Reg(t2, scratch, t2)
+ writeBarrier(scratch, t2)
+ storei scratch, TagOffset[propertyStorage, t1]
+ storei t2, PayloadOffset[propertyStorage, t1]
+ dispatch(9)
+ end)
+end
+
+_llint_op_put_by_id:
+ putById(withInlineStorage)
.opPutByIdSlow:
callSlowPath(_llint_slow_path_put_by_id)
dispatch(9)
-macro putByIdTransition(additionalChecks)
+_llint_op_put_by_id_out_of_line:
+ putById(withOutOfLineStorage)
+
+
+macro putByIdTransition(additionalChecks, getPropertyStorage)
traceExecution()
loadi 4[PC], t3
loadi 16[PC], t1
loadConstantOrVariablePayload(t3, CellTag, t0, .opPutByIdSlow)
loadi 12[PC], t2
bpneq JSCell::m_structure[t0], t1, .opPutByIdSlow
- additionalChecks(t1, t3, .opPutByIdSlow)
+ additionalChecks(t1, t3)
loadi 20[PC], t1
- loadp JSObject::m_propertyStorage[t0], t3
- addp t1, t3
- loadConstantOrVariable2Reg(t2, t1, t2)
- writeBarrier(t1, t2)
- storei t1, TagOffset[t3]
- loadi 24[PC], t1
- storei t2, PayloadOffset[t3]
- storep t1, JSCell::m_structure[t0]
- dispatch(9)
+ getPropertyStorage(
+ t0,
+ t3,
+ macro (propertyStorage, scratch)
+ addp t1, propertyStorage, t3
+ loadConstantOrVariable2Reg(t2, t1, t2)
+ writeBarrier(t1, t2)
+ storei t1, TagOffset[t3]
+ loadi 24[PC], t1
+ storei t2, PayloadOffset[t3]
+ storep t1, JSCell::m_structure[t0]
+ dispatch(9)
+ end)
+end
+
+macro noAdditionalChecks(oldStructure, scratch)
+end
+
+macro structureChainChecks(oldStructure, scratch)
+ const protoCell = oldStructure # Reusing the oldStructure register for the proto
+
+ loadp 28[PC], scratch
+ assert(macro (ok) btpnz scratch, ok end)
+ loadp StructureChain::m_vector[scratch], scratch
+ assert(macro (ok) btpnz scratch, ok end)
+ bieq Structure::m_prototype + TagOffset[oldStructure], NullTag, .done
+.loop:
+ loadi Structure::m_prototype + PayloadOffset[oldStructure], protoCell
+ loadp JSCell::m_structure[protoCell], oldStructure
+ bpneq oldStructure, [scratch], .opPutByIdSlow
+ addp 4, scratch
+ bineq Structure::m_prototype + TagOffset[oldStructure], NullTag, .loop
+.done:
end
_llint_op_put_by_id_transition_direct:
- putByIdTransition(macro (oldStructure, scratch, slow) end)
+ putByIdTransition(noAdditionalChecks, withInlineStorage)
+
+
+_llint_op_put_by_id_transition_direct_out_of_line:
+ putByIdTransition(noAdditionalChecks, withOutOfLineStorage)
_llint_op_put_by_id_transition_normal:
- putByIdTransition(
- macro (oldStructure, scratch, slow)
- const protoCell = oldStructure # Reusing the oldStructure register for the proto
-
- loadp 28[PC], scratch
- assert(macro (ok) btpnz scratch, ok end)
- loadp StructureChain::m_vector[scratch], scratch
- assert(macro (ok) btpnz scratch, ok end)
- bieq Structure::m_prototype + TagOffset[oldStructure], NullTag, .done
- .loop:
- loadi Structure::m_prototype + PayloadOffset[oldStructure], protoCell
- loadp JSCell::m_structure[protoCell], oldStructure
- bpneq oldStructure, [scratch], slow
- addp 4, scratch
- bineq Structure::m_prototype + TagOffset[oldStructure], NullTag, .loop
- .done:
- end)
+ putByIdTransition(structureChainChecks, withInlineStorage)
+
+
+_llint_op_put_by_id_transition_normal_out_of_line:
+ putByIdTransition(structureChainChecks, withOutOfLineStorage)
_llint_op_get_by_val:
@@ -1261,9 +1318,8 @@
loadi [cfr, t0, 8], t0
subi 1, t0
biaeq t0, JSPropertyNameIterator::m_numCacheableSlots[t3], .opGetByPnameSlow
- loadp JSObject::m_propertyStorage[t2], t2
- loadi TagOffset[t2, t0, 8], t1
- loadi PayloadOffset[t2, t0, 8], t3
+ addi JSPropertyNameIterator::m_offsetBase[t3], t0
+ loadPropertyAtVariableOffset(t0, t2, t1, t3)
loadi 4[PC], t0
storei t1, TagOffset[cfr, t0, 8]
storei t3, PayloadOffset[cfr, t0, 8]
diff --git a/Source/JavaScriptCore/llint/LowLevelInterpreter64.asm b/Source/JavaScriptCore/llint/LowLevelInterpreter64.asm
index a153586..a7a2ce8 100644
--- a/Source/JavaScriptCore/llint/LowLevelInterpreter64.asm
+++ b/Source/JavaScriptCore/llint/LowLevelInterpreter64.asm
@@ -778,6 +778,22 @@
dispatch(3)
+macro loadPropertyAtVariableOffsetKnownNotFinal(propertyOffset, objectAndStorage, value)
+ assert(macro (ok) bigteq propertyOffset, InlineStorageCapacity, ok end)
+ loadp JSObject::m_outOfLineStorage[objectAndStorage], objectAndStorage
+ loadp -8 * InlineStorageCapacity[objectAndStorage, propertyOffset, 8], value
+end
+
+macro loadPropertyAtVariableOffset(propertyOffset, objectAndStorage, value)
+ bilt propertyOffset, InlineStorageCapacity, .isInline
+ loadp JSObject::m_outOfLineStorage[objectAndStorage], objectAndStorage
+ jmp .ready
+.isInline:
+ addp JSFinalObject::m_inlineStorage + InlineStorageCapacity * 8, objectAndStorage
+.ready:
+ loadp -8 * InlineStorageCapacity[objectAndStorage, propertyOffset, 8], value
+end
+
macro resolveGlobal(size, slow)
# Operands are as follows:
# 8[PB, PC, 8] Destination for the load.
@@ -789,8 +805,7 @@
loadp JSCell::m_structure[t0], t1
bpneq t1, 24[PB, PC, 8], slow
loadis 32[PB, PC, 8], t1
- loadp JSObject::m_propertyStorage[t0], t0
- loadp [t0, t1, 8], t2
+ loadPropertyAtVariableOffset(t1, t0, t2)
loadis 8[PB, PC, 8], t0
storep t2, [cfr, t0, 8]
loadp (size - 1) * 8[PB, PC, 8], t0
@@ -937,7 +952,7 @@
dispatch(5)
-_llint_op_get_by_id:
+macro getById(getPropertyStorage)
traceExecution()
# We only do monomorphic get_by_id caching for now, and we do not modify the
# opcode. We do, however, allow for the cache to change anytime if fails, since
@@ -948,18 +963,30 @@
loadp 32[PB, PC, 8], t1
loadConstantOrVariableCell(t0, t3, .opGetByIdSlow)
loadis 40[PB, PC, 8], t2
- loadp JSObject::m_propertyStorage[t3], t0
- bpneq JSCell::m_structure[t3], t1, .opGetByIdSlow
- loadis 8[PB, PC, 8], t1
- loadp [t0, t2], t3
- storep t3, [cfr, t1, 8]
- loadp 64[PB, PC, 8], t1
- valueProfile(t3, t1)
- dispatch(9)
+ getPropertyStorage(
+ t3,
+ t0,
+ macro (propertyStorage, scratch)
+ bpneq JSCell::m_structure[t3], t1, .opGetByIdSlow
+ loadis 8[PB, PC, 8], t1
+ loadp [propertyStorage, t2], scratch
+ storep scratch, [cfr, t1, 8]
+ loadp 64[PB, PC, 8], t1
+ valueProfile(scratch, t1)
+ dispatch(9)
+ end)
+
+ .opGetByIdSlow:
+ callSlowPath(_llint_slow_path_get_by_id)
+ dispatch(9)
+end
-.opGetByIdSlow:
- callSlowPath(_llint_slow_path_get_by_id)
- dispatch(9)
+_llint_op_get_by_id:
+ getById(withInlineStorage)
+
+
+_llint_op_get_by_id_out_of_line:
+ getById(withOutOfLineStorage)
_llint_op_get_arguments_length:
@@ -978,65 +1005,93 @@
dispatch(4)
-_llint_op_put_by_id:
+macro putById(getPropertyStorage)
traceExecution()
loadis 8[PB, PC, 8], t3
loadp 32[PB, PC, 8], t1
loadConstantOrVariableCell(t3, t0, .opPutByIdSlow)
loadis 24[PB, PC, 8], t2
- loadp JSObject::m_propertyStorage[t0], t3
- bpneq JSCell::m_structure[t0], t1, .opPutByIdSlow
- loadis 40[PB, PC, 8], t1
- loadConstantOrVariable(t2, t0)
- writeBarrier(t0)
- storep t0, [t3, t1]
- dispatch(9)
+ getPropertyStorage(
+ t0,
+ t3,
+ macro (propertyStorage, scratch)
+ bpneq JSCell::m_structure[t0], t1, .opPutByIdSlow
+ loadis 40[PB, PC, 8], t1
+ loadConstantOrVariable(t2, scratch)
+ writeBarrier(t0)
+ storep scratch, [propertyStorage, t1]
+ dispatch(9)
+ end)
+end
+
+_llint_op_put_by_id:
+ putById(withInlineStorage)
.opPutByIdSlow:
callSlowPath(_llint_slow_path_put_by_id)
dispatch(9)
-macro putByIdTransition(additionalChecks)
+_llint_op_put_by_id_out_of_line:
+ putById(withOutOfLineStorage)
+
+
+macro putByIdTransition(additionalChecks, getPropertyStorage)
traceExecution()
loadis 8[PB, PC, 8], t3
loadp 32[PB, PC, 8], t1
loadConstantOrVariableCell(t3, t0, .opPutByIdSlow)
loadis 24[PB, PC, 8], t2
bpneq JSCell::m_structure[t0], t1, .opPutByIdSlow
- additionalChecks(t1, t3, .opPutByIdSlow)
+ additionalChecks(t1, t3)
loadis 40[PB, PC, 8], t1
- loadp JSObject::m_propertyStorage[t0], t3
- addp t1, t3
- loadConstantOrVariable(t2, t1)
- writeBarrier(t1)
- storep t1, [t3]
- loadp 48[PB, PC, 8], t1
- storep t1, JSCell::m_structure[t0]
- dispatch(9)
+ getPropertyStorage(
+ t0,
+ t3,
+ macro (propertyStorage, scratch)
+ addp t1, propertyStorage, t3
+ loadConstantOrVariable(t2, t1)
+ writeBarrier(t1)
+ storep t1, [t3]
+ loadp 48[PB, PC, 8], t1
+ storep t1, JSCell::m_structure[t0]
+ dispatch(9)
+ end)
+end
+
+macro noAdditionalChecks(oldStructure, scratch)
+end
+
+macro structureChainChecks(oldStructure, scratch)
+ const protoCell = oldStructure # Reusing the oldStructure register for the proto
+ loadp 56[PB, PC, 8], scratch
+ assert(macro (ok) btpnz scratch, ok end)
+ loadp StructureChain::m_vector[scratch], scratch
+ assert(macro (ok) btpnz scratch, ok end)
+ bpeq Structure::m_prototype[oldStructure], ValueNull, .done
+.loop:
+ loadp Structure::m_prototype[oldStructure], protoCell
+ loadp JSCell::m_structure[protoCell], oldStructure
+ bpneq oldStructure, [scratch], .opPutByIdSlow
+ addp 8, scratch
+ bpneq Structure::m_prototype[oldStructure], ValueNull, .loop
+.done:
end
_llint_op_put_by_id_transition_direct:
- putByIdTransition(macro (oldStructure, scratch, slow) end)
+ putByIdTransition(noAdditionalChecks, withInlineStorage)
+
+
+_llint_op_put_by_id_transition_direct_out_of_line:
+ putByIdTransition(noAdditionalChecks, withOutOfLineStorage)
_llint_op_put_by_id_transition_normal:
- putByIdTransition(
- macro (oldStructure, scratch, slow)
- const protoCell = oldStructure # Reusing the oldStructure register for the proto
- loadp 56[PB, PC, 8], scratch
- assert(macro (ok) btpnz scratch, ok end)
- loadp StructureChain::m_vector[scratch], scratch
- assert(macro (ok) btpnz scratch, ok end)
- bpeq Structure::m_prototype[oldStructure], ValueNull, .done
- .loop:
- loadp Structure::m_prototype[oldStructure], protoCell
- loadp JSCell::m_structure[protoCell], oldStructure
- bpneq oldStructure, [scratch], slow
- addp 8, scratch
- bpneq Structure::m_prototype[oldStructure], ValueNull, .loop
- .done:
- end)
+ putByIdTransition(structureChainChecks, withInlineStorage)
+
+
+_llint_op_put_by_id_transition_normal_out_of_line:
+ putByIdTransition(structureChainChecks, withOutOfLineStorage)
_llint_op_get_by_val:
@@ -1106,8 +1161,8 @@
loadi PayloadOffset[cfr, t3, 8], t3
subi 1, t3
biaeq t3, JSPropertyNameIterator::m_numCacheableSlots[t1], .opGetByPnameSlow
- loadp JSObject::m_propertyStorage[t0], t0
- loadp [t0, t3, 8], t0
+ addi JSPropertyNameIterator::m_offsetBase[t1], t3
+ loadPropertyAtVariableOffset(t3, t0, t0)
loadis 8[PB, PC, 8], t1
storep t0, [cfr, t1, 8]
dispatch(7)
diff --git a/Source/JavaScriptCore/offlineasm/x86.rb b/Source/JavaScriptCore/offlineasm/x86.rb
index e6a5c92..383526b 100644
--- a/Source/JavaScriptCore/offlineasm/x86.rb
+++ b/Source/JavaScriptCore/offlineasm/x86.rb
@@ -555,7 +555,11 @@
end
def handleX86Add(kind)
- if operands.size == 3 and operands[0].is_a? Immediate
+ if operands.size == 3 and operands[1] == operands[2]
+ unless Immediate.new(nil, 0) == operands[0]
+ $asm.puts "add#{x86Suffix(kind)} #{operands[0].x86Operand(kind)}, #{operands[2].x86Operand(kind)}"
+ end
+ elsif operands.size == 3 and operands[0].is_a? Immediate
raise unless operands[1].is_a? RegisterID
raise unless operands[2].is_a? RegisterID
if operands[0].value == 0
@@ -568,7 +572,11 @@
elsif operands.size == 3 and operands[0].is_a? RegisterID
raise unless operands[1].is_a? RegisterID
raise unless operands[2].is_a? RegisterID
- $asm.puts "lea#{x86Suffix(kind)} (#{operands[0].x86Operand(kind)}, #{operands[1].x86Operand(kind)}), #{operands[2].x86Operand(kind)}"
+ if operands[0] == operands[2]
+ $asm.puts "add#{x86Suffix(kind)} #{operands[1].x86Operand(kind)}, #{operands[2].x86Operand(kind)}"
+ else
+ $asm.puts "lea#{x86Suffix(kind)} (#{operands[0].x86Operand(kind)}, #{operands[1].x86Operand(kind)}), #{operands[2].x86Operand(kind)}"
+ end
else
unless Immediate.new(nil, 0) == operands[0]
$asm.puts "add#{x86Suffix(kind)} #{x86Operands(kind, kind)}"
diff --git a/Source/JavaScriptCore/runtime/JSGlobalObject.h b/Source/JavaScriptCore/runtime/JSGlobalObject.h
index 1dcfc63..af03f32 100644
--- a/Source/JavaScriptCore/runtime/JSGlobalObject.h
+++ b/Source/JavaScriptCore/runtime/JSGlobalObject.h
@@ -132,7 +132,7 @@
WriteBarrier<Structure> m_functionStructure;
WriteBarrier<Structure> m_boundFunctionStructure;
WriteBarrier<Structure> m_namedFunctionStructure;
- size_t m_functionNameOffset;
+ PropertyOffset m_functionNameOffset;
WriteBarrier<Structure> m_numberObjectStructure;
WriteBarrier<Structure> m_privateNameStructure;
WriteBarrier<Structure> m_regExpMatchesArrayStructure;
@@ -262,7 +262,7 @@
Structure* functionStructure() const { return m_functionStructure.get(); }
Structure* boundFunctionStructure() const { return m_boundFunctionStructure.get(); }
Structure* namedFunctionStructure() const { return m_namedFunctionStructure.get(); }
- size_t functionNameOffset() const { return m_functionNameOffset; }
+ PropertyOffset functionNameOffset() const { return m_functionNameOffset; }
Structure* numberObjectStructure() const { return m_numberObjectStructure.get(); }
Structure* privateNameStructure() const { return m_privateNameStructure.get(); }
Structure* internalFunctionStructure() const { return m_internalFunctionStructure.get(); }
diff --git a/Source/JavaScriptCore/runtime/JSObject.cpp b/Source/JavaScriptCore/runtime/JSObject.cpp
index 66cc898..ccc49fd 100644
--- a/Source/JavaScriptCore/runtime/JSObject.cpp
+++ b/Source/JavaScriptCore/runtime/JSObject.cpp
@@ -93,19 +93,17 @@
bool wasCheckingForDefaultMarkViolation = visitor.m_isCheckingForDefaultMarkViolation;
visitor.m_isCheckingForDefaultMarkViolation = false;
#endif
-
+
JSCell::visitChildren(thisObject, visitor);
- PropertyStorage storage = thisObject->propertyStorage();
- size_t storageSize = thisObject->structure()->propertyStorageSize();
- if (thisObject->isUsingInlineStorage())
- visitor.appendValues(storage, storageSize);
- else {
+ PropertyStorage storage = thisObject->outOfLineStorage();
+ if (storage) {
+ size_t storageSize = thisObject->structure()->outOfLineSizeForKnownNonFinalObject();
// We have this extra temp here to slake GCC's thirst for the blood of those who dereference type-punned pointers.
void* temp = storage;
- visitor.copyAndAppend(&temp, thisObject->structure()->propertyStorageCapacity() * sizeof(WriteBarrierBase<Unknown>), storage->slot(), storageSize);
+ visitor.copyAndAppend(&temp, thisObject->structure()->outOfLineCapacity() * sizeof(WriteBarrierBase<Unknown>), storage->slot(), storageSize);
storage = static_cast<PropertyStorage>(temp);
- thisObject->m_propertyStorage.set(storage, StorageBarrier::Unchecked);
+ thisObject->m_outOfLineStorage.set(storage, StorageBarrier::Unchecked);
}
if (thisObject->m_inheritorID)
@@ -116,6 +114,38 @@
#endif
}
+void JSFinalObject::visitChildren(JSCell* cell, SlotVisitor& visitor)
+{
+ JSFinalObject* thisObject = jsCast<JSFinalObject*>(cell);
+ ASSERT_GC_OBJECT_INHERITS(thisObject, &s_info);
+#if !ASSERT_DISABLED
+ bool wasCheckingForDefaultMarkViolation = visitor.m_isCheckingForDefaultMarkViolation;
+ visitor.m_isCheckingForDefaultMarkViolation = false;
+#endif
+
+ JSCell::visitChildren(thisObject, visitor);
+
+ PropertyStorage storage = thisObject->outOfLineStorage();
+ if (storage) {
+ size_t storageSize = thisObject->structure()->outOfLineSizeForKnownFinalObject();
+ // We have this extra temp here to slake GCC's thirst for the blood of those who dereference type-punned pointers.
+ void* temp = storage;
+ visitor.copyAndAppend(&temp, thisObject->structure()->outOfLineCapacity() * sizeof(WriteBarrierBase<Unknown>), storage->slot(), storageSize);
+ storage = static_cast<PropertyStorage>(temp);
+ thisObject->m_outOfLineStorage.set(storage, StorageBarrier::Unchecked);
+ }
+
+ if (thisObject->m_inheritorID)
+ visitor.append(&thisObject->m_inheritorID);
+
+ size_t storageSize = thisObject->structure()->inlineSizeForKnownFinalObject();
+ visitor.appendValues(thisObject->inlineStorage(), storageSize);
+
+#if !ASSERT_DISABLED
+ visitor.m_isCheckingForDefaultMarkViolation = wasCheckingForDefaultMarkViolation;
+#endif
+}
+
UString JSObject::className(const JSObject* object)
{
const ClassInfo* info = object->classInfo();
@@ -153,8 +183,8 @@
for (JSObject* obj = thisObject; ; obj = asObject(prototype)) {
unsigned attributes;
JSCell* specificValue;
- size_t offset = obj->structure()->get(globalData, propertyName, attributes, specificValue);
- if (offset != WTF::notFound) {
+ PropertyOffset offset = obj->structure()->get(globalData, propertyName, attributes, specificValue);
+ if (offset != invalidOffset) {
if (attributes & ReadOnly) {
if (slot.isStrictMode())
throwError(exec, createTypeError(exec, StrictModeReadonlyPropertyWriteError));
@@ -272,7 +302,7 @@
unsigned attributes;
JSCell* specificValue;
- if (thisObject->structure()->get(exec->globalData(), propertyName, attributes, specificValue) != WTF::notFound) {
+ if (isValidOffset(thisObject->structure()->get(exec->globalData(), propertyName, attributes, specificValue))) {
if (attributes & DontDelete && !exec->globalData().isInDefineOwnProperty())
return false;
thisObject->removeDirect(exec->globalData(), propertyName);
@@ -394,7 +424,7 @@
bool JSObject::getPropertySpecificValue(ExecState* exec, PropertyName propertyName, JSCell*& specificValue) const
{
unsigned attributes;
- if (structure()->get(exec->globalData(), propertyName, attributes, specificValue) != WTF::notFound)
+ if (isValidOffset(structure()->get(exec->globalData(), propertyName, attributes, specificValue)))
return true;
// This could be a function within the static table? - should probably
@@ -516,20 +546,20 @@
bool JSObject::removeDirect(JSGlobalData& globalData, PropertyName propertyName)
{
- if (structure()->get(globalData, propertyName) == WTF::notFound)
+ if (!isValidOffset(structure()->get(globalData, propertyName)))
return false;
- size_t offset;
+ PropertyOffset offset;
if (structure()->isUncacheableDictionary()) {
offset = structure()->removePropertyWithoutTransition(globalData, propertyName);
- if (offset == WTF::notFound)
+ if (offset == invalidOffset)
return false;
putUndefinedAtDirectOffset(offset);
return true;
}
setStructure(globalData, Structure::removePropertyTransition(globalData, structure(), propertyName, offset));
- if (offset == WTF::notFound)
+ if (offset == invalidOffset)
return false;
putUndefinedAtDirectOffset(offset);
return true;
@@ -559,25 +589,22 @@
return m_inheritorID.get();
}
-PropertyStorage JSObject::growPropertyStorage(JSGlobalData& globalData, size_t oldSize, size_t newSize)
+PropertyStorage JSObject::growOutOfLineStorage(JSGlobalData& globalData, size_t oldSize, size_t newSize)
{
ASSERT(newSize > oldSize);
// It's important that this function not rely on structure(), since
// we might be in the middle of a transition.
- PropertyStorage oldPropertyStorage = m_propertyStorage.get();
+ PropertyStorage oldPropertyStorage = m_outOfLineStorage.get();
PropertyStorage newPropertyStorage = 0;
- if (isUsingInlineStorage()) {
+ if (!oldPropertyStorage) {
// We have this extra temp here to slake GCC's thirst for the blood of those who dereference type-punned pointers.
void* temp = newPropertyStorage;
if (!globalData.heap.tryAllocateStorage(sizeof(WriteBarrierBase<Unknown>) * newSize, &temp))
CRASH();
newPropertyStorage = static_cast<PropertyStorage>(temp);
-
- for (unsigned i = 0; i < oldSize; ++i)
- newPropertyStorage[i] = oldPropertyStorage[i];
} else {
// We have this extra temp here to slake GCC's thirst for the blood of those who dereference type-punned pointers.
void* temp = oldPropertyStorage;
@@ -594,8 +621,8 @@
{
unsigned attributes = 0;
JSCell* cell = 0;
- size_t offset = object->structure()->get(exec->globalData(), propertyName, attributes, cell);
- if (offset == WTF::notFound)
+ PropertyOffset offset = object->structure()->get(exec->globalData(), propertyName, attributes, cell);
+ if (offset == invalidOffset)
return false;
descriptor.setDescriptor(object->getDirectOffset(offset), attributes);
return true;
diff --git a/Source/JavaScriptCore/runtime/JSObject.h b/Source/JavaScriptCore/runtime/JSObject.h
index db05591..7056623 100644
--- a/Source/JavaScriptCore/runtime/JSObject.h
+++ b/Source/JavaScriptCore/runtime/JSObject.h
@@ -79,18 +79,13 @@
Accessor = 1 << 5, // property is a getter/setter
};
-#if USE(JSVALUE32_64)
-#define JSFinalObject_inlineStorageCapacity 6
-#else
-#define JSFinalObject_inlineStorageCapacity 4
-#endif
-
-COMPILE_ASSERT((JSFinalObject_inlineStorageCapacity >= 0), final_storage_non_negative);
+ class JSFinalObject;
class JSObject : public JSCell {
friend class BatchedTransitionOptimizer;
friend class JIT;
friend class JSCell;
+ friend class JSFinalObject;
friend class MarkedBlock;
JS_EXPORT_PRIVATE friend bool setUpStaticFunctionSlot(ExecState*, const HashEntry*, JSObject*, PropertyName, PropertySlot&);
@@ -169,26 +164,72 @@
// This get function only looks at the property map.
JSValue getDirect(JSGlobalData& globalData, PropertyName propertyName) const
{
- size_t offset = structure()->get(globalData, propertyName);
- return offset != WTF::notFound ? getDirectOffset(offset) : JSValue();
+ PropertyOffset offset = structure()->get(globalData, propertyName);
+ checkOffset(offset, structure()->typeInfo().type());
+ return offset != invalidOffset ? getDirectOffset(offset) : JSValue();
}
WriteBarrierBase<Unknown>* getDirectLocation(JSGlobalData& globalData, PropertyName propertyName)
{
- size_t offset = structure()->get(globalData, propertyName);
- return offset != WTF::notFound ? locationForOffset(offset) : 0;
+ PropertyOffset offset = structure()->get(globalData, propertyName);
+ checkOffset(offset, structure()->typeInfo().type());
+ return offset != invalidOffset ? locationForOffset(offset) : 0;
}
WriteBarrierBase<Unknown>* getDirectLocation(JSGlobalData& globalData, PropertyName propertyName, unsigned& attributes)
{
JSCell* specificFunction;
- size_t offset = structure()->get(globalData, propertyName, attributes, specificFunction);
- return offset != WTF::notFound ? locationForOffset(offset) : 0;
+ PropertyOffset offset = structure()->get(globalData, propertyName, attributes, specificFunction);
+ return offset != invalidOffset ? locationForOffset(offset) : 0;
}
- size_t offsetForLocation(WriteBarrierBase<Unknown>* location) const
+ bool hasInlineStorage() const { return structure()->hasInlineStorage(); }
+ ConstPropertyStorage inlineStorageUnsafe() const
{
- return location - propertyStorage();
+ return bitwise_cast<ConstPropertyStorage>(this + 1);
+ }
+ PropertyStorage inlineStorageUnsafe()
+ {
+ return bitwise_cast<PropertyStorage>(this + 1);
+ }
+ ConstPropertyStorage inlineStorage() const
+ {
+ ASSERT(hasInlineStorage());
+ return inlineStorageUnsafe();
+ }
+ PropertyStorage inlineStorage()
+ {
+ ASSERT(hasInlineStorage());
+ return inlineStorageUnsafe();
+ }
+
+ ConstPropertyStorage outOfLineStorage() const { return m_outOfLineStorage.get(); }
+ PropertyStorage outOfLineStorage() { return m_outOfLineStorage.get(); }
+
+ const WriteBarrierBase<Unknown>* locationForOffset(PropertyOffset offset) const
+ {
+ if (isInlineOffset(offset))
+ return &inlineStorage()[offsetInInlineStorage(offset)];
+ return &outOfLineStorage()[offsetInOutOfLineStorage(offset)];
+ }
+
+ WriteBarrierBase<Unknown>* locationForOffset(PropertyOffset offset)
+ {
+ if (isInlineOffset(offset))
+ return &inlineStorage()[offsetInInlineStorage(offset)];
+ return &outOfLineStorage()[offsetInOutOfLineStorage(offset)];
+ }
+
+ PropertyOffset offsetForLocation(WriteBarrierBase<Unknown>* location) const
+ {
+ PropertyOffset result;
+ size_t offsetInInlineStorage = location - inlineStorageUnsafe();
+ if (offsetInInlineStorage < static_cast<size_t>(inlineStorageCapacity))
+ result = offsetInInlineStorage;
+ else
+ result = location - outOfLineStorage() + firstOutOfLineOffset;
+ validateOffset(result, structure()->typeInfo().type());
+ return result;
}
void transitionTo(JSGlobalData&, Structure*);
@@ -205,9 +246,9 @@
bool putOwnDataProperty(JSGlobalData&, PropertyName, JSValue, PutPropertySlot&);
// Fast access to known property offsets.
- JSValue getDirectOffset(size_t offset) const { return propertyStorage()[offset].get(); }
- void putDirectOffset(JSGlobalData& globalData, size_t offset, JSValue value) { propertyStorage()[offset].set(globalData, this, value); }
- void putUndefinedAtDirectOffset(size_t offset) { propertyStorage()[offset].setUndefined(); }
+ JSValue getDirectOffset(PropertyOffset offset) const { return locationForOffset(offset)->get(); }
+ void putDirectOffset(JSGlobalData& globalData, PropertyOffset offset, JSValue value) { locationForOffset(offset)->set(globalData, this, value); }
+ void putUndefinedAtDirectOffset(PropertyOffset offset) { locationForOffset(offset)->setUndefined(); }
JS_EXPORT_PRIVATE static bool defineOwnProperty(JSObject*, ExecState*, PropertyName, PropertyDescriptor&, bool shouldThrow);
@@ -228,24 +269,16 @@
bool staticFunctionsReified() { return structure()->staticFunctionsReified(); }
void reifyStaticFunctionsForDelete(ExecState* exec);
- JS_EXPORT_PRIVATE PropertyStorage growPropertyStorage(JSGlobalData&, size_t oldSize, size_t newSize);
- bool isUsingInlineStorage() const
- {
- bool result =
- !m_propertyStorage.get()
- || static_cast<const void*>(m_propertyStorage.get()) == static_cast<const void*>(this + 1);
- ASSERT(result == structure()->isUsingInlineStorage());
- return result;
- }
- void setPropertyStorage(JSGlobalData&, PropertyStorage, Structure*);
+ JS_EXPORT_PRIVATE PropertyStorage growOutOfLineStorage(JSGlobalData&, size_t oldSize, size_t newSize);
+ void setOutOfLineStorage(JSGlobalData&, PropertyStorage, Structure*);
bool reallocateStorageIfNecessary(JSGlobalData&, unsigned oldCapacity, Structure*);
void setStructureAndReallocateStorageIfNecessary(JSGlobalData&, unsigned oldCapacity, Structure*);
void setStructureAndReallocateStorageIfNecessary(JSGlobalData&, Structure*);
- void* addressOfPropertyStorage()
+ void* addressOfOutOfLineStorage()
{
- return &m_propertyStorage;
+ return &m_outOfLineStorage;
}
void flattenDictionaryObject(JSGlobalData& globalData)
@@ -261,7 +294,7 @@
}
static size_t offsetOfInlineStorage();
- static size_t offsetOfPropertyStorage();
+ static size_t offsetOfOutOfLineStorage();
static size_t offsetOfInheritorID();
static JS_EXPORTDATA const ClassInfo s_info;
@@ -271,7 +304,7 @@
{
Base::finishCreation(globalData);
ASSERT(inherits(&s_info));
- ASSERT(structure()->isUsingInlineStorage());
+ ASSERT(!structure()->outOfLineCapacity());
ASSERT(structure()->isEmpty());
ASSERT(prototype().isNull() || Heap::heap(this) == Heap::heap(prototype()));
ASSERT(structure()->isObject());
@@ -287,7 +320,7 @@
// To instantiate objects you likely want JSFinalObject, below.
// To create derived types you likely want JSNonFinalObject, below.
- JSObject(JSGlobalData&, Structure*, PropertyStorage inlineStorage);
+ JSObject(JSGlobalData&, Structure*);
void resetInheritorID()
{
@@ -305,19 +338,6 @@
void isObject();
void isString();
- ConstPropertyStorage propertyStorage() const { return m_propertyStorage.get(); }
- PropertyStorage propertyStorage() { return m_propertyStorage.get(); }
-
- const WriteBarrierBase<Unknown>* locationForOffset(size_t offset) const
- {
- return &propertyStorage()[offset];
- }
-
- WriteBarrierBase<Unknown>* locationForOffset(size_t offset)
- {
- return &propertyStorage()[offset];
- }
-
template<PutMode>
bool putDirectInternal(JSGlobalData&, PropertyName, JSValue, unsigned attr, PutPropertySlot&, JSCell*);
@@ -327,7 +347,7 @@
const HashEntry* findPropertyHashEntry(ExecState*, PropertyName) const;
Structure* createInheritorID(JSGlobalData&);
- StorageBarrier m_propertyStorage;
+ StorageBarrier m_outOfLineStorage;
WriteBarrier<Structure> m_inheritorID;
};
@@ -353,14 +373,14 @@
protected:
explicit JSNonFinalObject(JSGlobalData& globalData, Structure* structure)
- : JSObject(globalData, structure, 0)
+ : JSObject(globalData, structure)
{
}
void finishCreation(JSGlobalData& globalData)
{
Base::finishCreation(globalData);
- ASSERT(!this->structure()->propertyStorageCapacity());
+ ASSERT(!this->structure()->totalStorageCapacity());
ASSERT(classInfo());
}
};
@@ -381,6 +401,8 @@
return Structure::create(globalData, globalObject, prototype, TypeInfo(FinalObjectType, StructureFlags), &s_info);
}
+ JS_EXPORT_PRIVATE static void visitChildren(JSCell*, SlotVisitor&);
+
static JS_EXPORTDATA const ClassInfo s_info;
static bool hasInlineStorage()
@@ -388,11 +410,14 @@
return true;
}
protected:
+ void visitChildrenCommon(SlotVisitor&);
+
void finishCreation(JSGlobalData& globalData)
{
Base::finishCreation(globalData);
ASSERT(!(OBJECT_OFFSETOF(JSFinalObject, m_inlineStorage) % sizeof(double)));
- ASSERT(this->structure()->propertyStorageCapacity() == JSFinalObject_inlineStorageCapacity);
+ ASSERT(this->structure()->inlineCapacity() == inlineStorageCapacity);
+ ASSERT(this->structure()->totalStorageCapacity() == inlineStorageCapacity);
ASSERT(classInfo());
}
@@ -400,13 +425,13 @@
friend class LLIntOffsetsExtractor;
explicit JSFinalObject(JSGlobalData& globalData, Structure* structure)
- : JSObject(globalData, structure, m_inlineStorage)
+ : JSObject(globalData, structure)
{
}
static const unsigned StructureFlags = JSObject::StructureFlags;
- WriteBarrierBase<Unknown> m_inlineStorage[JSFinalObject_inlineStorageCapacity];
+ WriteBarrierBase<Unknown> m_inlineStorage[INLINE_STORAGE_CAPACITY];
};
inline JSFinalObject* JSFinalObject::create(ExecState* exec, Structure* structure)
@@ -431,9 +456,9 @@
return OBJECT_OFFSETOF(JSFinalObject, m_inlineStorage);
}
-inline size_t JSObject::offsetOfPropertyStorage()
+inline size_t JSObject::offsetOfOutOfLineStorage()
{
- return OBJECT_OFFSETOF(JSObject, m_propertyStorage);
+ return OBJECT_OFFSETOF(JSObject, m_outOfLineStorage);
}
inline size_t JSObject::offsetOfInheritorID()
@@ -471,14 +496,18 @@
return structure()->typeInfo().type() == GlobalThisType;
}
-inline void JSObject::setPropertyStorage(JSGlobalData& globalData, PropertyStorage storage, Structure* structure)
+inline void JSObject::setOutOfLineStorage(JSGlobalData& globalData, PropertyStorage storage, Structure* structure)
{
- ASSERT(storage);
ASSERT(structure);
- ASSERT(!structure->isUsingInlineStorage()
- || (classInfo() == &JSFinalObject::s_info && static_cast<void*>(storage) == static_cast<void*>(this + 1)));
+ if (!storage) {
+ ASSERT(!structure->outOfLineCapacity());
+ ASSERT(!structure->outOfLineSize());
+ } else {
+ ASSERT(structure->outOfLineCapacity());
+ ASSERT(structure->outOfLineSize());
+ }
setStructure(globalData, structure);
- m_propertyStorage.set(globalData, this, storage);
+ m_outOfLineStorage.set(globalData, this, storage);
}
inline JSObject* constructEmptyObject(ExecState* exec, Structure* structure)
@@ -516,9 +545,9 @@
return asObject(value.asCell());
}
-inline JSObject::JSObject(JSGlobalData& globalData, Structure* structure, PropertyStorage inlineStorage)
+inline JSObject::JSObject(JSGlobalData& globalData, Structure* structure)
: JSCell(globalData, structure)
- , m_propertyStorage(globalData, this, inlineStorage)
+ , m_outOfLineStorage(globalData, this, 0)
{
}
@@ -542,19 +571,6 @@
return createInheritorID(globalData);
}
-inline size_t Structure::inlineStorageCapacity() const
-{
- if (classInfo() == &JSFinalObject::s_info)
- return JSFinalObject_inlineStorageCapacity;
- return 0;
-}
-
-inline bool Structure::isUsingInlineStorage() const
-{
- ASSERT(propertyStorageCapacity() >= inlineStorageCapacity());
- return propertyStorageCapacity() == inlineStorageCapacity();
-}
-
inline bool JSCell::inherits(const ClassInfo* info) const
{
return classInfo()->isSubClassOf(info);
@@ -611,10 +627,10 @@
ALWAYS_INLINE JSValue JSCell::fastGetOwnProperty(ExecState* exec, const UString& name)
{
if (!structure()->typeInfo().overridesGetOwnPropertySlot() && !structure()->hasGetterSetterProperties()) {
- size_t offset = name.impl()->hasHash()
+ PropertyOffset offset = name.impl()->hasHash()
? structure()->get(exec->globalData(), Identifier(exec, name))
: structure()->get(exec->globalData(), name);
- if (offset != WTF::notFound)
+ if (offset != invalidOffset)
return asObject(this)->locationForOffset(offset)->get();
}
return JSValue();
@@ -676,8 +692,8 @@
if (structure()->isDictionary()) {
unsigned currentAttributes;
JSCell* currentSpecificFunction;
- size_t offset = structure()->get(globalData, propertyName, currentAttributes, currentSpecificFunction);
- if (offset != WTF::notFound) {
+ PropertyOffset offset = structure()->get(globalData, propertyName, currentAttributes, currentSpecificFunction);
+ if (offset != invalidOffset) {
// If there is currently a specific function, and there now either isn't,
// or the new value is different, then despecify.
if (currentSpecificFunction && (specificFunction != currentSpecificFunction))
@@ -700,13 +716,14 @@
if ((mode == PutModePut) && !isExtensible())
return false;
- PropertyStorage newStorage = propertyStorage();
- if (structure()->putWillGrowPropertyStorage())
- newStorage = growPropertyStorage(globalData, structure()->propertyStorageCapacity(), structure()->suggestedNewPropertyStorageSize());
+ PropertyStorage newStorage = outOfLineStorage();
+ if (structure()->putWillGrowOutOfLineStorage())
+ newStorage = growOutOfLineStorage(globalData, structure()->outOfLineCapacity(), structure()->suggestedNewOutOfLineStorageCapacity());
offset = structure()->addPropertyWithoutTransition(globalData, propertyName, attributes, specificFunction);
- setPropertyStorage(globalData, newStorage, structure());
+ setOutOfLineStorage(globalData, newStorage, structure());
- ASSERT(offset < structure()->propertyStorageCapacity());
+ validateOffset(offset);
+ ASSERT(structure()->isValidOffset(offset));
putDirectOffset(globalData, offset, value);
// See comment on setNewProperty call below.
if (!specificFunction)
@@ -714,15 +731,16 @@
return true;
}
- size_t offset;
- size_t currentCapacity = structure()->propertyStorageCapacity();
+ PropertyOffset offset;
+ size_t currentCapacity = structure()->outOfLineCapacity();
if (Structure* structure = Structure::addPropertyTransitionToExistingStructure(this->structure(), propertyName, attributes, specificFunction, offset)) {
- PropertyStorage newStorage = propertyStorage();
- if (currentCapacity != structure->propertyStorageCapacity())
- newStorage = growPropertyStorage(globalData, currentCapacity, structure->propertyStorageCapacity());
+ PropertyStorage newStorage = outOfLineStorage();
+ if (currentCapacity != structure->outOfLineCapacity())
+ newStorage = growOutOfLineStorage(globalData, currentCapacity, structure->outOfLineCapacity());
- ASSERT(offset < structure->propertyStorageCapacity());
- setPropertyStorage(globalData, newStorage, structure);
+ validateOffset(offset);
+ ASSERT(structure->isValidOffset(offset));
+ setOutOfLineStorage(globalData, newStorage, structure);
putDirectOffset(globalData, offset, value);
// This is a new property; transitions with specific values are not currently cachable,
// so leave the slot in an uncachable state.
@@ -734,7 +752,7 @@
unsigned currentAttributes;
JSCell* currentSpecificFunction;
offset = structure()->get(globalData, propertyName, currentAttributes, currentSpecificFunction);
- if (offset != WTF::notFound) {
+ if (offset != invalidOffset) {
if ((mode == PutModePut) && currentAttributes & ReadOnly)
return false;
@@ -768,7 +786,8 @@
Structure* structure = Structure::addPropertyTransition(globalData, this->structure(), propertyName, attributes, specificFunction, offset);
- ASSERT(offset < structure->propertyStorageCapacity());
+ validateOffset(offset);
+ ASSERT(structure->isValidOffset(offset));
setStructureAndReallocateStorageIfNecessary(globalData, structure);
putDirectOffset(globalData, offset, value);
@@ -781,22 +800,22 @@
inline void JSObject::setStructureAndReallocateStorageIfNecessary(JSGlobalData& globalData, unsigned oldCapacity, Structure* newStructure)
{
- ASSERT(oldCapacity <= newStructure->propertyStorageCapacity());
+ ASSERT(oldCapacity <= newStructure->outOfLineCapacity());
- if (oldCapacity == newStructure->propertyStorageCapacity()) {
+ if (oldCapacity == newStructure->outOfLineCapacity()) {
setStructure(globalData, newStructure);
return;
}
- PropertyStorage newStorage = growPropertyStorage(
- globalData, oldCapacity, newStructure->propertyStorageCapacity());
- setPropertyStorage(globalData, newStorage, newStructure);
+ PropertyStorage newStorage = growOutOfLineStorage(
+ globalData, oldCapacity, newStructure->outOfLineCapacity());
+ setOutOfLineStorage(globalData, newStorage, newStructure);
}
inline void JSObject::setStructureAndReallocateStorageIfNecessary(JSGlobalData& globalData, Structure* newStructure)
{
setStructureAndReallocateStorageIfNecessary(
- globalData, structure()->propertyStorageCapacity(), newStructure);
+ globalData, structure()->outOfLineCapacity(), newStructure);
}
inline bool JSObject::putOwnDataProperty(JSGlobalData& globalData, PropertyName propertyName, JSValue value, PutPropertySlot& slot)
@@ -824,11 +843,11 @@
inline void JSObject::putDirectWithoutTransition(JSGlobalData& globalData, PropertyName propertyName, JSValue value, unsigned attributes)
{
ASSERT(!value.isGetterSetter() && !(attributes & Accessor));
- PropertyStorage newStorage = propertyStorage();
- if (structure()->putWillGrowPropertyStorage())
- newStorage = growPropertyStorage(globalData, structure()->propertyStorageCapacity(), structure()->suggestedNewPropertyStorageSize());
- size_t offset = structure()->addPropertyWithoutTransition(globalData, propertyName, attributes, getCallableObject(value));
- setPropertyStorage(globalData, newStorage, structure());
+ PropertyStorage newStorage = outOfLineStorage();
+ if (structure()->putWillGrowOutOfLineStorage())
+ newStorage = growOutOfLineStorage(globalData, structure()->outOfLineCapacity(), structure()->suggestedNewOutOfLineStorageCapacity());
+ PropertyOffset offset = structure()->addPropertyWithoutTransition(globalData, propertyName, attributes, getCallableObject(value));
+ setOutOfLineStorage(globalData, newStorage, structure());
putDirectOffset(globalData, offset, value);
}
@@ -906,8 +925,6 @@
asCell()->methodTable()->putByIndex(asCell(), exec, propertyName, value, shouldThrow);
}
-// --- JSValue inlines ----------------------------
-
ALWAYS_INLINE JSObject* Register::function() const
{
if (!jsValue())
@@ -922,6 +939,32 @@
return r;
}
+// This is a helper for patching code where you want to emit a load or store and
+// the base is:
+// For inline offsets: a pointer to the out-of-line storage pointer.
+// For out-of-line offsets: the base of the out-of-line storage.
+inline size_t offsetRelativeToPatchedStorage(PropertyOffset offset)
+{
+ if (isOutOfLineOffset(offset))
+ return sizeof(EncodedJSValue) * offsetInOutOfLineStorage(offset);
+ return JSObject::offsetOfInlineStorage() - JSObject::offsetOfOutOfLineStorage() + sizeof(EncodedJSValue) * offsetInInlineStorage(offset);
+}
+
+inline int indexRelativeToBase(PropertyOffset offset)
+{
+ if (isOutOfLineOffset(offset))
+ return offsetInOutOfLineStorage(offset);
+ ASSERT(!(JSObject::offsetOfInlineStorage() % sizeof(EncodedJSValue)));
+ return JSObject::offsetOfInlineStorage() / sizeof(EncodedJSValue) + offsetInInlineStorage(offset);
+}
+
+inline int offsetRelativeToBase(PropertyOffset offset)
+{
+ if (isOutOfLineOffset(offset))
+ return offsetInOutOfLineStorage(offset) * sizeof(EncodedJSValue);
+ return JSObject::offsetOfInlineStorage() + offsetInInlineStorage(offset) * sizeof(EncodedJSValue);
+}
+
} // namespace JSC
#endif // JSObject_h
diff --git a/Source/JavaScriptCore/runtime/JSPropertyNameIterator.cpp b/Source/JavaScriptCore/runtime/JSPropertyNameIterator.cpp
index 6ceb3c4..aaf946d 100644
--- a/Source/JavaScriptCore/runtime/JSPropertyNameIterator.cpp
+++ b/Source/JavaScriptCore/runtime/JSPropertyNameIterator.cpp
@@ -56,10 +56,10 @@
size_t numCacheableSlots = 0;
if (!o->structure()->hasNonEnumerableProperties() && !o->structure()->hasGetterSetterProperties()
&& !o->structure()->isUncacheableDictionary() && !o->structure()->typeInfo().overridesGetPropertyNames())
- numCacheableSlots = o->structure()->propertyStorageSize();
+ numCacheableSlots = o->structure()->totalStorageSize();
JSPropertyNameIterator* jsPropertyNameIterator = new (NotNull, allocateCell<JSPropertyNameIterator>(*exec->heap())) JSPropertyNameIterator(exec, propertyNames.data(), numCacheableSlots);
- jsPropertyNameIterator->finishCreation(exec, propertyNames.data());
+ jsPropertyNameIterator->finishCreation(exec, propertyNames.data(), o);
if (o->structure()->isDictionary())
return jsPropertyNameIterator;
diff --git a/Source/JavaScriptCore/runtime/JSPropertyNameIterator.h b/Source/JavaScriptCore/runtime/JSPropertyNameIterator.h
index 5b65e59..653ee04 100644
--- a/Source/JavaScriptCore/runtime/JSPropertyNameIterator.h
+++ b/Source/JavaScriptCore/runtime/JSPropertyNameIterator.h
@@ -47,12 +47,6 @@
typedef JSCell Base;
static JSPropertyNameIterator* create(ExecState*, JSObject*);
- static JSPropertyNameIterator* create(ExecState* exec, PropertyNameArrayData* propertyNameArrayData, size_t numCacheableSlot)
- {
- JSPropertyNameIterator* iterator = new (NotNull, allocateCell<JSPropertyNameIterator>(*exec->heap())) JSPropertyNameIterator(exec, propertyNameArrayData, numCacheableSlot);
- iterator->finishCreation(exec, propertyNameArrayData);
- return iterator;
- }
static void destroy(JSCell*);
@@ -63,11 +57,11 @@
static void visitChildren(JSCell*, SlotVisitor&);
- bool getOffset(size_t i, int& offset)
+ bool getOffset(size_t i, PropertyOffset& offset)
{
if (i >= m_numCacheableSlots)
return false;
- offset = i;
+ offset = i + m_offsetBase;
return true;
}
@@ -88,12 +82,13 @@
static const ClassInfo s_info;
protected:
- void finishCreation(ExecState* exec, PropertyNameArrayData* propertyNameArrayData)
+ void finishCreation(ExecState* exec, PropertyNameArrayData* propertyNameArrayData, JSObject* object)
{
Base::finishCreation(exec->globalData());
PropertyNameArrayData::PropertyNameVector& propertyNameVector = propertyNameArrayData->propertyNameVector();
for (size_t i = 0; i < m_jsStringsSize; ++i)
m_jsStrings[i].set(exec->globalData(), this, jsOwnedString(exec, propertyNameVector[i].ustring()));
+ m_offsetBase = object->structure()->firstValidOffset();
}
private:
@@ -105,6 +100,7 @@
WriteBarrier<StructureChain> m_cachedPrototypeChain;
uint32_t m_numCacheableSlots;
uint32_t m_jsStringsSize;
+ PropertyOffset m_offsetBase;
OwnArrayPtr<WriteBarrier<Unknown> > m_jsStrings;
};
diff --git a/Source/JavaScriptCore/runtime/JSValue.cpp b/Source/JavaScriptCore/runtime/JSValue.cpp
index e108671..c344311 100644
--- a/Source/JavaScriptCore/runtime/JSValue.cpp
+++ b/Source/JavaScriptCore/runtime/JSValue.cpp
@@ -130,8 +130,8 @@
for (; ; obj = asObject(prototype)) {
unsigned attributes;
JSCell* specificValue;
- size_t offset = obj->structure()->get(globalData, propertyName, attributes, specificValue);
- if (offset != WTF::notFound) {
+ PropertyOffset offset = obj->structure()->get(globalData, propertyName, attributes, specificValue);
+ if (offset != invalidOffset) {
if (attributes & ReadOnly) {
if (slot.isStrictMode())
throwError(exec, createTypeError(exec, StrictModeReadonlyPropertyWriteError));
diff --git a/Source/JavaScriptCore/runtime/Operations.h b/Source/JavaScriptCore/runtime/Operations.h
index b2081f3..497b19d 100644
--- a/Source/JavaScriptCore/runtime/Operations.h
+++ b/Source/JavaScriptCore/runtime/Operations.h
@@ -297,7 +297,7 @@
return jsAddSlowCase(callFrame, v1, v2);
}
- inline size_t normalizePrototypeChain(CallFrame* callFrame, JSValue base, JSValue slotBase, const Identifier& propertyName, size_t& slotOffset)
+ inline size_t normalizePrototypeChain(CallFrame* callFrame, JSValue base, JSValue slotBase, const Identifier& propertyName, PropertyOffset& slotOffset)
{
JSCell* cell = base.asCell();
size_t count = 0;
diff --git a/Source/JavaScriptCore/runtime/Options.cpp b/Source/JavaScriptCore/runtime/Options.cpp
index 17743d3..b5ce39c 100644
--- a/Source/JavaScriptCore/runtime/Options.cpp
+++ b/Source/JavaScriptCore/runtime/Options.cpp
@@ -106,7 +106,6 @@
return cpusToUse;
}
-
Options::Entry Options::s_options[Options::numberOfOptions];
// Realize the names for each of the options:
@@ -124,7 +123,7 @@
name_() = defaultValue_;
JSC_OPTIONS(FOR_EACH_OPTION)
#undef FOR_EACH_OPTION
-
+
// Allow environment vars to override options if applicable.
// The evn var should be the name of the option prefixed with
// "JSC_".
@@ -133,9 +132,12 @@
overrideOptionWithHeuristic(name_(), "JSC_" #name_);
JSC_OPTIONS(FOR_EACH_OPTION)
#undef FOR_EACH_OPTION
-
#endif // RUN_TIME_HEURISTICS
+#if 0
+ ; // Deconfuse editors that do auto indentation
+#endif
+
// Do range checks where needed and make corrections to the options:
ASSERT(thresholdForOptimizeAfterLongWarmUp() >= thresholdForOptimizeAfterWarmUp());
ASSERT(thresholdForOptimizeAfterWarmUp() >= thresholdForOptimizeSoon());
diff --git a/Source/JavaScriptCore/runtime/PropertyMapHashTable.h b/Source/JavaScriptCore/runtime/PropertyMapHashTable.h
index c47f347..5953f5e 100644
--- a/Source/JavaScriptCore/runtime/PropertyMapHashTable.h
+++ b/Source/JavaScriptCore/runtime/PropertyMapHashTable.h
@@ -21,6 +21,7 @@
#ifndef PropertyMapHashTable_h
#define PropertyMapHashTable_h
+#include "PropertyOffset.h"
#include "UString.h"
#include "WriteBarrier.h"
#include <wtf/HashTable.h>
@@ -72,11 +73,11 @@
struct PropertyMapEntry {
StringImpl* key;
- unsigned offset;
+ PropertyOffset offset;
unsigned attributes;
WriteBarrier<JSCell> specificValue;
- PropertyMapEntry(JSGlobalData& globalData, JSCell* owner, StringImpl* key, unsigned offset, unsigned attributes, JSCell* specificValue)
+ PropertyMapEntry(JSGlobalData& globalData, JSCell* owner, StringImpl* key, PropertyOffset offset, unsigned attributes, JSCell* specificValue)
: key(key)
, offset(offset)
, attributes(attributes)
@@ -174,8 +175,10 @@
// Used to maintain a list of unused entries in the property storage.
void clearDeletedOffsets();
bool hasDeletedOffset();
- unsigned getDeletedOffset();
- void addDeletedOffset(unsigned offset);
+ PropertyOffset getDeletedOffset();
+ void addDeletedOffset(PropertyOffset);
+
+ PropertyOffset nextOffset(JSType);
// Copy this PropertyTable, ensuring the copy has at least the capacity provided.
PassOwnPtr<PropertyTable> copy(JSGlobalData&, JSCell* owner, unsigned newCapacity);
@@ -230,7 +233,7 @@
unsigned* m_index;
unsigned m_keyCount;
unsigned m_deletedCount;
- OwnPtr< Vector<unsigned> > m_deletedOffsets;
+ OwnPtr< Vector<PropertyOffset> > m_deletedOffsets;
static const unsigned MinimumTableSize = 16;
static const unsigned EmptyEntryIndex = 0;
@@ -264,9 +267,9 @@
}
// Copy the m_deletedOffsets vector.
- Vector<unsigned>* otherDeletedOffsets = other.m_deletedOffsets.get();
+ Vector<PropertyOffset>* otherDeletedOffsets = other.m_deletedOffsets.get();
if (otherDeletedOffsets)
- m_deletedOffsets = adoptPtr(new Vector<unsigned>(*otherDeletedOffsets));
+ m_deletedOffsets = adoptPtr(new Vector<PropertyOffset>(*otherDeletedOffsets));
}
inline PropertyTable::PropertyTable(JSGlobalData&, JSCell* owner, unsigned initialCapacity, const PropertyTable& other)
@@ -288,9 +291,9 @@
}
// Copy the m_deletedOffsets vector.
- Vector<unsigned>* otherDeletedOffsets = other.m_deletedOffsets.get();
+ Vector<PropertyOffset>* otherDeletedOffsets = other.m_deletedOffsets.get();
if (otherDeletedOffsets)
- m_deletedOffsets = adoptPtr(new Vector<unsigned>(*otherDeletedOffsets));
+ m_deletedOffsets = adoptPtr(new Vector<PropertyOffset>(*otherDeletedOffsets));
}
inline PropertyTable::~PropertyTable()
@@ -469,20 +472,31 @@
return m_deletedOffsets && !m_deletedOffsets->isEmpty();
}
-inline unsigned PropertyTable::getDeletedOffset()
+inline PropertyOffset PropertyTable::getDeletedOffset()
{
- unsigned offset = m_deletedOffsets->last();
+ PropertyOffset offset = m_deletedOffsets->last();
m_deletedOffsets->removeLast();
return offset;
}
-inline void PropertyTable::addDeletedOffset(unsigned offset)
+inline void PropertyTable::addDeletedOffset(PropertyOffset offset)
{
if (!m_deletedOffsets)
- m_deletedOffsets = adoptPtr(new Vector<unsigned>);
+ m_deletedOffsets = adoptPtr(new Vector<PropertyOffset>);
m_deletedOffsets->append(offset);
}
+inline PropertyOffset PropertyTable::nextOffset(JSType type)
+{
+ if (hasDeletedOffset())
+ return getDeletedOffset();
+
+ if (type == FinalObjectType)
+ return size();
+
+ return size() + firstOutOfLineOffset;
+}
+
inline PassOwnPtr<PropertyTable> PropertyTable::copy(JSGlobalData& globalData, JSCell* owner, unsigned newCapacity)
{
ASSERT(newCapacity >= m_keyCount);
@@ -499,7 +513,7 @@
{
size_t result = sizeof(PropertyTable) + dataSize();
if (m_deletedOffsets)
- result += (m_deletedOffsets->capacity() * sizeof(unsigned));
+ result += (m_deletedOffsets->capacity() * sizeof(PropertyOffset));
return result;
}
#endif
diff --git a/Source/JavaScriptCore/runtime/PropertyOffset.h b/Source/JavaScriptCore/runtime/PropertyOffset.h
new file mode 100644
index 0000000..c0d1316
--- /dev/null
+++ b/Source/JavaScriptCore/runtime/PropertyOffset.h
@@ -0,0 +1,163 @@
+/*
+ * Copyright (C) 2012 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.
+ */
+
+#ifndef PropertyOffset_h
+#define PropertyOffset_h
+
+#include "JSType.h"
+#include <wtf/Platform.h>
+#include <wtf/StdLibExtras.h>
+#include <wtf/UnusedParam.h>
+
+namespace JSC {
+
+#if USE(JSVALUE32_64)
+#define INLINE_STORAGE_CAPACITY 6
+#else
+#define INLINE_STORAGE_CAPACITY 4
+#endif
+
+typedef int PropertyOffset;
+
+static const PropertyOffset invalidOffset = -1;
+static const PropertyOffset inlineStorageCapacity = INLINE_STORAGE_CAPACITY;
+static const PropertyOffset firstOutOfLineOffset = inlineStorageCapacity;
+
+// Declare all of the functions because they tend to do forward calls.
+inline void checkOffset(PropertyOffset);
+inline void checkOffset(PropertyOffset, JSType);
+inline void validateOffset(PropertyOffset);
+inline void validateOffset(PropertyOffset, JSType);
+inline bool isValidOffset(PropertyOffset);
+inline bool isInlineOffset(PropertyOffset);
+inline bool isOutOfLineOffset(PropertyOffset);
+inline size_t offsetInInlineStorage(PropertyOffset);
+inline size_t offsetInOutOfLineStorage(PropertyOffset);
+inline size_t offsetInRespectiveStorage(PropertyOffset);
+inline size_t numberOfOutOfLineSlotsForLastOffset(PropertyOffset);
+inline size_t numberOfSlotsForLastOffset(PropertyOffset, JSType);
+inline PropertyOffset nextPropertyOffsetFor(PropertyOffset, JSType);
+inline PropertyOffset firstPropertyOffsetFor(JSType);
+
+inline void checkOffset(PropertyOffset offset)
+{
+ UNUSED_PARAM(offset);
+ ASSERT(offset >= invalidOffset);
+}
+
+inline void checkOffset(PropertyOffset offset, JSType type)
+{
+ UNUSED_PARAM(offset);
+ UNUSED_PARAM(type);
+ ASSERT(offset >= invalidOffset);
+ ASSERT(offset == invalidOffset
+ || type == FinalObjectType
+ || isOutOfLineOffset(offset));
+}
+
+inline void validateOffset(PropertyOffset offset)
+{
+ checkOffset(offset);
+ ASSERT(isValidOffset(offset));
+}
+
+inline void validateOffset(PropertyOffset offset, JSType type)
+{
+ checkOffset(offset, type);
+ ASSERT(isValidOffset(offset));
+}
+
+inline bool isValidOffset(PropertyOffset offset)
+{
+ checkOffset(offset);
+ return offset != invalidOffset;
+}
+
+inline bool isInlineOffset(PropertyOffset offset)
+{
+ checkOffset(offset);
+ return offset < inlineStorageCapacity;
+}
+
+inline bool isOutOfLineOffset(PropertyOffset offset)
+{
+ checkOffset(offset);
+ return !isInlineOffset(offset);
+}
+
+inline size_t offsetInInlineStorage(PropertyOffset offset)
+{
+ validateOffset(offset);
+ ASSERT(isInlineOffset(offset));
+ return offset;
+}
+
+inline size_t offsetInOutOfLineStorage(PropertyOffset offset)
+{
+ validateOffset(offset);
+ ASSERT(isOutOfLineOffset(offset));
+ return offset - firstOutOfLineOffset;
+}
+
+inline size_t offsetInRespectiveStorage(PropertyOffset offset)
+{
+ if (isInlineOffset(offset))
+ return offsetInInlineStorage(offset);
+ return offsetInOutOfLineStorage(offset);
+}
+
+inline size_t numberOfOutOfLineSlotsForLastOffset(PropertyOffset offset)
+{
+ checkOffset(offset);
+ if (offset < firstOutOfLineOffset)
+ return 0;
+ return offset - firstOutOfLineOffset + 1;
+}
+
+inline size_t numberOfSlotsForLastOffset(PropertyOffset offset, JSType type)
+{
+ checkOffset(offset, type);
+ if (type == FinalObjectType)
+ return offset + 1;
+ return numberOfOutOfLineSlotsForLastOffset(offset);
+}
+
+inline PropertyOffset nextPropertyOffsetFor(PropertyOffset offset, JSType type)
+{
+ checkOffset(offset, type);
+ if (type != FinalObjectType && offset == invalidOffset)
+ return firstOutOfLineOffset;
+ return offset + 1;
+}
+
+inline PropertyOffset firstPropertyOffsetFor(JSType type)
+{
+ return nextPropertyOffsetFor(invalidOffset, type);
+}
+
+} // namespace JSC
+
+#endif // PropertyOffset_h
+
diff --git a/Source/JavaScriptCore/runtime/PropertySlot.h b/Source/JavaScriptCore/runtime/PropertySlot.h
index 131cf7a9..c673eaa 100644
--- a/Source/JavaScriptCore/runtime/PropertySlot.h
+++ b/Source/JavaScriptCore/runtime/PropertySlot.h
@@ -23,6 +23,7 @@
#include "JSValue.h"
#include "PropertyName.h"
+#include "PropertyOffset.h"
#include "Register.h"
#include <wtf/Assertions.h>
#include <wtf/NotFound.h>
@@ -89,7 +90,7 @@
CachedPropertyType cachedPropertyType() const { return m_cachedPropertyType; }
bool isCacheable() const { return m_cachedPropertyType != Uncacheable; }
bool isCacheableValue() const { return m_cachedPropertyType == Value; }
- size_t cachedOffset() const
+ PropertyOffset cachedOffset() const
{
ASSERT(isCacheable());
return m_offset;
@@ -104,7 +105,7 @@
m_value = value;
}
- void setValue(JSValue slotBase, JSValue value, size_t offset)
+ void setValue(JSValue slotBase, JSValue value, PropertyOffset offset)
{
ASSERT(value);
m_getValue = JSC_VALUE_MARKER;
@@ -160,7 +161,7 @@
m_data.getterFunc = getterFunc;
}
- void setCacheableGetterSlot(JSValue slotBase, JSObject* getterFunc, unsigned offset)
+ void setCacheableGetterSlot(JSValue slotBase, JSObject* getterFunc, PropertyOffset offset)
{
ASSERT(getterFunc);
m_getValue = GETTER_FUNCTION_MARKER;
@@ -206,7 +207,7 @@
{
// Clear offset even in release builds, in case this PropertySlot has been used before.
// (For other data members, we don't need to clear anything because reuse would meaningfully overwrite them.)
- m_offset = 0;
+ m_offset = invalidOffset;
m_cachedPropertyType = Uncacheable;
}
@@ -232,7 +233,7 @@
JSValue m_value;
JSValue m_thisValue;
- size_t m_offset;
+ PropertyOffset m_offset;
CachedPropertyType m_cachedPropertyType;
};
diff --git a/Source/JavaScriptCore/runtime/PutPropertySlot.h b/Source/JavaScriptCore/runtime/PutPropertySlot.h
index 69d1f8b..0f694e3 100644
--- a/Source/JavaScriptCore/runtime/PutPropertySlot.h
+++ b/Source/JavaScriptCore/runtime/PutPropertySlot.h
@@ -45,14 +45,14 @@
{
}
- void setExistingProperty(JSObject* base, size_t offset)
+ void setExistingProperty(JSObject* base, PropertyOffset offset)
{
m_type = ExistingProperty;
m_base = base;
m_offset = offset;
}
- void setNewProperty(JSObject* base, size_t offset)
+ void setNewProperty(JSObject* base, PropertyOffset offset)
{
m_type = NewProperty;
m_base = base;
@@ -64,7 +64,8 @@
bool isStrictMode() const { return m_isStrictMode; }
bool isCacheable() const { return m_type != Uncachable; }
- size_t cachedOffset() const {
+ PropertyOffset cachedOffset() const
+ {
ASSERT(isCacheable());
return m_offset;
}
@@ -72,7 +73,7 @@
private:
Type m_type;
JSObject* m_base;
- size_t m_offset;
+ PropertyOffset m_offset;
bool m_isStrictMode;
};
diff --git a/Source/JavaScriptCore/runtime/Structure.cpp b/Source/JavaScriptCore/runtime/Structure.cpp
index a2585b0..509ff3d 100644
--- a/Source/JavaScriptCore/runtime/Structure.cpp
+++ b/Source/JavaScriptCore/runtime/Structure.cpp
@@ -156,8 +156,8 @@
, m_prototype(globalData, this, prototype)
, m_classInfo(classInfo)
, m_transitionWatchpointSet(InitializedWatching)
- , m_propertyStorageCapacity(typeInfo.isFinalObject() ? JSFinalObject_inlineStorageCapacity : 0)
- , m_offset(noOffset)
+ , m_outOfLineCapacity(0)
+ , m_offset(invalidOffset)
, m_dictionaryKind(NoneDictionaryKind)
, m_isPinnedPropertyTable(false)
, m_hasGetterSetterProperties(false)
@@ -179,8 +179,8 @@
, m_prototype(globalData, this, jsNull())
, m_classInfo(&s_info)
, m_transitionWatchpointSet(InitializedWatching)
- , m_propertyStorageCapacity(0)
- , m_offset(noOffset)
+ , m_outOfLineCapacity(0)
+ , m_offset(invalidOffset)
, m_dictionaryKind(NoneDictionaryKind)
, m_isPinnedPropertyTable(false)
, m_hasGetterSetterProperties(false)
@@ -200,8 +200,8 @@
, m_prototype(globalData, this, previous->storedPrototype())
, m_classInfo(previous->m_classInfo)
, m_transitionWatchpointSet(InitializedWatching)
- , m_propertyStorageCapacity(previous->m_propertyStorageCapacity)
- , m_offset(noOffset)
+ , m_outOfLineCapacity(previous->m_outOfLineCapacity)
+ , m_offset(invalidOffset)
, m_dictionaryKind(previous->m_dictionaryKind)
, m_isPinnedPropertyTable(false)
, m_hasGetterSetterProperties(previous->m_hasGetterSetterProperties)
@@ -239,7 +239,7 @@
ASSERT(structure->m_propertyTable);
ASSERT(!structure->m_previous);
- m_propertyTable = structure->m_propertyTable->copy(globalData, 0, m_offset + 1);
+ m_propertyTable = structure->m_propertyTable->copy(globalData, 0, numberOfSlotsForLastOffset(m_offset, m_typeInfo.type()));
break;
}
@@ -247,7 +247,7 @@
}
if (!m_propertyTable)
- createPropertyMap(m_offset + 1);
+ createPropertyMap(numberOfSlotsForLastOffset(m_offset, m_typeInfo.type()));
for (ptrdiff_t i = structures.size() - 2; i >= 0; --i) {
structure = structures[i];
@@ -256,21 +256,21 @@
}
}
-inline size_t nextPropertyStorageCapacity(size_t currentCapacity)
+inline size_t nextOutOfLineStorageCapacity(size_t currentCapacity)
{
if (!currentCapacity)
return 4;
return currentCapacity * 2;
}
-void Structure::growPropertyStorageCapacity()
+void Structure::growOutOfLineCapacity()
{
- m_propertyStorageCapacity = nextPropertyStorageCapacity(m_propertyStorageCapacity);
+ m_outOfLineCapacity = nextOutOfLineStorageCapacity(m_outOfLineCapacity);
}
-size_t Structure::suggestedNewPropertyStorageSize()
+size_t Structure::suggestedNewOutOfLineStorageCapacity()
{
- return nextPropertyStorageCapacity(m_propertyStorageCapacity);
+ return nextOutOfLineStorageCapacity(m_outOfLineCapacity);
}
void Structure::despecifyDictionaryFunction(JSGlobalData& globalData, PropertyName propertyName)
@@ -287,7 +287,7 @@
entry->specificValue.clear();
}
-Structure* Structure::addPropertyTransitionToExistingStructure(Structure* structure, PropertyName propertyName, unsigned attributes, JSCell* specificValue, size_t& offset)
+Structure* Structure::addPropertyTransitionToExistingStructure(Structure* structure, PropertyName propertyName, unsigned attributes, JSCell* specificValue, PropertyOffset& offset)
{
ASSERT(!structure->isDictionary());
ASSERT(structure->isObject());
@@ -296,7 +296,7 @@
JSCell* specificValueInPrevious = existingTransition->m_specificValueInPrevious.get();
if (specificValueInPrevious && specificValueInPrevious != specificValue)
return 0;
- ASSERT(existingTransition->m_offset != noOffset);
+ validateOffset(existingTransition->m_offset, structure->m_typeInfo.type());
offset = existingTransition->m_offset;
return existingTransition;
}
@@ -304,7 +304,7 @@
return 0;
}
-Structure* Structure::addPropertyTransition(JSGlobalData& globalData, Structure* structure, PropertyName propertyName, unsigned attributes, JSCell* specificValue, size_t& offset)
+Structure* Structure::addPropertyTransition(JSGlobalData& globalData, Structure* structure, PropertyName propertyName, unsigned attributes, JSCell* specificValue, PropertyOffset& offset)
{
// If we have a specific function, we may have got to this point if there is
// already a transition with the correct property name and attributes, but
@@ -327,8 +327,8 @@
Structure* transition = toCacheableDictionaryTransition(globalData, structure);
ASSERT(structure != transition);
offset = transition->putSpecificValue(globalData, propertyName, attributes, specificValue);
- if (transition->propertyStorageSize() > transition->propertyStorageCapacity())
- transition->growPropertyStorageCapacity();
+ if (transition->outOfLineSize() > transition->outOfLineCapacity())
+ transition->growOutOfLineCapacity();
return transition;
}
@@ -353,15 +353,15 @@
}
offset = transition->putSpecificValue(globalData, propertyName, attributes, specificValue);
- if (transition->propertyStorageSize() > transition->propertyStorageCapacity())
- transition->growPropertyStorageCapacity();
+ if (transition->outOfLineSize() > transition->outOfLineCapacity())
+ transition->growOutOfLineCapacity();
transition->m_offset = offset;
structure->m_transitionTable.add(globalData, transition);
return transition;
}
-Structure* Structure::removePropertyTransition(JSGlobalData& globalData, Structure* structure, PropertyName propertyName, size_t& offset)
+Structure* Structure::removePropertyTransition(JSGlobalData& globalData, Structure* structure, PropertyName propertyName, PropertyOffset& offset)
{
ASSERT(!structure->isUncacheableDictionary());
@@ -548,18 +548,19 @@
size_t propertyCount = m_propertyTable->size();
Vector<JSValue> values(propertyCount);
-
+
unsigned i = 0;
+ PropertyOffset firstOffset = firstPropertyOffsetFor(m_typeInfo.type());
PropertyTable::iterator end = m_propertyTable->end();
for (PropertyTable::iterator iter = m_propertyTable->begin(); iter != end; ++iter, ++i) {
values[i] = object->getDirectOffset(iter->offset);
// Update property table to have the new property offsets
- iter->offset = i;
+ iter->offset = i + firstOffset;
}
// Copy the original property values into their final locations
for (unsigned i = 0; i < propertyCount; i++)
- object->putDirectOffset(globalData, i, values[i]);
+ object->putDirectOffset(globalData, firstOffset + i, values[i]);
m_propertyTable->clearDeletedOffsets();
}
@@ -568,7 +569,7 @@
return this;
}
-size_t Structure::addPropertyWithoutTransition(JSGlobalData& globalData, PropertyName propertyName, unsigned attributes, JSCell* specificValue)
+PropertyOffset Structure::addPropertyWithoutTransition(JSGlobalData& globalData, PropertyName propertyName, unsigned attributes, JSCell* specificValue)
{
ASSERT(!m_enumerationCache);
@@ -579,13 +580,13 @@
pin();
- size_t offset = putSpecificValue(globalData, propertyName, attributes, specificValue);
- if (propertyStorageSize() > propertyStorageCapacity())
- growPropertyStorageCapacity();
+ PropertyOffset offset = putSpecificValue(globalData, propertyName, attributes, specificValue);
+ if (outOfLineSize() > outOfLineCapacity())
+ growOutOfLineCapacity();
return offset;
}
-size_t Structure::removePropertyWithoutTransition(JSGlobalData& globalData, PropertyName propertyName)
+PropertyOffset Structure::removePropertyWithoutTransition(JSGlobalData& globalData, PropertyName propertyName)
{
ASSERT(isUncacheableDictionary());
ASSERT(!m_enumerationCache);
@@ -593,8 +594,7 @@
materializePropertyMapIfNecessaryForPinning(globalData);
pin();
- size_t offset = remove(propertyName);
- return offset;
+ return remove(propertyName);
}
void Structure::pin()
@@ -639,20 +639,20 @@
PassOwnPtr<PropertyTable> Structure::copyPropertyTableForPinning(JSGlobalData& globalData, Structure* owner)
{
- return adoptPtr(m_propertyTable ? new PropertyTable(globalData, owner, *m_propertyTable) : new PropertyTable(m_offset == noOffset ? 0 : m_offset));
+ return adoptPtr(m_propertyTable ? new PropertyTable(globalData, owner, *m_propertyTable) : new PropertyTable(numberOfSlotsForLastOffset(m_offset, m_typeInfo.type())));
}
-size_t Structure::get(JSGlobalData& globalData, PropertyName propertyName, unsigned& attributes, JSCell*& specificValue)
+PropertyOffset Structure::get(JSGlobalData& globalData, PropertyName propertyName, unsigned& attributes, JSCell*& specificValue)
{
ASSERT(structure()->classInfo() == &s_info);
materializePropertyMapIfNecessary(globalData);
if (!m_propertyTable)
- return WTF::notFound;
+ return invalidOffset;
PropertyMapEntry* entry = m_propertyTable->find(propertyName.uid()).first;
if (!entry)
- return WTF::notFound;
+ return invalidOffset;
attributes = entry->attributes;
specificValue = entry->specificValue.get();
@@ -685,9 +685,9 @@
iter->specificValue.clear();
}
-size_t Structure::putSpecificValue(JSGlobalData& globalData, PropertyName propertyName, unsigned attributes, JSCell* specificValue)
+PropertyOffset Structure::putSpecificValue(JSGlobalData& globalData, PropertyName propertyName, unsigned attributes, JSCell* specificValue)
{
- ASSERT(get(globalData, propertyName) == notFound);
+ ASSERT(!JSC::isValidOffset(get(globalData, propertyName)));
checkConsistency();
if (attributes & DontEnum)
@@ -698,12 +698,7 @@
if (!m_propertyTable)
createPropertyMap();
- unsigned newOffset;
-
- if (m_propertyTable->hasDeletedOffset())
- newOffset = m_propertyTable->getDeletedOffset();
- else
- newOffset = m_propertyTable->size();
+ PropertyOffset newOffset = m_propertyTable->nextOffset(m_typeInfo.type());
m_propertyTable->add(PropertyMapEntry(globalData, this, rep, newOffset, attributes, specificValue));
@@ -711,20 +706,20 @@
return newOffset;
}
-size_t Structure::remove(PropertyName propertyName)
+PropertyOffset Structure::remove(PropertyName propertyName)
{
checkConsistency();
StringImpl* rep = propertyName.uid();
if (!m_propertyTable)
- return notFound;
+ return invalidOffset;
PropertyTable::find_iterator position = m_propertyTable->find(rep);
if (!position.first)
- return notFound;
+ return invalidOffset;
- size_t offset = position.first->offset;
+ PropertyOffset offset = position.first->offset;
m_propertyTable->remove(position);
m_propertyTable->addDeletedOffset(offset);
diff --git a/Source/JavaScriptCore/runtime/Structure.h b/Source/JavaScriptCore/runtime/Structure.h
index bb53c42..d2d025b 100644
--- a/Source/JavaScriptCore/runtime/Structure.h
+++ b/Source/JavaScriptCore/runtime/Structure.h
@@ -87,9 +87,9 @@
public:
static void dumpStatistics();
- JS_EXPORT_PRIVATE static Structure* addPropertyTransition(JSGlobalData&, Structure*, PropertyName, unsigned attributes, JSCell* specificValue, size_t& offset);
- JS_EXPORT_PRIVATE static Structure* addPropertyTransitionToExistingStructure(Structure*, PropertyName, unsigned attributes, JSCell* specificValue, size_t& offset);
- static Structure* removePropertyTransition(JSGlobalData&, Structure*, PropertyName, size_t& offset);
+ JS_EXPORT_PRIVATE static Structure* addPropertyTransition(JSGlobalData&, Structure*, PropertyName, unsigned attributes, JSCell* specificValue, PropertyOffset&);
+ JS_EXPORT_PRIVATE static Structure* addPropertyTransitionToExistingStructure(Structure*, PropertyName, unsigned attributes, JSCell* specificValue, PropertyOffset&);
+ static Structure* removePropertyTransition(JSGlobalData&, Structure*, PropertyName, PropertyOffset&);
JS_EXPORT_PRIVATE static Structure* changePrototypeTransition(JSGlobalData&, Structure*, JSValue prototype);
JS_EXPORT_PRIVATE static Structure* despecifyFunctionTransition(JSGlobalData&, Structure*, PropertyName);
static Structure* attributeChangeTransition(JSGlobalData&, Structure*, PropertyName, unsigned attributes);
@@ -103,32 +103,32 @@
bool isFrozen(JSGlobalData&);
bool isExtensible() const { return !m_preventExtensions; }
bool didTransition() const { return m_didTransition; }
- bool putWillGrowPropertyStorage()
+ bool putWillGrowOutOfLineStorage()
{
- ASSERT(propertyStorageCapacity() >= propertyStorageSize());
+ ASSERT(outOfLineCapacity() >= outOfLineSize());
if (!m_propertyTable) {
- unsigned currentSize = static_cast<unsigned>(m_offset + 1);
- ASSERT(propertyStorageCapacity() >= currentSize);
- return currentSize == propertyStorageCapacity();
+ unsigned currentSize = numberOfOutOfLineSlotsForLastOffset(m_offset);
+ ASSERT(outOfLineCapacity() >= currentSize);
+ return currentSize == outOfLineCapacity();
}
- ASSERT(propertyStorageCapacity() >= m_propertyTable->propertyStorageSize());
+ ASSERT(totalStorageCapacity() >= m_propertyTable->propertyStorageSize());
if (m_propertyTable->hasDeletedOffset())
return false;
- ASSERT(propertyStorageCapacity() >= m_propertyTable->size());
- return m_propertyTable->size() == propertyStorageCapacity();
+ ASSERT(totalStorageCapacity() >= m_propertyTable->size());
+ return m_propertyTable->size() == totalStorageCapacity();
}
- JS_EXPORT_PRIVATE size_t suggestedNewPropertyStorageSize();
+ JS_EXPORT_PRIVATE size_t suggestedNewOutOfLineStorageCapacity();
Structure* flattenDictionaryStructure(JSGlobalData&, JSObject*);
static void destroy(JSCell*);
// These should be used with caution.
- JS_EXPORT_PRIVATE size_t addPropertyWithoutTransition(JSGlobalData&, PropertyName, unsigned attributes, JSCell* specificValue);
- size_t removePropertyWithoutTransition(JSGlobalData&, PropertyName);
+ JS_EXPORT_PRIVATE PropertyOffset addPropertyWithoutTransition(JSGlobalData&, PropertyName, unsigned attributes, JSCell* specificValue);
+ PropertyOffset removePropertyWithoutTransition(JSGlobalData&, PropertyName);
void setPrototypeWithoutTransition(JSGlobalData& globalData, JSValue prototype) { m_prototype.set(globalData, this, prototype); }
bool isDictionary() const { return m_dictionaryKind != NoneDictionaryKind; }
@@ -149,18 +149,114 @@
StructureChain* prototypeChain(ExecState*) const;
static void visitChildren(JSCell*, SlotVisitor&);
- Structure* previousID() const { ASSERT(structure()->classInfo() == &s_info); return m_previous.get(); }
+ Structure* previousID() const
+ {
+ ASSERT(structure()->classInfo() == &s_info);
+ return m_previous.get();
+ }
bool transitivelyTransitionedFrom(Structure* structureToFind);
- void growPropertyStorageCapacity();
- unsigned propertyStorageCapacity() const { ASSERT(structure()->classInfo() == &s_info); return m_propertyStorageCapacity; }
- unsigned propertyStorageSize() const { ASSERT(structure()->classInfo() == &s_info); return (m_propertyTable ? m_propertyTable->propertyStorageSize() : static_cast<unsigned>(m_offset + 1)); }
- size_t inlineStorageCapacity() const;
- bool isUsingInlineStorage() const;
+ void growOutOfLineCapacity();
+ unsigned outOfLineCapacity() const
+ {
+ ASSERT(structure()->classInfo() == &s_info);
+ return m_outOfLineCapacity;
+ }
+ unsigned outOfLineSizeForKnownFinalObject() const
+ {
+ ASSERT(m_typeInfo.type() == FinalObjectType);
+ if (m_propertyTable) {
+ unsigned totalSize = m_propertyTable->propertyStorageSize();
+ if (totalSize < static_cast<unsigned>(inlineStorageCapacity))
+ return 0;
+ return totalSize - inlineStorageCapacity;
+ }
+ return numberOfOutOfLineSlotsForLastOffset(m_offset);
+ }
+ unsigned outOfLineSizeForKnownNonFinalObject() const
+ {
+ ASSERT(m_typeInfo.type() != FinalObjectType);
+ if (m_propertyTable)
+ return m_propertyTable->propertyStorageSize();
+ return numberOfOutOfLineSlotsForLastOffset(m_offset);
+ }
+ unsigned outOfLineSize() const
+ {
+ ASSERT(structure()->classInfo() == &s_info);
+ if (m_propertyTable) {
+ unsigned totalSize = m_propertyTable->propertyStorageSize();
+ unsigned inlineCapacity = this->inlineCapacity();
+ if (totalSize < inlineCapacity)
+ return 0;
+ return totalSize - inlineCapacity;
+ }
+ return numberOfOutOfLineSlotsForLastOffset(m_offset);
+ }
+ bool hasInlineStorage() const
+ {
+ return m_typeInfo.type() == FinalObjectType;
+ }
+ unsigned inlineCapacity() const
+ {
+ if (hasInlineStorage())
+ return inlineStorageCapacity;
+ return 0;
+ }
+ unsigned inlineSizeForKnownFinalObject() const
+ {
+ ASSERT(m_typeInfo.type() == FinalObjectType);
+ unsigned result;
+ if (m_propertyTable)
+ result = m_propertyTable->propertyStorageSize();
+ else
+ result = m_offset + 1;
+ if (result > static_cast<unsigned>(inlineStorageCapacity))
+ return inlineStorageCapacity;
+ return result;
+ }
+ unsigned inlineSize() const
+ {
+ if (!hasInlineStorage())
+ return 0;
+ return inlineSizeForKnownFinalObject();
+ }
+ unsigned totalStorageSize() const
+ {
+ if (m_propertyTable)
+ return m_propertyTable->propertyStorageSize();
+ return numberOfSlotsForLastOffset(m_offset, m_typeInfo.type());
+ }
+ unsigned totalStorageCapacity() const
+ {
+ ASSERT(structure()->classInfo() == &s_info);
+ return m_outOfLineCapacity + inlineCapacity();
+ }
- size_t get(JSGlobalData&, PropertyName);
- size_t get(JSGlobalData&, const UString& name);
- JS_EXPORT_PRIVATE size_t get(JSGlobalData&, PropertyName, unsigned& attributes, JSCell*& specificValue);
+ PropertyOffset firstValidOffset() const
+ {
+ if (hasInlineStorage())
+ return 0;
+ return inlineStorageCapacity;
+ }
+ PropertyOffset lastValidOffset() const
+ {
+ if (m_propertyTable) {
+ PropertyOffset size = m_propertyTable->propertyStorageSize();
+ if (!hasInlineStorage())
+ size += inlineStorageCapacity;
+ return size - 1;
+ }
+ return m_offset;
+ }
+ bool isValidOffset(PropertyOffset offset) const
+ {
+ return offset >= firstValidOffset()
+ && offset <= lastValidOffset();
+ }
+
+ PropertyOffset get(JSGlobalData&, PropertyName);
+ PropertyOffset get(JSGlobalData&, const UString& name);
+ JS_EXPORT_PRIVATE PropertyOffset get(JSGlobalData&, PropertyName, unsigned& attributes, JSCell*& specificValue);
bool hasGetterSetterProperties() const { return m_hasGetterSetterProperties; }
bool hasReadOnlyOrGetterSetterPropertiesExcludingProto() const { return m_hasReadOnlyOrGetterSetterPropertiesExcludingProto; }
@@ -177,7 +273,12 @@
bool hasNonEnumerableProperties() const { return m_hasNonEnumerableProperties; }
- bool isEmpty() const { return m_propertyTable ? m_propertyTable->isEmpty() : m_offset == noOffset; }
+ bool isEmpty() const
+ {
+ if (m_propertyTable)
+ return m_propertyTable->isEmpty();
+ return !JSC::isValidOffset(m_offset);
+ }
JS_EXPORT_PRIVATE void despecifyDictionaryFunction(JSGlobalData&, PropertyName);
void disableSpecificFunctionTracking() { m_specificFunctionThrashCount = maxSpecificFunctionThrashCount; }
@@ -273,8 +374,8 @@
} DictionaryKind;
static Structure* toDictionaryTransition(JSGlobalData&, Structure*, DictionaryKind);
- size_t putSpecificValue(JSGlobalData&, PropertyName, unsigned attributes, JSCell* specificValue);
- size_t remove(PropertyName);
+ PropertyOffset putSpecificValue(JSGlobalData&, PropertyName, unsigned attributes, JSCell* specificValue);
+ PropertyOffset remove(PropertyName);
void createPropertyMap(unsigned keyCount = 0);
void checkConsistency();
@@ -301,7 +402,7 @@
int transitionCount() const
{
// Since the number of transitions is always the same as m_offset, we keep the size of Structure down by not storing both.
- return m_offset == noOffset ? 0 : m_offset + 1;
+ return numberOfSlotsForLastOffset(m_offset, m_typeInfo.type());
}
bool isValid(ExecState*, StructureChain* cachedPrototypeChain) const;
@@ -310,8 +411,6 @@
static const int s_maxTransitionLength = 64;
- static const int noOffset = -1;
-
static const unsigned maxSpecificFunctionThrashCount = 3;
TypeInfo m_typeInfo;
@@ -336,10 +435,10 @@
mutable InlineWatchpointSet m_transitionWatchpointSet;
- uint32_t m_propertyStorageCapacity;
+ uint32_t m_outOfLineCapacity;
// m_offset does not account for anonymous slots
- int m_offset;
+ PropertyOffset m_offset;
unsigned m_dictionaryKind : 2;
bool m_isPinnedPropertyTable : 1;
@@ -353,26 +452,26 @@
unsigned m_staticFunctionReified;
};
- inline size_t Structure::get(JSGlobalData& globalData, PropertyName propertyName)
+ inline PropertyOffset Structure::get(JSGlobalData& globalData, PropertyName propertyName)
{
ASSERT(structure()->classInfo() == &s_info);
materializePropertyMapIfNecessary(globalData);
if (!m_propertyTable)
- return notFound;
+ return invalidOffset;
PropertyMapEntry* entry = m_propertyTable->find(propertyName.uid()).first;
- return entry ? entry->offset : notFound;
+ return entry ? entry->offset : invalidOffset;
}
- inline size_t Structure::get(JSGlobalData& globalData, const UString& name)
+ inline PropertyOffset Structure::get(JSGlobalData& globalData, const UString& name)
{
ASSERT(structure()->classInfo() == &s_info);
materializePropertyMapIfNecessary(globalData);
if (!m_propertyTable)
- return notFound;
+ return invalidOffset;
PropertyMapEntry* entry = m_propertyTable->findWithString(name.impl()).first;
- return entry ? entry->offset : notFound;
+ return entry ? entry->offset : invalidOffset;
}
inline JSValue JSValue::structureOrUndefined() const