Diff
Modified: trunk/Source/_javascript_Core/ChangeLog (131981 => 131982)
--- trunk/Source/_javascript_Core/ChangeLog 2012-10-20 06:29:25 UTC (rev 131981)
+++ trunk/Source/_javascript_Core/ChangeLog 2012-10-20 06:53:04 UTC (rev 131982)
@@ -1,5 +1,57 @@
2012-10-19 Filip Pizlo <[email protected]>
+ DFG should have some facility for recognizing redundant CheckArrays and Arrayifies
+ https://bugs.webkit.org/show_bug.cgi?id=99287
+
+ Reviewed by Mark Hahnenberg.
+
+ Adds reasoning about indexing type sets (i.e. ArrayModes) to AbstractValue, which
+ then enables us to fold away CheckArray's and Arrayify's that are redundant.
+
+ * bytecode/ArrayProfile.cpp:
+ (JSC::arrayModesToString):
+ (JSC):
+ * bytecode/ArrayProfile.h:
+ (JSC):
+ (JSC::mergeArrayModes):
+ (JSC::arrayModesAlreadyChecked):
+ * bytecode/StructureSet.h:
+ (JSC::StructureSet::arrayModesFromStructures):
+ (StructureSet):
+ * dfg/DFGAbstractState.cpp:
+ (JSC::DFG::AbstractState::execute):
+ * dfg/DFGAbstractValue.h:
+ (JSC::DFG::AbstractValue::AbstractValue):
+ (JSC::DFG::AbstractValue::clear):
+ (JSC::DFG::AbstractValue::isClear):
+ (JSC::DFG::AbstractValue::makeTop):
+ (JSC::DFG::AbstractValue::clobberStructures):
+ (AbstractValue):
+ (JSC::DFG::AbstractValue::setMostSpecific):
+ (JSC::DFG::AbstractValue::set):
+ (JSC::DFG::AbstractValue::operator==):
+ (JSC::DFG::AbstractValue::merge):
+ (JSC::DFG::AbstractValue::filter):
+ (JSC::DFG::AbstractValue::filterArrayModes):
+ (JSC::DFG::AbstractValue::validate):
+ (JSC::DFG::AbstractValue::checkConsistency):
+ (JSC::DFG::AbstractValue::dump):
+ (JSC::DFG::AbstractValue::clobberArrayModes):
+ (JSC::DFG::AbstractValue::clobberArrayModesSlow):
+ (JSC::DFG::AbstractValue::setFuturePossibleStructure):
+ (JSC::DFG::AbstractValue::filterFuturePossibleStructure):
+ * dfg/DFGArrayMode.cpp:
+ (JSC::DFG::modeAlreadyChecked):
+ * dfg/DFGArrayMode.h:
+ (JSC::DFG::arrayModesFor):
+ (DFG):
+ * dfg/DFGConstantFoldingPhase.cpp:
+ (JSC::DFG::ConstantFoldingPhase::foldConstants):
+ * dfg/DFGSpeculativeJIT.cpp:
+ (JSC::DFG::SpeculativeJIT::arrayify):
+
+2012-10-19 Filip Pizlo <[email protected]>
+
Baseline JIT should not inline array allocations, to make them easier to instrument
https://bugs.webkit.org/show_bug.cgi?id=99905
Modified: trunk/Source/_javascript_Core/bytecode/ArrayProfile.cpp (131981 => 131982)
--- trunk/Source/_javascript_Core/bytecode/ArrayProfile.cpp 2012-10-20 06:29:25 UTC (rev 131981)
+++ trunk/Source/_javascript_Core/bytecode/ArrayProfile.cpp 2012-10-20 06:53:04 UTC (rev 131982)
@@ -26,8 +26,44 @@
#include "config.h"
#include "ArrayProfile.h"
+#include <wtf/StringExtras.h>
+
namespace JSC {
+const char* arrayModesToString(ArrayModes arrayModes)
+{
+ if (!arrayModes)
+ return "0:<empty>";
+
+ if (arrayModes == ALL_ARRAY_MODES)
+ return "TOP";
+
+ bool isNonArray = !!(arrayModes & NonArray);
+ bool isNonArrayWithContiguous = !!(arrayModes & NonArrayWithContiguous);
+ bool isNonArrayWithArrayStorage = !!(arrayModes & NonArrayWithArrayStorage);
+ bool isNonArrayWithSlowPutArrayStorage = !!(arrayModes & NonArrayWithSlowPutArrayStorage);
+ bool isArray = !!(arrayModes & ArrayClass);
+ bool isArrayWithContiguous = !!(arrayModes & ArrayWithContiguous);
+ bool isArrayWithArrayStorage = !!(arrayModes & ArrayWithArrayStorage);
+ bool isArrayWithSlowPutArrayStorage = !!(arrayModes & ArrayWithSlowPutArrayStorage);
+
+ static char result[256];
+ snprintf(
+ result, sizeof(result),
+ "%u:%s%s%s%s%s%s%s%s",
+ arrayModes,
+ isNonArray ? "NonArray" : "",
+ isNonArrayWithContiguous ? "NonArrayWithContiguous" : "",
+ isNonArrayWithArrayStorage ? " NonArrayWithArrayStorage" : "",
+ isNonArrayWithSlowPutArrayStorage ? "NonArrayWithSlowPutArrayStorage" : "",
+ isArray ? "ArrayClass" : "",
+ isArrayWithContiguous ? "ArrayWithContiguous" : "",
+ isArrayWithArrayStorage ? " ArrayWithArrayStorage" : "",
+ isArrayWithSlowPutArrayStorage ? "ArrayWithSlowPutArrayStorage" : "");
+
+ return result;
+}
+
void ArrayProfile::computeUpdatedPrediction(OperationInProgress operation)
{
if (m_lastSeenStructure) {
Modified: trunk/Source/_javascript_Core/bytecode/ArrayProfile.h (131981 => 131982)
--- trunk/Source/_javascript_Core/bytecode/ArrayProfile.h 2012-10-20 06:29:25 UTC (rev 131981)
+++ trunk/Source/_javascript_Core/bytecode/ArrayProfile.h 2012-10-20 06:53:04 UTC (rev 131982)
@@ -40,13 +40,44 @@
typedef unsigned ArrayModes;
#define asArrayModes(type) \
- (1 << static_cast<unsigned>(type))
+ (static_cast<unsigned>(1) << static_cast<unsigned>(type))
+#define ALL_NON_ARRAY_ARRAY_MODES \
+ (asArrayModes(NonArray) \
+ | asArrayModes(NonArrayWithContiguous) \
+ | asArrayModes(NonArrayWithArrayStorage) \
+ | asArrayModes(NonArrayWithSlowPutArrayStorage))
+
+#define ALL_ARRAY_ARRAY_MODES \
+ (asArrayModes(ArrayClass) \
+ | asArrayModes(ArrayWithContiguous) \
+ | asArrayModes(ArrayWithArrayStorage) \
+ | asArrayModes(ArrayWithSlowPutArrayStorage))
+
+#define ALL_ARRAY_MODES (ALL_NON_ARRAY_ARRAY_MODES | ALL_ARRAY_ARRAY_MODES)
+
inline ArrayModes arrayModeFromStructure(Structure* structure)
{
return asArrayModes(structure->indexingType());
}
+const char* arrayModesToString(ArrayModes);
+
+inline bool mergeArrayModes(ArrayModes& left, ArrayModes right)
+{
+ ArrayModes newModes = left | right;
+ if (newModes == left)
+ return false;
+ left = newModes;
+ return true;
+}
+
+// Checks if proven is a subset of expected.
+inline bool arrayModesAlreadyChecked(ArrayModes proven, ArrayModes expected)
+{
+ return (expected | proven) == expected;
+}
+
class ArrayProfile {
public:
ArrayProfile()
Modified: trunk/Source/_javascript_Core/bytecode/StructureSet.h (131981 => 131982)
--- trunk/Source/_javascript_Core/bytecode/StructureSet.h 2012-10-20 06:29:25 UTC (rev 131981)
+++ trunk/Source/_javascript_Core/bytecode/StructureSet.h 2012-10-20 06:53:04 UTC (rev 131982)
@@ -26,6 +26,7 @@
#ifndef StructureSet_h
#define StructureSet_h
+#include "ArrayProfile.h"
#include "SpeculatedType.h"
#include "Structure.h"
#include <stdio.h>
@@ -137,6 +138,16 @@
return result;
}
+ ArrayModes arrayModesFromStructures() const
+ {
+ ArrayModes result = 0;
+
+ for (size_t i = 0; i < m_structures.size(); ++i)
+ mergeArrayModes(result, asArrayModes(m_structures[i]->indexingType()));
+
+ return result;
+ }
+
bool operator==(const StructureSet& other) const
{
if (m_structures.size() != other.m_structures.size())
Modified: trunk/Source/_javascript_Core/dfg/DFGAbstractState.cpp (131981 => 131982)
--- trunk/Source/_javascript_Core/dfg/DFGAbstractState.cpp 2012-10-20 06:29:25 UTC (rev 131981)
+++ trunk/Source/_javascript_Core/dfg/DFGAbstractState.cpp 2012-10-20 06:53:04 UTC (rev 131982)
@@ -1420,9 +1420,15 @@
ASSERT_NOT_REACHED();
break;
}
+ forNode(node.child1()).filterArrayModes(arrayModesFor(node.arrayMode()));
break;
}
case Arrayify: {
+ if (modeAlreadyChecked(forNode(node.child1()), node.arrayMode())) {
+ m_foundConstants = true;
+ node.setCanExit(false);
+ break;
+ }
switch (node.arrayMode()) {
case ALL_EFFECTFUL_MODES:
node.setCanExit(true);
@@ -1431,9 +1437,10 @@
forNode(node.child2()).filter(SpecInt32);
forNode(nodeIndex).clear();
clobberStructures(indexInBlock);
+ forNode(node.child1()).filterArrayModes(arrayModesFor(node.arrayMode()));
break;
default:
- ASSERT_NOT_REACHED();
+ CRASH();
break;
}
break;
Modified: trunk/Source/_javascript_Core/dfg/DFGAbstractValue.h (131981 => 131982)
--- trunk/Source/_javascript_Core/dfg/DFGAbstractValue.h 2012-10-20 06:29:25 UTC (rev 131981)
+++ trunk/Source/_javascript_Core/dfg/DFGAbstractValue.h 2012-10-20 06:53:04 UTC (rev 131982)
@@ -30,6 +30,7 @@
#if ENABLE(DFG_JIT)
+#include "ArrayProfile.h"
#include "DFGStructureAbstractValue.h"
#include "JSCell.h"
#include "SpeculatedType.h"
@@ -40,12 +41,14 @@
struct AbstractValue {
AbstractValue()
: m_type(SpecNone)
+ , m_arrayModes(0)
{
}
void clear()
{
m_type = SpecNone;
+ m_arrayModes = 0;
m_currentKnownStructure.clear();
m_futurePossibleStructure.clear();
m_value = JSValue();
@@ -54,7 +57,7 @@
bool isClear() const
{
- bool result = m_type == SpecNone && m_currentKnownStructure.isClear() && m_futurePossibleStructure.isClear();
+ bool result = m_type == SpecNone && !m_arrayModes && m_currentKnownStructure.isClear() && m_futurePossibleStructure.isClear();
if (result)
ASSERT(!m_value);
return result;
@@ -63,6 +66,7 @@
void makeTop()
{
m_type = SpecTop;
+ m_arrayModes = ALL_ARRAY_MODES;
m_currentKnownStructure.makeTop();
m_futurePossibleStructure.makeTop();
m_value = JSValue();
@@ -71,13 +75,16 @@
void clobberStructures()
{
- if (m_type & SpecCell)
+ if (m_type & SpecCell) {
m_currentKnownStructure.makeTop();
- else
+ clobberArrayModes();
+ } else {
ASSERT(m_currentKnownStructure.isClear());
+ ASSERT(!m_arrayModes);
+ }
checkConsistency();
}
-
+
void clobberValue()
{
m_value = JSValue();
@@ -105,29 +112,17 @@
return result;
}
- void setFuturePossibleStructure(Structure* structure)
- {
- if (structure->transitionWatchpointSetIsStillValid())
- m_futurePossibleStructure = structure;
- else
- m_futurePossibleStructure.makeTop();
- }
-
- void filterFuturePossibleStructure(Structure* structure)
- {
- if (structure->transitionWatchpointSetIsStillValid())
- m_futurePossibleStructure.filter(StructureAbstractValue(structure));
- }
-
void setMostSpecific(JSValue value)
{
if (!!value && value.isCell()) {
Structure* structure = value.asCell()->structure();
m_currentKnownStructure = structure;
setFuturePossibleStructure(structure);
+ m_arrayModes = asArrayModes(structure->indexingType());
} else {
m_currentKnownStructure.clear();
m_futurePossibleStructure.clear();
+ m_arrayModes = 0;
}
m_type = speculationFromValue(value);
@@ -140,10 +135,14 @@
{
if (!!value && value.isCell()) {
m_currentKnownStructure.makeTop();
- setFuturePossibleStructure(value.asCell()->structure());
+ Structure* structure = value.asCell()->structure();
+ setFuturePossibleStructure(structure);
+ m_arrayModes = asArrayModes(structure->indexingType());
+ clobberArrayModes();
} else {
m_currentKnownStructure.clear();
m_futurePossibleStructure.clear();
+ m_arrayModes = 0;
}
m_type = speculationFromValue(value);
@@ -156,6 +155,7 @@
{
m_currentKnownStructure = structure;
setFuturePossibleStructure(structure);
+ m_arrayModes = asArrayModes(structure->indexingType());
m_type = speculationFromStructure(structure);
m_value = JSValue();
@@ -167,9 +167,11 @@
if (type & SpecCell) {
m_currentKnownStructure.makeTop();
m_futurePossibleStructure.makeTop();
+ m_arrayModes = ALL_ARRAY_MODES;
} else {
m_currentKnownStructure.clear();
m_futurePossibleStructure.clear();
+ m_arrayModes = 0;
}
m_type = type;
m_value = JSValue();
@@ -179,6 +181,7 @@
bool operator==(const AbstractValue& other) const
{
return m_type == other.m_type
+ && m_arrayModes == other.m_arrayModes
&& m_currentKnownStructure == other.m_currentKnownStructure
&& m_futurePossibleStructure == other.m_futurePossibleStructure
&& m_value == other.m_value;
@@ -199,6 +202,7 @@
result = !other.isClear();
} else {
result |= mergeSpeculation(m_type, other.m_type);
+ result |= mergeArrayModes(m_arrayModes, other.m_arrayModes);
result |= m_currentKnownStructure.addAll(other.m_currentKnownStructure);
result |= m_futurePossibleStructure.addAll(other.m_futurePossibleStructure);
if (m_value != other.m_value) {
@@ -218,6 +222,7 @@
if (type & SpecCell) {
m_currentKnownStructure.makeTop();
m_futurePossibleStructure.makeTop();
+ m_arrayModes = ALL_ARRAY_MODES;
}
m_value = JSValue();
@@ -227,6 +232,7 @@
void filter(const StructureSet& other)
{
m_type &= other.speculationFromStructures();
+ m_arrayModes &= other.arrayModesFromStructures();
m_currentKnownStructure.filter(other);
if (m_currentKnownStructure.isClear())
m_futurePossibleStructure.clear();
@@ -241,11 +247,24 @@
m_currentKnownStructure.filter(m_type);
m_futurePossibleStructure.filter(m_type);
+ filterArrayModesByType();
filterValueByType();
checkConsistency();
}
+ void filterArrayModes(ArrayModes arrayModes)
+ {
+ ASSERT(arrayModes);
+
+ m_type &= SpecCell;
+ m_arrayModes &= arrayModes;
+
+ // I could do more fancy filtering here. But it probably won't make any difference.
+
+ checkConsistency();
+ }
+
void filter(SpeculatedType type)
{
if (type == SpecTop)
@@ -258,31 +277,13 @@
// the new type (None) rather than the one passed (Array).
m_currentKnownStructure.filter(m_type);
m_futurePossibleStructure.filter(m_type);
-
+
+ filterArrayModesByType();
filterValueByType();
checkConsistency();
}
- // We could go further, and ensure that if the futurePossibleStructure contravenes
- // the value, then we could clear both of those things. But that's unlikely to help
- // in any realistic scenario, so we don't do it. Simpler is better.
- void filterValueByType()
- {
- if (!!m_type) {
- // The type is still non-empty. This implies that regardless of what filtering
- // was done, we either didn't have a value to begin with, or that value is still
- // valid.
- ASSERT(!m_value || validateType(m_value));
- return;
- }
-
- // The type has been rendered empty. That means that the value must now be invalid,
- // as well.
- ASSERT(!m_value || !validateType(m_value));
- m_value = JSValue();
- }
-
bool validateType(JSValue value) const
{
if (isTop())
@@ -319,7 +320,8 @@
ASSERT(m_type & SpecCell);
Structure* structure = value.asCell()->structure();
return m_currentKnownStructure.contains(structure)
- && m_futurePossibleStructure.contains(structure);
+ && m_futurePossibleStructure.contains(structure)
+ && (m_arrayModes & asArrayModes(structure->indexingType()));
}
return true;
@@ -330,6 +332,7 @@
if (!(m_type & SpecCell)) {
ASSERT(m_currentKnownStructure.isClear());
ASSERT(m_futurePossibleStructure.isClear());
+ ASSERT(!m_arrayModes);
}
if (isClear())
@@ -346,7 +349,7 @@
void dump(FILE* out) const
{
- fprintf(out, "(%s, ", speculationToString(m_type));
+ fprintf(out, "(%s, %s, ", speculationToString(m_type), arrayModesToString(m_arrayModes));
m_currentKnownStructure.dump(out);
dataLog(", ");
m_futurePossibleStructure.dump(out);
@@ -437,6 +440,13 @@
// unified with the set of all objects with structure 0x12345.
SpeculatedType m_type;
+ // This is a proven constraint on the possible indexing types that this value
+ // can have right now. It also implicitly constraints the set of structures
+ // that the value may have right now, since a structure has an immutable
+ // indexing type. This is subject to change upon reassignment, or any side
+ // effect that makes non-obvious changes to the heap.
+ ArrayModes m_arrayModes;
+
// This is a proven constraint on the possible values that this value can
// have now or any time in the future, unless it is reassigned. Note that this
// implies nothing about the structure. Oddly, JSValue() (i.e. the empty value)
@@ -444,6 +454,75 @@
// BOTTOM then JSValue() means BOTTOM; if m_type is not BOTTOM then JSValue()
// means TOP.
JSValue m_value;
+
+private:
+ void clobberArrayModes()
+ {
+ if (m_arrayModes == ALL_ARRAY_MODES)
+ return;
+
+ if (LIKELY(m_arrayModes & asArrayModes(NonArray)))
+ m_arrayModes = ALL_ARRAY_MODES;
+ else
+ clobberArrayModesSlow();
+ }
+
+ void clobberArrayModesSlow()
+ {
+ if (m_arrayModes & asArrayModes(ArrayClass))
+ m_arrayModes = ALL_ARRAY_MODES;
+ else if (m_arrayModes & asArrayModes(NonArrayWithContiguous))
+ m_arrayModes |= asArrayModes(NonArrayWithArrayStorage) | asArrayModes(NonArrayWithSlowPutArrayStorage);
+ else if (m_arrayModes & asArrayModes(ArrayWithContiguous))
+ m_arrayModes |= asArrayModes(ArrayWithArrayStorage) | asArrayModes(ArrayWithSlowPutArrayStorage);
+ else if (m_arrayModes & asArrayModes(NonArrayWithArrayStorage))
+ m_arrayModes |= asArrayModes(NonArrayWithSlowPutArrayStorage);
+ else if (m_arrayModes & asArrayModes(ArrayWithArrayStorage))
+ m_arrayModes |= asArrayModes(ArrayWithArrayStorage);
+ }
+
+ void setFuturePossibleStructure(Structure* structure)
+ {
+ if (structure->transitionWatchpointSetIsStillValid())
+ m_futurePossibleStructure = structure;
+ else
+ m_futurePossibleStructure.makeTop();
+ }
+
+ void filterFuturePossibleStructure(Structure* structure)
+ {
+ if (structure->transitionWatchpointSetIsStillValid())
+ m_futurePossibleStructure.filter(StructureAbstractValue(structure));
+ }
+
+ // We could go further, and ensure that if the futurePossibleStructure contravenes
+ // the value, then we could clear both of those things. But that's unlikely to help
+ // in any realistic scenario, so we don't do it. Simpler is better.
+ void filterValueByType()
+ {
+ if (!!m_type) {
+ // The type is still non-empty. This implies that regardless of what filtering
+ // was done, we either didn't have a value to begin with, or that value is still
+ // valid.
+ ASSERT(!m_value || validateType(m_value));
+ return;
+ }
+
+ // The type has been rendered empty. That means that the value must now be invalid,
+ // as well.
+ ASSERT(!m_value || !validateType(m_value));
+ m_value = JSValue();
+ }
+
+ void filterArrayModesByType()
+ {
+ if (!(m_type & SpecCell))
+ m_arrayModes = 0;
+ else if (!(m_type & ~SpecArray))
+ m_arrayModes &= ALL_ARRAY_ARRAY_MODES;
+ else if (!(m_type & SpecArray))
+ m_arrayModes &= ALL_NON_ARRAY_ARRAY_MODES;
+ }
};
} } // namespace JSC::DFG
Modified: trunk/Source/_javascript_Core/dfg/DFGArrayMode.cpp (131981 => 131982)
--- trunk/Source/_javascript_Core/dfg/DFGArrayMode.cpp 2012-10-20 06:29:25 UTC (rev 131981)
+++ trunk/Source/_javascript_Core/dfg/DFGArrayMode.cpp 2012-10-20 06:53:04 UTC (rev 131982)
@@ -167,12 +167,17 @@
case Array::PossiblyArrayWithContiguous:
case Array::PossiblyArrayWithContiguousToTail:
case Array::PossiblyArrayWithContiguousOutOfBounds:
+ case Array::ToContiguous:
+ if (arrayModesAlreadyChecked(value.m_arrayModes, asArrayModes(NonArrayWithContiguous) | asArrayModes(ArrayWithContiguous)))
+ return true;
return value.m_currentKnownStructure.hasSingleton()
&& hasContiguous(value.m_currentKnownStructure.singleton()->indexingType());
case Array::ArrayWithContiguous:
case Array::ArrayWithContiguousToTail:
case Array::ArrayWithContiguousOutOfBounds:
+ if (arrayModesAlreadyChecked(value.m_arrayModes, asArrayModes(ArrayWithContiguous)))
+ return true;
return value.m_currentKnownStructure.hasSingleton()
&& hasContiguous(value.m_currentKnownStructure.singleton()->indexingType())
&& (value.m_currentKnownStructure.singleton()->indexingType() & IsArray);
@@ -183,29 +188,38 @@
case Array::PossiblyArrayWithArrayStorage:
case Array::PossiblyArrayWithArrayStorageToHole:
case Array::PossiblyArrayWithArrayStorageOutOfBounds:
+ case Array::ToArrayStorage:
+ case Array::PossiblyArrayToArrayStorage:
+ if (arrayModesAlreadyChecked(value.m_arrayModes, asArrayModes(NonArrayWithArrayStorage) | asArrayModes(ArrayWithArrayStorage)))
+ return true;
return value.m_currentKnownStructure.hasSingleton()
&& hasFastArrayStorage(value.m_currentKnownStructure.singleton()->indexingType());
case Array::SlowPutArrayStorage:
case Array::PossiblyArrayWithSlowPutArrayStorage:
+ case Array::ToSlowPutArrayStorage:
+ if (arrayModesAlreadyChecked(value.m_arrayModes, asArrayModes(NonArrayWithArrayStorage) | asArrayModes(ArrayWithArrayStorage) | asArrayModes(NonArrayWithSlowPutArrayStorage) | asArrayModes(ArrayWithSlowPutArrayStorage)))
+ return true;
return value.m_currentKnownStructure.hasSingleton()
&& hasArrayStorage(value.m_currentKnownStructure.singleton()->indexingType());
case Array::ArrayWithArrayStorage:
case Array::ArrayWithArrayStorageToHole:
case Array::ArrayWithArrayStorageOutOfBounds:
+ case Array::ArrayToArrayStorage:
+ if (arrayModesAlreadyChecked(value.m_arrayModes, asArrayModes(ArrayWithArrayStorage)))
+ return true;
return value.m_currentKnownStructure.hasSingleton()
&& hasFastArrayStorage(value.m_currentKnownStructure.singleton()->indexingType())
&& (value.m_currentKnownStructure.singleton()->indexingType() & IsArray);
case Array::ArrayWithSlowPutArrayStorage:
+ if (arrayModesAlreadyChecked(value.m_arrayModes, asArrayModes(ArrayWithArrayStorage) | asArrayModes(ArrayWithSlowPutArrayStorage)))
+ return true;
return value.m_currentKnownStructure.hasSingleton()
&& hasArrayStorage(value.m_currentKnownStructure.singleton()->indexingType())
&& (value.m_currentKnownStructure.singleton()->indexingType() & IsArray);
- case ALL_EFFECTFUL_MODES:
- return false;
-
case Array::Arguments:
return isArgumentsSpeculation(value.m_type);
Modified: trunk/Source/_javascript_Core/dfg/DFGArrayMode.h (131981 => 131982)
--- trunk/Source/_javascript_Core/dfg/DFGArrayMode.h 2012-10-20 06:29:25 UTC (rev 131981)
+++ trunk/Source/_javascript_Core/dfg/DFGArrayMode.h 2012-10-20 06:53:04 UTC (rev 131982)
@@ -349,6 +349,51 @@
}
}
+// This returns the set of array modes that will pass filtering of a CheckArray or
+// Arrayify with the given mode.
+inline ArrayModes arrayModesFor(Array::Mode arrayMode)
+{
+ switch (arrayMode) {
+ case Array::Generic:
+ return ALL_ARRAY_MODES;
+ case Array::Contiguous:
+ case Array::ContiguousToTail:
+ case Array::ContiguousOutOfBounds:
+ case Array::ToContiguous:
+ return asArrayModes(NonArrayWithContiguous);
+ case Array::PossiblyArrayWithContiguous:
+ case Array::PossiblyArrayWithContiguousToTail:
+ case Array::PossiblyArrayWithContiguousOutOfBounds:
+ return asArrayModes(NonArrayWithContiguous) | asArrayModes(ArrayWithContiguous);
+ case ARRAY_WITH_CONTIGUOUS_MODES:
+ return asArrayModes(ArrayWithContiguous);
+ case Array::ArrayStorage:
+ case Array::ArrayStorageToHole:
+ case Array::ArrayStorageOutOfBounds:
+ case Array::ToArrayStorage:
+ return asArrayModes(NonArrayWithArrayStorage);
+ case Array::ToSlowPutArrayStorage:
+ case Array::SlowPutArrayStorage:
+ return asArrayModes(NonArrayWithArrayStorage) | asArrayModes(NonArrayWithSlowPutArrayStorage);
+ case Array::PossiblyArrayWithArrayStorage:
+ case Array::PossiblyArrayWithArrayStorageToHole:
+ case Array::PossiblyArrayWithArrayStorageOutOfBounds:
+ case Array::PossiblyArrayToArrayStorage:
+ return asArrayModes(NonArrayWithArrayStorage) | asArrayModes(ArrayWithArrayStorage);
+ case Array::PossiblyArrayWithSlowPutArrayStorage:
+ return asArrayModes(NonArrayWithArrayStorage) | asArrayModes(ArrayWithArrayStorage) | asArrayModes(NonArrayWithSlowPutArrayStorage) | asArrayModes(ArrayWithSlowPutArrayStorage);
+ case Array::ArrayWithArrayStorage:
+ case Array::ArrayWithArrayStorageToHole:
+ case Array::ArrayWithArrayStorageOutOfBounds:
+ case Array::ArrayToArrayStorage:
+ return asArrayModes(ArrayWithArrayStorage);
+ case Array::ArrayWithSlowPutArrayStorage:
+ return asArrayModes(ArrayWithArrayStorage) | asArrayModes(ArrayWithSlowPutArrayStorage);
+ default:
+ return asArrayModes(NonArray);
+ }
+}
+
} } // namespace JSC::DFG
#endif // ENABLE(DFG_JIT)
Modified: trunk/Source/_javascript_Core/dfg/DFGConstantFoldingPhase.cpp (131981 => 131982)
--- trunk/Source/_javascript_Core/dfg/DFGConstantFoldingPhase.cpp 2012-10-20 06:29:25 UTC (rev 131981)
+++ trunk/Source/_javascript_Core/dfg/DFGConstantFoldingPhase.cpp 2012-10-20 06:53:04 UTC (rev 131982)
@@ -102,7 +102,8 @@
break;
}
- case CheckArray: {
+ case CheckArray:
+ case Arrayify: {
if (!modeAlreadyChecked(m_state.forNode(node.child1()), node.arrayMode()))
break;
ASSERT(node.refCount() == 1);
Modified: trunk/Source/_javascript_Core/dfg/DFGSpeculativeJIT.cpp (131981 => 131982)
--- trunk/Source/_javascript_Core/dfg/DFGSpeculativeJIT.cpp 2012-10-20 06:29:25 UTC (rev 131981)
+++ trunk/Source/_javascript_Core/dfg/DFGSpeculativeJIT.cpp 2012-10-20 06:53:04 UTC (rev 131982)
@@ -579,10 +579,17 @@
void SpeculativeJIT::arrayify(Node& node)
{
ASSERT(modeIsSpecific(node.arrayMode()));
- ASSERT(!modeAlreadyChecked(m_state.forNode(node.child1()), node.arrayMode()));
SpeculateCellOperand base(this, node.child1());
+ if (modeAlreadyChecked(m_state.forNode(node.child1()), node.arrayMode())) {
+ GPRTemporary temp(this);
+ m_jit.loadPtr(
+ MacroAssembler::Address(base.gpr(), JSObject::butterflyOffset()), temp.gpr());
+ storageResult(temp.gpr(), m_compileIndex);
+ return;
+ }
+
if (!node.child2()) {
arrayify(node, base.gpr(), InvalidGPRReg);
return;