Commit b9aa7ba0 authored by fpizlo@apple.com's avatar fpizlo@apple.com
Browse files

IndexingType should not have a bit for each type

https://bugs.webkit.org/show_bug.cgi?id=98997

Reviewed by Oliver Hunt.

Somewhat incidentally, the introduction of butterflies led to each indexing
type being represented by a unique bit. This is superficially nice since it
allows you to test if a structure corresponds to a particular indexing type
by saying !!(structure->indexingType() & TheType). But the downside is that
given the 8 bits we have for the m_indexingType field, that leaves only a
small number of possible indexing types if we have one per bit.
        
This changeset changes the indexing type to be:
        
Bit #1: Tells you if you're an array.
        
Bits #2 - #5: 16 possible indexing types, including the blank type for
    objects that don't have indexed properties.
        
Bits #6-8: Auxiliary bits that we could use for other things. Currently we
    just use one of those bits, for MayHaveIndexedAccessors.
        
This is performance-neutral, and is primarily intended to give us more
breathing room for introducing new inferred array modes.

* assembler/AbstractMacroAssembler.h:
(JSC::AbstractMacroAssembler::JumpList::jumps):
* assembler/MacroAssembler.h:
(MacroAssembler):
(JSC::MacroAssembler::patchableBranch32):
* assembler/MacroAssemblerARMv7.h:
(JSC::MacroAssemblerARMv7::patchableBranch32):
(MacroAssemblerARMv7):
* dfg/DFGArrayMode.cpp:
(JSC::DFG::modeAlreadyChecked):
* dfg/DFGRepatch.cpp:
(JSC::DFG::tryCacheGetByID):
* dfg/DFGSpeculativeJIT.cpp:
(JSC::DFG::SpeculativeJIT::speculationCheck):
(JSC::DFG::SpeculativeJIT::forwardSpeculationCheck):
(JSC::DFG::SpeculativeJIT::jumpSlowForUnwantedArrayMode):
(DFG):
(JSC::DFG::SpeculativeJIT::checkArray):
(JSC::DFG::SpeculativeJIT::arrayify):
* dfg/DFGSpeculativeJIT.h:
(SpeculativeJIT):
* dfg/DFGSpeculativeJIT32_64.cpp:
(JSC::DFG::SpeculativeJIT::compile):
* dfg/DFGSpeculativeJIT64.cpp:
(JSC::DFG::SpeculativeJIT::compile):
* jit/JITInlineMethods.h:
(JSC::JIT::emitAllocateJSArray):
(JSC::JIT::chooseArrayMode):
* jit/JITPropertyAccess.cpp:
(JSC::JIT::emit_op_get_by_val):
(JSC::JIT::emitContiguousGetByVal):
(JSC::JIT::emitArrayStorageGetByVal):
(JSC::JIT::emit_op_put_by_val):
(JSC::JIT::emitContiguousPutByVal):
(JSC::JIT::emitArrayStoragePutByVal):
(JSC::JIT::privateCompilePatchGetArrayLength):
* jit/JITPropertyAccess32_64.cpp:
(JSC::JIT::emit_op_get_by_val):
(JSC::JIT::emitContiguousGetByVal):
(JSC::JIT::emitArrayStorageGetByVal):
(JSC::JIT::emit_op_put_by_val):
(JSC::JIT::emitContiguousPutByVal):
(JSC::JIT::emitArrayStoragePutByVal):
(JSC::JIT::privateCompilePatchGetArrayLength):
* llint/LowLevelInterpreter.asm:
* llint/LowLevelInterpreter32_64.asm:
* llint/LowLevelInterpreter64.asm:
* runtime/IndexingType.h:
(JSC):
(JSC::hasIndexedProperties):
(JSC::hasContiguous):
(JSC::hasFastArrayStorage):
(JSC::hasArrayStorage):
(JSC::shouldUseSlowPut):
* runtime/JSGlobalObject.cpp:
(JSC):
* runtime/StructureTransitionTable.h:
(JSC::newIndexingType):



git-svn-id: http://svn.webkit.org/repository/webkit/trunk@131276 268f45cc-cd09-0410-ab3c-d52691b4dbfc
parent 1a6cf377
2012-10-13 Filip Pizlo <fpizlo@apple.com>
IndexingType should not have a bit for each type
https://bugs.webkit.org/show_bug.cgi?id=98997
Reviewed by Oliver Hunt.
Somewhat incidentally, the introduction of butterflies led to each indexing
type being represented by a unique bit. This is superficially nice since it
allows you to test if a structure corresponds to a particular indexing type
by saying !!(structure->indexingType() & TheType). But the downside is that
given the 8 bits we have for the m_indexingType field, that leaves only a
small number of possible indexing types if we have one per bit.
This changeset changes the indexing type to be:
Bit #1: Tells you if you're an array.
Bits #2 - #5: 16 possible indexing types, including the blank type for
objects that don't have indexed properties.
Bits #6-8: Auxiliary bits that we could use for other things. Currently we
just use one of those bits, for MayHaveIndexedAccessors.
This is performance-neutral, and is primarily intended to give us more
breathing room for introducing new inferred array modes.
* assembler/AbstractMacroAssembler.h:
(JSC::AbstractMacroAssembler::JumpList::jumps):
* assembler/MacroAssembler.h:
(MacroAssembler):
(JSC::MacroAssembler::patchableBranch32):
* assembler/MacroAssemblerARMv7.h:
(JSC::MacroAssemblerARMv7::patchableBranch32):
(MacroAssemblerARMv7):
* dfg/DFGArrayMode.cpp:
(JSC::DFG::modeAlreadyChecked):
* dfg/DFGRepatch.cpp:
(JSC::DFG::tryCacheGetByID):
* dfg/DFGSpeculativeJIT.cpp:
(JSC::DFG::SpeculativeJIT::speculationCheck):
(JSC::DFG::SpeculativeJIT::forwardSpeculationCheck):
(JSC::DFG::SpeculativeJIT::jumpSlowForUnwantedArrayMode):
(DFG):
(JSC::DFG::SpeculativeJIT::checkArray):
(JSC::DFG::SpeculativeJIT::arrayify):
* dfg/DFGSpeculativeJIT.h:
(SpeculativeJIT):
* dfg/DFGSpeculativeJIT32_64.cpp:
(JSC::DFG::SpeculativeJIT::compile):
* dfg/DFGSpeculativeJIT64.cpp:
(JSC::DFG::SpeculativeJIT::compile):
* jit/JITInlineMethods.h:
(JSC::JIT::emitAllocateJSArray):
(JSC::JIT::chooseArrayMode):
* jit/JITPropertyAccess.cpp:
(JSC::JIT::emit_op_get_by_val):
(JSC::JIT::emitContiguousGetByVal):
(JSC::JIT::emitArrayStorageGetByVal):
(JSC::JIT::emit_op_put_by_val):
(JSC::JIT::emitContiguousPutByVal):
(JSC::JIT::emitArrayStoragePutByVal):
(JSC::JIT::privateCompilePatchGetArrayLength):
* jit/JITPropertyAccess32_64.cpp:
(JSC::JIT::emit_op_get_by_val):
(JSC::JIT::emitContiguousGetByVal):
(JSC::JIT::emitArrayStorageGetByVal):
(JSC::JIT::emit_op_put_by_val):
(JSC::JIT::emitContiguousPutByVal):
(JSC::JIT::emitArrayStoragePutByVal):
(JSC::JIT::privateCompilePatchGetArrayLength):
* llint/LowLevelInterpreter.asm:
* llint/LowLevelInterpreter32_64.asm:
* llint/LowLevelInterpreter64.asm:
* runtime/IndexingType.h:
(JSC):
(JSC::hasIndexedProperties):
(JSC::hasContiguous):
(JSC::hasFastArrayStorage):
(JSC::hasArrayStorage):
(JSC::shouldUseSlowPut):
* runtime/JSGlobalObject.cpp:
(JSC):
* runtime/StructureTransitionTable.h:
(JSC::newIndexingType):
2012-10-14 Filip Pizlo <fpizlo@apple.com>
DFG structure check hoisting should attempt to ignore side effects and make transformations that are sound even in their presence
......
......@@ -579,7 +579,7 @@ public:
m_jumps.clear();
}
const JumpVector& jumps() { return m_jumps; }
const JumpVector& jumps() const { return m_jumps; }
private:
JumpVector m_jumps;
......
......@@ -253,6 +253,11 @@ public:
{
return PatchableJump(branchTest32(cond, reg, mask));
}
PatchableJump patchableBranch32(RelationalCondition cond, RegisterID reg, TrustedImm32 imm)
{
return PatchableJump(branch32(cond, reg, imm));
}
#endif
void jump(Label target)
......
......@@ -1701,6 +1701,14 @@ public:
return PatchableJump(result);
}
PatchableJump patchableBranch32(RelationalCondition cond, RegisterID reg, TrustedImm32 imm)
{
m_makeJumpPatchable = true;
Jump result = branch32(cond, reg, imm);
m_makeJumpPatchable = false;
return PatchableJump(result);
}
PatchableJump patchableBranchPtrWithPatch(RelationalCondition cond, Address left, DataLabelPtr& dataLabel, TrustedImmPtr initialRightValue = TrustedImmPtr(0))
{
m_makeJumpPatchable = true;
......
......@@ -171,13 +171,13 @@ bool modeAlreadyChecked(AbstractValue& value, Array::Mode arrayMode)
case Array::PossiblyArrayWithContiguousToTail:
case Array::PossiblyArrayWithContiguousOutOfBounds:
return value.m_currentKnownStructure.hasSingleton()
&& (value.m_currentKnownStructure.singleton()->indexingType() & HasContiguous);
&& hasContiguous(value.m_currentKnownStructure.singleton()->indexingType());
case Array::ArrayWithContiguous:
case Array::ArrayWithContiguousToTail:
case Array::ArrayWithContiguousOutOfBounds:
return value.m_currentKnownStructure.hasSingleton()
&& (value.m_currentKnownStructure.singleton()->indexingType() & HasContiguous)
&& hasContiguous(value.m_currentKnownStructure.singleton()->indexingType())
&& (value.m_currentKnownStructure.singleton()->indexingType() & IsArray);
case Array::ArrayStorage:
......@@ -187,23 +187,23 @@ bool modeAlreadyChecked(AbstractValue& value, Array::Mode arrayMode)
case Array::PossiblyArrayWithArrayStorageToHole:
case Array::PossiblyArrayWithArrayStorageOutOfBounds:
return value.m_currentKnownStructure.hasSingleton()
&& (value.m_currentKnownStructure.singleton()->indexingType() & HasArrayStorage);
&& hasFastArrayStorage(value.m_currentKnownStructure.singleton()->indexingType());
case Array::SlowPutArrayStorage:
case Array::PossiblyArrayWithSlowPutArrayStorage:
return value.m_currentKnownStructure.hasSingleton()
&& (value.m_currentKnownStructure.singleton()->indexingType() & (HasArrayStorage | HasSlowPutArrayStorage));
&& hasArrayStorage(value.m_currentKnownStructure.singleton()->indexingType());
case Array::ArrayWithArrayStorage:
case Array::ArrayWithArrayStorageToHole:
case Array::ArrayWithArrayStorageOutOfBounds:
return value.m_currentKnownStructure.hasSingleton()
&& (value.m_currentKnownStructure.singleton()->indexingType() & HasArrayStorage)
&& hasFastArrayStorage(value.m_currentKnownStructure.singleton()->indexingType())
&& (value.m_currentKnownStructure.singleton()->indexingType() & IsArray);
case Array::ArrayWithSlowPutArrayStorage:
return value.m_currentKnownStructure.hasSingleton()
&& (value.m_currentKnownStructure.singleton()->indexingType() & (HasArrayStorage | HasSlowPutArrayStorage))
&& hasArrayStorage(value.m_currentKnownStructure.singleton()->indexingType())
&& (value.m_currentKnownStructure.singleton()->indexingType() & IsArray);
case ALL_EFFECTFUL_MODES:
......
......@@ -256,7 +256,7 @@ static bool tryCacheGetByID(ExecState* exec, JSValue baseValue, const Identifier
stubJit.loadPtr(MacroAssembler::Address(baseGPR, JSCell::structureOffset()), scratchGPR);
stubJit.load8(MacroAssembler::Address(scratchGPR, Structure::indexingTypeOffset()), scratchGPR);
failureCases.append(stubJit.branchTest32(MacroAssembler::Zero, scratchGPR, MacroAssembler::TrustedImm32(IsArray)));
failureCases.append(stubJit.branchTest32(MacroAssembler::Zero, scratchGPR, MacroAssembler::TrustedImm32(HasArrayStorage | HasContiguous | HasSlowPutArrayStorage)));
failureCases.append(stubJit.branchTest32(MacroAssembler::Zero, scratchGPR, MacroAssembler::TrustedImm32(IndexingShapeMask)));
stubJit.loadPtr(MacroAssembler::Address(baseGPR, JSObject::butterflyOffset()), scratchGPR);
stubJit.load32(MacroAssembler::Address(scratchGPR, ArrayStorage::lengthOffset()), scratchGPR);
......
......@@ -102,7 +102,7 @@ void SpeculativeJIT::speculationCheck(ExitKind kind, JSValueSource jsValueSource
speculationCheck(kind, jsValueSource, nodeUse.index(), jumpToFail);
}
void SpeculativeJIT::speculationCheck(ExitKind kind, JSValueSource jsValueSource, NodeIndex nodeIndex, MacroAssembler::JumpList& jumpsToFail)
void SpeculativeJIT::speculationCheck(ExitKind kind, JSValueSource jsValueSource, NodeIndex nodeIndex, const MacroAssembler::JumpList& jumpsToFail)
{
ASSERT(at(m_compileIndex).canExit() || m_isCheckingArgumentTypes);
Vector<MacroAssembler::Jump, 16> jumpVector = jumpsToFail.jumps();
......@@ -110,7 +110,7 @@ void SpeculativeJIT::speculationCheck(ExitKind kind, JSValueSource jsValueSource
speculationCheck(kind, jsValueSource, nodeIndex, jumpVector[i]);
}
void SpeculativeJIT::speculationCheck(ExitKind kind, JSValueSource jsValueSource, Edge nodeUse, MacroAssembler::JumpList& jumpsToFail)
void SpeculativeJIT::speculationCheck(ExitKind kind, JSValueSource jsValueSource, Edge nodeUse, const MacroAssembler::JumpList& jumpsToFail)
{
ASSERT(at(m_compileIndex).canExit() || m_isCheckingArgumentTypes);
speculationCheck(kind, jsValueSource, nodeUse.index(), jumpsToFail);
......@@ -222,7 +222,7 @@ void SpeculativeJIT::forwardSpeculationCheck(ExitKind kind, JSValueSource jsValu
convertLastOSRExitToForward(valueRecovery);
}
void SpeculativeJIT::forwardSpeculationCheck(ExitKind kind, JSValueSource jsValueSource, NodeIndex nodeIndex, MacroAssembler::JumpList& jumpsToFail, const ValueRecovery& valueRecovery)
void SpeculativeJIT::forwardSpeculationCheck(ExitKind kind, JSValueSource jsValueSource, NodeIndex nodeIndex, const MacroAssembler::JumpList& jumpsToFail, const ValueRecovery& valueRecovery)
{
ASSERT(at(m_compileIndex).canExit() || m_isCheckingArgumentTypes);
Vector<MacroAssembler::Jump, 16> jumpVector = jumpsToFail.jumps();
......@@ -327,6 +327,77 @@ const TypedArrayDescriptor* SpeculativeJIT::typedArrayDescriptor(Array::Mode arr
}
}
JITCompiler::JumpList SpeculativeJIT::jumpSlowForUnwantedArrayMode(GPRReg tempGPR, Array::Mode arrayMode)
{
JITCompiler::JumpList result;
switch (arrayMode) {
case NON_ARRAY_CONTIGUOUS_MODES: {
m_jit.and32(TrustedImm32(IndexingShapeMask), tempGPR);
result.append(
m_jit.branch32(MacroAssembler::NotEqual, tempGPR, TrustedImm32(ContiguousShape)));
break;
}
case ARRAY_WITH_CONTIGUOUS_MODES: {
m_jit.and32(TrustedImm32(IsArray | IndexingShapeMask), tempGPR);
result.append(
m_jit.branch32(
MacroAssembler::NotEqual, tempGPR, TrustedImm32(IsArray | ContiguousShape)));
break;
}
case NON_ARRAY_ARRAY_STORAGE_MODES: {
m_jit.and32(TrustedImm32(IndexingShapeMask), tempGPR);
if (isSlowPutAccess(arrayMode)) {
m_jit.sub32(TrustedImm32(ArrayStorageShape), tempGPR);
result.append(
m_jit.branch32(
MacroAssembler::Above, tempGPR,
TrustedImm32(SlowPutArrayStorageShape - ArrayStorageShape)));
} else {
result.append(
m_jit.branch32(MacroAssembler::NotEqual, tempGPR, TrustedImm32(ArrayStorageShape)));
}
break;
}
case Array::ArrayWithArrayStorage:
case Array::ArrayWithArrayStorageToHole:
case Array::ArrayWithArrayStorageOutOfBounds: {
m_jit.and32(TrustedImm32(IsArray | IndexingShapeMask), tempGPR);
result.append(
m_jit.branch32(MacroAssembler::NotEqual, tempGPR, TrustedImm32(ArrayStorageShape)));
break;
}
case Array::ArrayWithSlowPutArrayStorage: {
result.append(
m_jit.branchTest32(
MacroAssembler::Zero, tempGPR, MacroAssembler::TrustedImm32(IsArray)));
m_jit.and32(TrustedImm32(IndexingShapeMask), tempGPR);
m_jit.sub32(TrustedImm32(ArrayStorageShape), tempGPR);
result.append(
m_jit.branch32(
MacroAssembler::Above, tempGPR,
TrustedImm32(SlowPutArrayStorageShape - ArrayStorageShape)));
break;
}
case POLYMORPHIC_MODES: {
if (modeIsJSArray(arrayMode)) {
result.append(
m_jit.branchTest32(
MacroAssembler::Zero, tempGPR, TrustedImm32(IsArray)));
}
result.append(
m_jit.branchTest32(
MacroAssembler::Zero, tempGPR, TrustedImm32(IndexingShapeMask)));
break;
}
default:
CRASH();
break;
}
return result;
}
void SpeculativeJIT::checkArray(Node& node)
{
ASSERT(modeIsSpecific(node.arrayMode()));
......@@ -347,97 +418,19 @@ void SpeculativeJIT::checkArray(Node& node)
case Array::String:
expectedClassInfo = &JSString::s_info;
break;
case NON_ARRAY_CONTIGUOUS_MODES: {
GPRTemporary temp(this);
m_jit.loadPtr(
MacroAssembler::Address(baseReg, JSCell::structureOffset()), temp.gpr());
speculationCheck(
Uncountable, JSValueRegs(), NoNode,
m_jit.branchTest8(
MacroAssembler::Zero,
MacroAssembler::Address(temp.gpr(), Structure::indexingTypeOffset()),
MacroAssembler::TrustedImm32(HasContiguous)));
noResult(m_compileIndex);
return;
}
case ARRAY_WITH_CONTIGUOUS_MODES: {
GPRTemporary temp(this);
GPRReg tempGPR = temp.gpr();
m_jit.loadPtr(
MacroAssembler::Address(baseReg, JSCell::structureOffset()), tempGPR);
m_jit.load8(MacroAssembler::Address(tempGPR, Structure::indexingTypeOffset()), tempGPR);
// FIXME: This can be turned into a single branch. But we currently have no evidence
// that doing so would be profitable, nor do I feel comfortable with the present test
// coverage for this code path.
speculationCheck(
Uncountable, JSValueRegs(), NoNode,
m_jit.branchTest32(
MacroAssembler::Zero, tempGPR, MacroAssembler::TrustedImm32(IsArray)));
speculationCheck(
Uncountable, JSValueRegs(), NoNode,
m_jit.branchTest32(
MacroAssembler::Zero, tempGPR, MacroAssembler::TrustedImm32(HasContiguous)));
noResult(m_compileIndex);
return;
}
case NON_ARRAY_ARRAY_STORAGE_MODES: {
GPRTemporary temp(this);
m_jit.loadPtr(
MacroAssembler::Address(baseReg, JSCell::structureOffset()), temp.gpr());
speculationCheck(
Uncountable, JSValueRegs(), NoNode,
m_jit.branchTest8(
MacroAssembler::Zero,
MacroAssembler::Address(temp.gpr(), Structure::indexingTypeOffset()),
MacroAssembler::TrustedImm32(
isSlowPutAccess(node.arrayMode()) ? (HasArrayStorage | HasSlowPutArrayStorage) : HasArrayStorage)));
noResult(m_compileIndex);
return;
}
case ARRAY_WITH_ARRAY_STORAGE_MODES: {
GPRTemporary temp(this);
GPRReg tempGPR = temp.gpr();
m_jit.loadPtr(
MacroAssembler::Address(baseReg, JSCell::structureOffset()), tempGPR);
m_jit.load8(MacroAssembler::Address(tempGPR, Structure::indexingTypeOffset()), tempGPR);
// FIXME: This can be turned into a single branch. But we currently have no evidence
// that doing so would be profitable, nor do I feel comfortable with the present test
// coverage for this code path.
speculationCheck(
Uncountable, JSValueRegs(), NoNode,
m_jit.branchTest32(
MacroAssembler::Zero, tempGPR, MacroAssembler::TrustedImm32(IsArray)));
speculationCheck(
Uncountable, JSValueRegs(), NoNode,
m_jit.branchTest32(
MacroAssembler::Zero, tempGPR, MacroAssembler::TrustedImm32(
isSlowPutAccess(node.arrayMode()) ? (HasArrayStorage | HasSlowPutArrayStorage) : HasArrayStorage)));
noResult(m_compileIndex);
return;
}
case NON_ARRAY_CONTIGUOUS_MODES:
case ARRAY_WITH_CONTIGUOUS_MODES:
case NON_ARRAY_ARRAY_STORAGE_MODES:
case ARRAY_WITH_ARRAY_STORAGE_MODES:
case POLYMORPHIC_MODES: {
GPRTemporary temp(this);
GPRReg tempGPR = temp.gpr();
m_jit.loadPtr(
MacroAssembler::Address(baseReg, JSCell::structureOffset()), tempGPR);
m_jit.load8(MacroAssembler::Address(tempGPR, Structure::indexingTypeOffset()), tempGPR);
// FIXME: This can be turned into a single branch. But we currently have no evidence
// that doing so would be profitable, nor do I feel comfortable with the present test
// coverage for this code path.
speculationCheck(
Uncountable, JSValueRegs(), NoNode,
m_jit.branchTest32(
MacroAssembler::Zero, tempGPR, MacroAssembler::TrustedImm32(IsArray)));
speculationCheck(
Uncountable, JSValueRegs(), NoNode,
m_jit.branchTest32(
MacroAssembler::Zero, tempGPR, MacroAssembler::TrustedImm32(
(polymorphicIncludesContiguous(node.arrayMode()) ? HasContiguous : 0)
| (polymorphicIncludesArrayStorage(node.arrayMode()) ? HasArrayStorage : 0))));
jumpSlowForUnwantedArrayMode(tempGPR, node.arrayMode()));
noResult(m_compileIndex);
return;
......@@ -484,24 +477,24 @@ void SpeculativeJIT::arrayify(Node& node)
GPRReg baseReg = base.gpr();
GPRReg propertyReg = property.gpr();
IndexingType desiredIndexingTypeMask;
Array::Mode desiredArrayMode;
switch (node.arrayMode()) {
case Array::BlankToContiguous:
desiredIndexingTypeMask = HasContiguous;
desiredArrayMode = Array::Contiguous;
break;
case Array::BlankToArrayStorage:
desiredIndexingTypeMask = HasArrayStorage;
desiredArrayMode = Array::ArrayStorage;
break;
case Array::BlankToSlowPutArrayStorage:
desiredIndexingTypeMask = HasArrayStorage | HasSlowPutArrayStorage;
desiredArrayMode = Array::SlowPutArrayStorage;
break;
case Array::BlankToContiguousOrArrayStorage:
desiredIndexingTypeMask = HasContiguous | HasArrayStorage;
desiredArrayMode = Array::ContiguousOrArrayStorage;
break;
default:
CRASH();
desiredIndexingTypeMask = 0;
desiredArrayMode = Array::Undecided;
break;
}
......@@ -512,19 +505,20 @@ void SpeculativeJIT::arrayify(Node& node)
m_jit.loadPtr(
MacroAssembler::Address(baseReg, JSCell::structureOffset()), structureGPR);
m_jit.load8(
MacroAssembler::Address(structureGPR, Structure::indexingTypeOffset()), tempGPR);
// We can skip all that comes next if we already have array storage.
MacroAssembler::Jump slowCase = m_jit.branchTest8(
MacroAssembler::Zero,
MacroAssembler::Address(structureGPR, Structure::indexingTypeOffset()),
MacroAssembler::TrustedImm32(desiredIndexingTypeMask));
MacroAssembler::JumpList slowCases =
jumpSlowForUnwantedArrayMode(tempGPR, desiredArrayMode);
m_jit.loadPtr(
MacroAssembler::Address(baseReg, JSObject::butterflyOffset()), tempGPR);
MacroAssembler::Jump done = m_jit.jump();
slowCase.link(&m_jit);
slowCases.link(&m_jit);
// If we're allegedly creating contiguous storage and the index is bogus, then
// just don't.
......@@ -568,17 +562,16 @@ void SpeculativeJIT::arrayify(Node& node)
// about a load.
m_jit.loadPtr(
MacroAssembler::Address(baseReg, JSCell::structureOffset()), structureGPR);
// Finally, check that we have the kind of array storage that we wanted to get.
// Note that this is a backwards speculation check, which will result in the
// bytecode operation corresponding to this arrayification being reexecuted.
// That's fine, since arrayification is not user-visible.
m_jit.load8(
MacroAssembler::Address(structureGPR, Structure::indexingTypeOffset()), structureGPR);
speculationCheck(
Uncountable, JSValueRegs(), NoNode,
m_jit.branchTest8(
MacroAssembler::Zero,
MacroAssembler::Address(structureGPR, Structure::indexingTypeOffset()),
MacroAssembler::TrustedImm32(desiredIndexingTypeMask)));
jumpSlowForUnwantedArrayMode(structureGPR, desiredArrayMode));
done.link(&m_jit);
storageResult(tempGPR, m_compileIndex);
......
......@@ -2336,8 +2336,8 @@ public:
void speculationCheck(ExitKind, JSValueSource, NodeIndex, MacroAssembler::Jump jumpToFail);
void speculationCheck(ExitKind, JSValueSource, Edge, MacroAssembler::Jump jumpToFail);
// Add a set of speculation checks without additional recovery.
void speculationCheck(ExitKind, JSValueSource, NodeIndex, MacroAssembler::JumpList& jumpsToFail);
void speculationCheck(ExitKind, JSValueSource, Edge, MacroAssembler::JumpList& jumpsToFail);
void speculationCheck(ExitKind, JSValueSource, NodeIndex, const MacroAssembler::JumpList& jumpsToFail);
void speculationCheck(ExitKind, JSValueSource, Edge, const MacroAssembler::JumpList& jumpsToFail);
// Add a speculation check with additional recovery.
void speculationCheck(ExitKind, JSValueSource, NodeIndex, MacroAssembler::Jump jumpToFail, const SpeculationRecovery&);
void speculationCheck(ExitKind, JSValueSource, Edge, MacroAssembler::Jump jumpToFail, const SpeculationRecovery&);
......@@ -2358,7 +2358,7 @@ public:
// Note: not specifying the valueRecovery argument (leaving it as ValueRecovery()) implies
// that you've ensured that there exists a MovHint prior to your use of forwardSpeculationCheck().
void forwardSpeculationCheck(ExitKind, JSValueSource, NodeIndex, MacroAssembler::Jump jumpToFail, const ValueRecovery& = ValueRecovery());
void forwardSpeculationCheck(ExitKind, JSValueSource, NodeIndex, MacroAssembler::JumpList& jumpsToFail, const ValueRecovery& = ValueRecovery());
void forwardSpeculationCheck(ExitKind, JSValueSource, NodeIndex, const MacroAssembler::JumpList& jumpsToFail, const ValueRecovery& = ValueRecovery());
void speculationCheckWithConditionalDirection(ExitKind, JSValueSource, NodeIndex, MacroAssembler::Jump jumpToFail, bool isForward);
// Called when we statically determine that a speculation will fail.
void terminateSpeculativeExecution(ExitKind, JSValueRegs, NodeIndex);
......@@ -2371,6 +2371,7 @@ public:
const TypedArrayDescriptor* typedArrayDescriptor(Array::Mode);
JITCompiler::JumpList jumpSlowForUnwantedArrayMode(GPRReg tempWithIndexingTypeReg, Array::Mode arrayMode);
void checkArray(Node&);
void arrayify(Node&);
......
......@@ -2805,12 +2805,13 @@ void SpeculativeJIT::compile(Node& node)
m_jit.loadPtr(MacroAssembler::Address(baseReg, JSCell::structureOffset()), resultTagReg);
m_jit.loadPtr(MacroAssembler::Address(baseReg, JSObject::butterflyOffset()), storageReg);
m_jit.load8(MacroAssembler::Address(resultTagReg, Structure::indexingTypeOffset()), resultTagReg);
m_jit.and32(TrustedImm32(IndexingShapeMask), resultTagReg);
if (polymorphicIncludesContiguous(node.arrayMode())) {
if (fallThrough.isSet()) {
doneCases.append(m_jit.jump());
fallThrough.link(&m_jit);
}
fallThrough = m_jit.branchTest32(MacroAssembler::Zero, resultTagReg, MacroAssembler::TrustedImm32(HasContiguous));
fallThrough = m_jit.branch32(MacroAssembler::NotEqual, resultTagReg, MacroAssembler::TrustedImm32(ContiguousShape));
slowCases.append(compileContiguousGetByVal(node, baseReg, propertyReg, storageReg, resultTagReg, resultPayloadReg));
}
if (polymorphicIncludesArrayStorage(node.arrayMode())) {
......@@ -2818,7 +2819,7 @@ void SpeculativeJIT::compile(Node& node)
doneCases.append(m_jit.jump());
fallThrough.link(&m_jit);
}
fallThrough = m_jit.branchTest32(MacroAssembler::Zero, resultTagReg, MacroAssembler::TrustedImm32(HasArrayStorage));
fallThrough = m_jit.branch32(MacroAssembler::NotEqual, resultTagReg, MacroAssembler::TrustedImm32(ArrayStorageShape));
slowCases.append(compileArrayStorageGetByVal(node, baseReg, propertyReg, storageReg, resultTagReg, resultPayloadReg));
}
ASSERT(fallThrough.isSet());
......@@ -3040,12 +3041,13 @@ void SpeculativeJIT::compile(Node& node)
MacroAssembler::Jump fallThrough;
m_jit.loadPtr(MacroAssembler::Address(baseReg, JSCell::structureOffset()), storageReg);
m_jit.load8(MacroAssembler::Address(storageReg, Structure::indexingTypeOffset()), storageReg);
m_jit.and32(TrustedImm32(IndexingShapeMask), storageReg);
if (polymorphicIncludesContiguous(node.arrayMode())) {
if (fallThrough.isSet()) {
doneCases.append(m_jit.jump());
fallThrough.link(&m_jit);
}
fallThrough = m_jit.branchTest32(MacroAssembler::Zero, storageReg, MacroAssembler::TrustedImm32(HasContiguous));
fallThrough = m_jit.branch32(MacroAssembler::NotEqual, storageReg, MacroAssembler::TrustedImm32(ContiguousShape));
m_jit.loadPtr(MacroAssembler::Address(baseReg, JSObject::butterflyOffset()), storageReg);
slowCases.append(compileContiguousPutByVal(node, baseReg, propertyReg, storageReg, valueTagReg, valuePayloadReg));
}
......@@ -3054,7 +3056,7 @@ void SpeculativeJIT::compile(Node& node)
doneCases.append(m_jit.jump());
fallThrough.link(&m_jit);
}
fallThrough = m_jit.branchTest32(MacroAssembler::Zero, storageReg, MacroAssembler::TrustedImm32(HasArrayStorage));
fallThrough = m_jit.branch32(MacroAssembler::NotEqual, storageReg, MacroAssembler::TrustedImm32(ArrayStorageShape));
m_jit.loadPtr(MacroAssembler::Address(baseReg, JSObject::butterflyOffset()), storageReg);
slowCases.append(compileArrayStoragePutByVal(node, baseReg, propertyReg, storageReg, valueTagReg, valuePayloadReg));
}
......
......@@ -2809,12 +2809,13 @@ void SpeculativeJIT::compile(Node& node)
m_jit.loadPtr(MacroAssembler::Address(baseReg, JSCell::structureOffset()), resultReg);
m_jit.loadPtr(MacroAssembler::Address(baseReg, JSObject::butterflyOffset()), storageReg);
m_jit.load8(MacroAssembler::Address(resultReg, Structure::indexingTypeOffset()), resultReg);
m_jit.and32(TrustedImm32(IndexingShapeMask), resultReg);
if (polymorphicIncludesContiguous(node.arrayMode())) {
if (fallThrough.isSet()) {
doneCases.append(m_jit.jump());
fallThrough.link(&m_jit);
}
fallThrough = m_jit.branchTest32(MacroAssembler::Zero, resultReg, MacroAssembler::TrustedImm32(HasContiguous));
fallThrough = m_jit.branch32(MacroAssembler::NotEqual, resultReg, MacroAssembler::TrustedImm32(ContiguousShape));
slowCases.append(compileContiguousGetByVal(node, baseReg, propertyReg, storageReg, resultReg));
}
if (polymorphicIncludesArrayStorage(node.arrayMode())) {
......@@ -2822,7 +2823,7 @@ void SpeculativeJIT::compile(Node& node)
doneCases.append(m_jit.jump());
fallThrough.link(&m_jit);
}
fallThrough = m_jit.branchTest32(MacroAssembler::Zero, resultReg, MacroAssembler::TrustedImm32(HasArrayStorage));
fallThrough = m_jit.branch32(MacroAssembler::NotEqual, resultReg, MacroAssembler::TrustedImm32(ArrayStorageShape));
slowCases.append(compileArrayStorageGetByVal(node, baseReg, propertyReg, storageReg, resultReg));
}
ASSERT(fallThrough.isSet());
......@@ -3050,12 +3051,13 @@ void SpeculativeJIT::compile(Node& node)
m_jit.loadPtr(MacroAssembler::Address(baseReg, JSCell::structureOffset()), temporaryReg);
m_jit.loadPtr(MacroAssembler::Address(baseReg, JSObject::butterflyOffset()), storageReg);
m_jit.load8(MacroAssembler::Address(temporaryReg, Structure::indexingTypeOffset()), temporaryReg);
m_jit.and32(TrustedImm32(IndexingShapeMask), temporaryReg);
if (polymorphicIncludesContiguous(node.arrayMode())) {
if (fallThrough.isSet()) {
doneCases.append(m_jit.jump());
fallThrough.link(&m_jit);
}