Diff
Modified: trunk/Source/_javascript_Core/ChangeLog (136371 => 136372)
--- trunk/Source/_javascript_Core/ChangeLog 2012-12-03 08:56:42 UTC (rev 136371)
+++ trunk/Source/_javascript_Core/ChangeLog 2012-12-03 09:21:22 UTC (rev 136372)
@@ -1,5 +1,61 @@
2012-12-02 Filip Pizlo <[email protected]>
+ DFG should trigger rage conversion from double to contiguous if it sees a GetByVal on Double being used in an integer context
+ https://bugs.webkit.org/show_bug.cgi?id=103858
+
+ Reviewed by Gavin Barraclough.
+
+ A rage conversion from double to contiguous is one where you try to convert each
+ double to an int32.
+
+ This is probably not the last we'll hear of rage conversion from double to contiguous.
+ It may be better to do this right during parsing, which will result in fewer cases of
+ Arrayification. But even so, this looks like a straight win already - 1% speed-up on
+ Kraken, no major regression anywhere else.
+
+ * dfg/DFGAbstractState.cpp:
+ (JSC::DFG::AbstractState::execute):
+ * dfg/DFGArrayMode.cpp:
+ (JSC::DFG::ArrayMode::refine):
+ (JSC::DFG::arrayConversionToString):
+ (JSC::DFG::ArrayMode::dump):
+ (WTF):
+ (WTF::printInternal):
+ * dfg/DFGArrayMode.h:
+ (JSC::DFG::ArrayMode::withConversion):
+ (ArrayMode):
+ (JSC::DFG::ArrayMode::doesConversion):
+ (WTF):
+ * dfg/DFGFixupPhase.cpp:
+ (JSC::DFG::FixupPhase::fixupBlock):
+ (JSC::DFG::FixupPhase::fixupNode):
+ (JSC::DFG::FixupPhase::checkArray):
+ (FixupPhase):
+ * dfg/DFGGraph.cpp:
+ (JSC::DFG::Graph::dump):
+ * dfg/DFGNodeFlags.h:
+ (DFG):
+ * dfg/DFGOperations.cpp:
+ * dfg/DFGOperations.h:
+ * dfg/DFGPredictionPropagationPhase.cpp:
+ (JSC::DFG::PredictionPropagationPhase::propagate):
+ * dfg/DFGSpeculativeJIT.cpp:
+ (JSC::DFG::SpeculativeJIT::arrayify):
+ * dfg/DFGStructureCheckHoistingPhase.cpp:
+ (JSC::DFG::StructureCheckHoistingPhase::run):
+ * runtime/JSObject.cpp:
+ (JSC):
+ (JSC::JSObject::genericConvertDoubleToContiguous):
+ (JSC::JSObject::convertDoubleToContiguous):
+ (JSC::JSObject::rageConvertDoubleToContiguous):
+ (JSC::JSObject::ensureContiguousSlow):
+ (JSC::JSObject::rageEnsureContiguousSlow):
+ * runtime/JSObject.h:
+ (JSObject):
+ (JSC::JSObject::rageEnsureContiguous):
+
+2012-12-02 Filip Pizlo <[email protected]>
+
DFG CSE should not keep alive things that aren't relevant to OSR
https://bugs.webkit.org/show_bug.cgi?id=103849
Modified: trunk/Source/_javascript_Core/dfg/DFGAbstractState.cpp (136371 => 136372)
--- trunk/Source/_javascript_Core/dfg/DFGAbstractState.cpp 2012-12-03 08:56:42 UTC (rev 136371)
+++ trunk/Source/_javascript_Core/dfg/DFGAbstractState.cpp 2012-12-03 09:21:22 UTC (rev 136372)
@@ -1562,7 +1562,8 @@
node.setCanExit(false);
break;
}
- ASSERT(node.arrayMode().conversion() == Array::Convert);
+ ASSERT(node.arrayMode().conversion() == Array::Convert
+ || node.arrayMode().conversion() == Array::RageConvert);
node.setCanExit(true);
forNode(node.child1()).filter(SpecCell);
if (node.child2())
Modified: trunk/Source/_javascript_Core/dfg/DFGArrayMode.cpp (136371 => 136372)
--- trunk/Source/_javascript_Core/dfg/DFGArrayMode.cpp 2012-12-03 08:56:42 UTC (rev 136371)
+++ trunk/Source/_javascript_Core/dfg/DFGArrayMode.cpp 2012-12-03 09:21:22 UTC (rev 136372)
@@ -122,7 +122,7 @@
}
}
-ArrayMode ArrayMode::refine(SpeculatedType base, SpeculatedType index, SpeculatedType value) const
+ArrayMode ArrayMode::refine(SpeculatedType base, SpeculatedType index, SpeculatedType value, NodeFlags flags) const
{
if (!base || !index) {
// It can be that we had a legitimate arrayMode but no incoming predictions. That'll
@@ -156,10 +156,17 @@
return withTypeAndConversion(Array::Contiguous, Array::Convert);
case Array::Double:
+ if (flags & NodeUsedAsIntLocally)
+ return withTypeAndConversion(Array::Contiguous, Array::RageConvert);
if (!value || isNumberSpeculation(value))
return *this;
return withTypeAndConversion(Array::Contiguous, Array::Convert);
+ case Array::Contiguous:
+ if (doesConversion() && (flags & NodeUsedAsIntLocally))
+ return withConversion(Array::RageConvert);
+ return *this;
+
case Array::SelectUsingPredictions:
if (isStringSpeculation(base))
return ArrayMode(Array::String);
@@ -429,19 +436,43 @@
return "AsIs";
case Array::Convert:
return "Convert";
+ case Array::RageConvert:
+ return "RageConvert";
default:
return "Unknown!";
}
}
-const char* ArrayMode::toString() const
+void ArrayMode::dump(PrintStream& out) const
{
- static char buffer[256];
- snprintf(buffer, sizeof(buffer), "%s%s%s%s", arrayTypeToString(type()), arrayClassToString(arrayClass()), arraySpeculationToString(speculation()), arrayConversionToString(conversion()));
- return buffer;
+ out.print(type(), arrayClass(), speculation(), conversion());
}
} } // namespace JSC::DFG
+namespace WTF {
+
+void printInternal(PrintStream& out, JSC::DFG::Array::Type type)
+{
+ out.print(JSC::DFG::arrayTypeToString(type));
+}
+
+void printInternal(PrintStream& out, JSC::DFG::Array::Class arrayClass)
+{
+ out.print(JSC::DFG::arrayClassToString(arrayClass));
+}
+
+void printInternal(PrintStream& out, JSC::DFG::Array::Speculation speculation)
+{
+ out.print(JSC::DFG::arraySpeculationToString(speculation));
+}
+
+void printInternal(PrintStream& out, JSC::DFG::Array::Conversion conversion)
+{
+ out.print(JSC::DFG::arrayConversionToString(conversion));
+}
+
+} // namespace WTF
+
#endif // ENABLE(DFG_JIT)
Modified: trunk/Source/_javascript_Core/dfg/DFGArrayMode.h (136371 => 136372)
--- trunk/Source/_javascript_Core/dfg/DFGArrayMode.h 2012-12-03 08:56:42 UTC (rev 136371)
+++ trunk/Source/_javascript_Core/dfg/DFGArrayMode.h 2012-12-03 09:21:22 UTC (rev 136372)
@@ -31,6 +31,7 @@
#if ENABLE(DFG_JIT)
#include "ArrayProfile.h"
+#include "DFGNodeFlags.h"
#include "SpeculatedType.h"
namespace JSC {
@@ -93,7 +94,8 @@
};
enum Conversion {
AsIs,
- Convert
+ Convert,
+ RageConvert
};
} // namespace Array
@@ -183,16 +185,21 @@
return ArrayMode(type, arrayClass(), speculation(), conversion());
}
+ ArrayMode withConversion(Array::Conversion conversion) const
+ {
+ return ArrayMode(type(), arrayClass(), speculation(), conversion);
+ }
+
ArrayMode withTypeAndConversion(Array::Type type, Array::Conversion conversion) const
{
return ArrayMode(type, arrayClass(), speculation(), conversion);
}
- ArrayMode refine(SpeculatedType base, SpeculatedType index, SpeculatedType value = SpecNone) const;
+ ArrayMode refine(SpeculatedType base, SpeculatedType index, SpeculatedType value = SpecNone, NodeFlags = 0) const;
bool alreadyChecked(Graph&, Node&, AbstractValue&) const;
- const char* toString() const;
+ void dump(PrintStream&) const;
bool usesButterfly() const
{
@@ -353,7 +360,7 @@
bool doesConversion() const
{
- return conversion() == Array::Convert;
+ return conversion() != Array::AsIs;
}
ArrayModes arrayModesThatPassFiltering() const
@@ -435,6 +442,16 @@
} } // namespace JSC::DFG
+namespace WTF {
+
+class PrintStream;
+void printInternal(PrintStream&, JSC::DFG::Array::Type);
+void printInternal(PrintStream&, JSC::DFG::Array::Class);
+void printInternal(PrintStream&, JSC::DFG::Array::Speculation);
+void printInternal(PrintStream&, JSC::DFG::Array::Conversion);
+
+} // namespace WTF
+
#endif // ENABLE(DFG_JIT)
#endif // DFGArrayMode_h
Modified: trunk/Source/_javascript_Core/dfg/DFGFixupPhase.cpp (136371 => 136372)
--- trunk/Source/_javascript_Core/dfg/DFGFixupPhase.cpp 2012-12-03 08:56:42 UTC (rev 136371)
+++ trunk/Source/_javascript_Core/dfg/DFGFixupPhase.cpp 2012-12-03 09:21:22 UTC (rev 136372)
@@ -54,6 +54,7 @@
if (!block)
return;
ASSERT(block->isReachable);
+ m_block = block;
for (m_indexInBlock = 0; m_indexInBlock < block->size(); ++m_indexInBlock) {
m_compileIndex = block->at(m_indexInBlock);
fixupNode(m_graph[m_compileIndex]);
@@ -131,7 +132,8 @@
node.setArrayMode(
node.arrayMode().refine(
m_graph[node.child1()].prediction(),
- m_graph[node.child2()].prediction()));
+ m_graph[node.child2()].prediction(),
+ SpecNone, node.flags()));
blessArrayOperation(node.child1(), node.child2(), 2);
@@ -442,6 +444,16 @@
m_graph.ref(index);
if (structure) {
+ if (m_indexInBlock > 0) {
+ // If the previous node was a CheckStructure inserted because of stuff
+ // that the array profile told us, then remove it.
+ Node& previousNode = m_graph[m_block->at(m_indexInBlock - 1)];
+ if (previousNode.op() == CheckStructure
+ && previousNode.child1() == array
+ && previousNode.codeOrigin == codeOrigin)
+ previousNode.setOpAndDefaultFlags(Phantom);
+ }
+
Node arrayify(ArrayifyToStructure, codeOrigin, OpInfo(structure), OpInfo(arrayMode.asWord()), array, index);
arrayify.ref();
NodeIndex arrayifyIndex = m_graph.size();
@@ -564,7 +576,8 @@
int32ToDouble.predict(SpecDouble);
int32ToDouble.ref();
}
-
+
+ BasicBlock* m_block;
unsigned m_indexInBlock;
NodeIndex m_compileIndex;
InsertionSet<NodeIndex> m_insertionSet;
Modified: trunk/Source/_javascript_Core/dfg/DFGGraph.cpp (136371 => 136372)
--- trunk/Source/_javascript_Core/dfg/DFGGraph.cpp 2012-12-03 08:56:42 UTC (rev 136371)
+++ trunk/Source/_javascript_Core/dfg/DFGGraph.cpp 2012-12-03 09:21:22 UTC (rev 136372)
@@ -189,7 +189,7 @@
hasPrinted = true;
}
if (node.hasArrayMode()) {
- out.print(hasPrinted ? ", " : "", node.arrayMode().toString());
+ out.print(hasPrinted ? ", " : "", node.arrayMode());
hasPrinted = true;
}
if (node.hasVarNumber()) {
Modified: trunk/Source/_javascript_Core/dfg/DFGNodeFlags.h (136371 => 136372)
--- trunk/Source/_javascript_Core/dfg/DFGNodeFlags.h 2012-12-03 08:56:42 UTC (rev 136371)
+++ trunk/Source/_javascript_Core/dfg/DFGNodeFlags.h 2012-12-03 09:21:22 UTC (rev 136372)
@@ -52,15 +52,16 @@
#define NodeMayOverflow 0x100
#define NodeMayNegZero 0x200
-#define NodeBackPropMask 0x3C00
-#define NodeUseBottom 0x000
+#define NodeBackPropMask 0x7C00
+#define NodeUseBottom 0x0000
#define NodeUsedAsNumber 0x400 // The result of this computation may be used in a context that observes fractional results.
#define NodeNeedsNegZero 0x800 // The result of this computation may be used in a context that observes -0.
#define NodeUsedAsOther 0x1000 // The result of this computation may be used in a context that distinguishes between NaN and other things (like undefined).
#define NodeUsedAsValue (NodeUsedAsNumber | NodeNeedsNegZero | NodeUsedAsOther)
#define NodeUsedAsInt 0x2000 // The result of this computation is known to be used in a context that prefers, but does not require, integer values.
+#define NodeUsedAsIntLocally 0x4000 // Same as NodeUsedAsInt, but within the same basic block.
-#define NodeDoesNotExit 0x4000 // This flag is negated to make it natural for the default to be that a node does exit.
+#define NodeDoesNotExit 0x8000 // This flag is negated to make it natural for the default to be that a node does exit.
typedef uint16_t NodeFlags;
Modified: trunk/Source/_javascript_Core/dfg/DFGOperations.cpp (136371 => 136372)
--- trunk/Source/_javascript_Core/dfg/DFGOperations.cpp 2012-12-03 08:56:42 UTC (rev 136371)
+++ trunk/Source/_javascript_Core/dfg/DFGOperations.cpp 2012-12-03 09:21:22 UTC (rev 136372)
@@ -1444,6 +1444,14 @@
return reinterpret_cast<char*>(object->ensureContiguous(globalData));
}
+char* DFG_OPERATION operationRageEnsureContiguous(ExecState* exec, JSObject* object)
+{
+ JSGlobalData& globalData = exec->globalData();
+ NativeCallFrameTracer tracer(&globalData, exec);
+
+ return reinterpret_cast<char*>(object->rageEnsureContiguous(globalData));
+}
+
char* DFG_OPERATION operationEnsureArrayStorage(ExecState* exec, JSObject* object)
{
JSGlobalData& globalData = exec->globalData();
Modified: trunk/Source/_javascript_Core/dfg/DFGOperations.h (136371 => 136372)
--- trunk/Source/_javascript_Core/dfg/DFGOperations.h 2012-12-03 08:56:42 UTC (rev 136371)
+++ trunk/Source/_javascript_Core/dfg/DFGOperations.h 2012-12-03 09:21:22 UTC (rev 136372)
@@ -205,6 +205,7 @@
char* DFG_OPERATION operationEnsureInt32(ExecState*, JSObject*);
char* DFG_OPERATION operationEnsureDouble(ExecState*, JSObject*);
char* DFG_OPERATION operationEnsureContiguous(ExecState*, JSObject*);
+char* DFG_OPERATION operationRageEnsureContiguous(ExecState*, JSObject*);
char* DFG_OPERATION operationEnsureArrayStorage(ExecState*, JSObject*);
// This method is used to lookup an exception hander, keyed by faultLocation, which is
Modified: trunk/Source/_javascript_Core/dfg/DFGPredictionPropagationPhase.cpp (136371 => 136372)
--- trunk/Source/_javascript_Core/dfg/DFGPredictionPropagationPhase.cpp 2012-12-03 08:56:42 UTC (rev 136371)
+++ trunk/Source/_javascript_Core/dfg/DFGPredictionPropagationPhase.cpp 2012-12-03 09:21:22 UTC (rev 136372)
@@ -204,7 +204,7 @@
if (prediction)
changed |= mergePrediction(prediction);
- changed |= variableAccessData->mergeFlags(flags);
+ changed |= variableAccessData->mergeFlags(flags & ~NodeUsedAsIntLocally);
break;
}
@@ -229,7 +229,7 @@
case BitLShift:
case BitURShift: {
changed |= setPrediction(SpecInt32);
- flags |= NodeUsedAsInt;
+ flags |= NodeUsedAsInt | NodeUsedAsIntLocally;
flags &= ~(NodeUsedAsNumber | NodeNeedsNegZero | NodeUsedAsOther);
changed |= m_graph[node.child1()].mergeFlags(flags);
changed |= m_graph[node.child2()].mergeFlags(flags);
@@ -238,7 +238,7 @@
case ValueToInt32: {
changed |= setPrediction(SpecInt32);
- flags |= NodeUsedAsInt;
+ flags |= NodeUsedAsInt | NodeUsedAsIntLocally;
flags &= ~(NodeUsedAsNumber | NodeNeedsNegZero | NodeUsedAsOther);
changed |= m_graph[node.child1()].mergeFlags(flags);
break;
@@ -267,7 +267,7 @@
case StringCharCodeAt: {
changed |= mergePrediction(SpecInt32);
changed |= m_graph[node.child1()].mergeFlags(NodeUsedAsValue);
- changed |= m_graph[node.child2()].mergeFlags(NodeUsedAsNumber | NodeUsedAsOther | NodeUsedAsInt);
+ changed |= m_graph[node.child2()].mergeFlags(NodeUsedAsNumber | NodeUsedAsOther | NodeUsedAsInt | NodeUsedAsIntLocally);
break;
}
@@ -517,13 +517,13 @@
changed |= mergePrediction(node.getHeapPrediction());
changed |= m_graph[node.child1()].mergeFlags(NodeUsedAsValue);
- changed |= m_graph[node.child2()].mergeFlags(NodeUsedAsNumber | NodeUsedAsOther | NodeUsedAsInt);
+ changed |= m_graph[node.child2()].mergeFlags(NodeUsedAsNumber | NodeUsedAsOther | NodeUsedAsInt | NodeUsedAsIntLocally);
break;
}
case GetMyArgumentByValSafe: {
changed |= mergePrediction(node.getHeapPrediction());
- changed |= m_graph[node.child1()].mergeFlags(NodeUsedAsNumber | NodeUsedAsOther | NodeUsedAsInt);
+ changed |= m_graph[node.child1()].mergeFlags(NodeUsedAsNumber | NodeUsedAsOther | NodeUsedAsInt | NodeUsedAsIntLocally);
break;
}
@@ -626,7 +626,7 @@
case NewArrayWithSize: {
changed |= setPrediction(SpecArray);
- changed |= m_graph[node.child1()].mergeFlags(NodeUsedAsValue | NodeUsedAsInt);
+ changed |= m_graph[node.child1()].mergeFlags(NodeUsedAsValue | NodeUsedAsInt | NodeUsedAsIntLocally);
break;
}
@@ -643,7 +643,7 @@
case StringCharAt: {
changed |= setPrediction(SpecString);
changed |= m_graph[node.child1()].mergeFlags(NodeUsedAsValue);
- changed |= m_graph[node.child2()].mergeFlags(NodeUsedAsNumber | NodeUsedAsOther | NodeUsedAsInt);
+ changed |= m_graph[node.child2()].mergeFlags(NodeUsedAsNumber | NodeUsedAsOther | NodeUsedAsInt | NodeUsedAsIntLocally);
break;
}
@@ -718,7 +718,7 @@
case PutByVal:
changed |= m_graph[m_graph.varArgChild(node, 0)].mergeFlags(NodeUsedAsValue);
- changed |= m_graph[m_graph.varArgChild(node, 1)].mergeFlags(NodeUsedAsNumber | NodeUsedAsOther | NodeUsedAsInt);
+ changed |= m_graph[m_graph.varArgChild(node, 1)].mergeFlags(NodeUsedAsNumber | NodeUsedAsOther | NodeUsedAsInt | NodeUsedAsIntLocally);
changed |= m_graph[m_graph.varArgChild(node, 2)].mergeFlags(NodeUsedAsValue);
break;
Modified: trunk/Source/_javascript_Core/dfg/DFGSpeculativeJIT.cpp (136371 => 136372)
--- trunk/Source/_javascript_Core/dfg/DFGSpeculativeJIT.cpp 2012-12-03 08:56:42 UTC (rev 136371)
+++ trunk/Source/_javascript_Core/dfg/DFGSpeculativeJIT.cpp 2012-12-03 09:21:22 UTC (rev 136372)
@@ -598,7 +598,10 @@
callOperation(operationEnsureDouble, tempGPR, baseReg);
break;
case Array::Contiguous:
- callOperation(operationEnsureContiguous, tempGPR, baseReg);
+ if (node.arrayMode().conversion() == Array::RageConvert)
+ callOperation(operationRageEnsureContiguous, tempGPR, baseReg);
+ else
+ callOperation(operationEnsureContiguous, tempGPR, baseReg);
break;
case Array::ArrayStorage:
case Array::SlowPutArrayStorage:
Modified: trunk/Source/_javascript_Core/dfg/DFGStructureCheckHoistingPhase.cpp (136371 => 136372)
--- trunk/Source/_javascript_Core/dfg/DFGStructureCheckHoistingPhase.cpp 2012-12-03 08:56:42 UTC (rev 136371)
+++ trunk/Source/_javascript_Core/dfg/DFGStructureCheckHoistingPhase.cpp 2012-12-03 09:21:22 UTC (rev 136372)
@@ -106,6 +106,24 @@
// Don't count these uses.
break;
+ case ArrayifyToStructure:
+ case Arrayify:
+ if (node.arrayMode().conversion() == Array::RageConvert) {
+ // Rage conversion changes structures. We should avoid tying to do
+ // any kind of hoisting when rage conversion is in play.
+ Node& child = m_graph[node.child1()];
+ if (child.op() != GetLocal)
+ break;
+ VariableAccessData* variable = child.variableAccessData();
+ variable->vote(VoteOther);
+ if (variable->isCaptured() || variable->structureCheckHoistingFailed())
+ break;
+ if (!isCellSpeculation(variable->prediction()))
+ break;
+ noticeStructureCheck(variable, 0);
+ }
+ break;
+
case SetLocal: {
// Find all uses of the source of the SetLocal. If any of them are a
// kind of CheckStructure, then we should notice them to ensure that
Modified: trunk/Source/_javascript_Core/runtime/JSObject.cpp (136371 => 136372)
--- trunk/Source/_javascript_Core/runtime/JSObject.cpp 2012-12-03 08:56:42 UTC (rev 136371)
+++ trunk/Source/_javascript_Core/runtime/JSObject.cpp 2012-12-03 09:21:22 UTC (rev 136372)
@@ -804,7 +804,8 @@
return convertInt32ToArrayStorage(globalData, structure()->suggestedArrayStorageTransition());
}
-WriteBarrier<Unknown>* JSObject::convertDoubleToContiguous(JSGlobalData& globalData)
+template<JSObject::DoubleToContiguousMode mode>
+WriteBarrier<Unknown>* JSObject::genericConvertDoubleToContiguous(JSGlobalData& globalData)
{
ASSERT(hasDouble(structure()->indexingType()));
@@ -816,13 +817,33 @@
currentAsValue->clear();
continue;
}
- currentAsValue->setWithoutWriteBarrier(JSValue(JSValue::EncodeAsDouble, value));
+ JSValue v;
+ switch (mode) {
+ case EncodeValueAsDouble:
+ v = JSValue(JSValue::EncodeAsDouble, value);
+ break;
+ case RageConvertDoubleToValue:
+ v = jsNumber(value);
+ break;
+ }
+ ASSERT(v.isNumber());
+ currentAsValue->setWithoutWriteBarrier(v);
}
setStructure(globalData, Structure::nonPropertyTransition(globalData, structure(), AllocateContiguous));
return m_butterfly->contiguous();
}
+WriteBarrier<Unknown>* JSObject::convertDoubleToContiguous(JSGlobalData& globalData)
+{
+ return genericConvertDoubleToContiguous<EncodeValueAsDouble>(globalData);
+}
+
+WriteBarrier<Unknown>* JSObject::rageConvertDoubleToContiguous(JSGlobalData& globalData)
+{
+ return genericConvertDoubleToContiguous<RageConvertDoubleToValue>(globalData);
+}
+
ArrayStorage* JSObject::convertDoubleToArrayStorage(JSGlobalData& globalData, NonPropertyTransition transition, unsigned neededLength)
{
ASSERT(hasDouble(structure()->indexingType()));
@@ -974,7 +995,7 @@
}
}
-WriteBarrier<Unknown>* JSObject::ensureContiguousSlow(JSGlobalData& globalData)
+WriteBarrier<Unknown>* JSObject::ensureContiguousSlow(JSGlobalData& globalData, DoubleToContiguousMode mode)
{
switch (structure()->indexingType()) {
case ALL_BLANK_INDEXING_TYPES:
@@ -989,6 +1010,8 @@
return convertInt32ToContiguous(globalData);
case ALL_DOUBLE_INDEXING_TYPES:
+ if (mode == RageConvertDoubleToValue)
+ return rageConvertDoubleToContiguous(globalData);
return convertDoubleToContiguous(globalData);
case ALL_ARRAY_STORAGE_INDEXING_TYPES:
@@ -1000,6 +1023,16 @@
}
}
+WriteBarrier<Unknown>* JSObject::ensureContiguousSlow(JSGlobalData& globalData)
+{
+ return ensureContiguousSlow(globalData, EncodeValueAsDouble);
+}
+
+WriteBarrier<Unknown>* JSObject::rageEnsureContiguousSlow(JSGlobalData& globalData)
+{
+ return ensureContiguousSlow(globalData, RageConvertDoubleToValue);
+}
+
ArrayStorage* JSObject::ensureArrayStorageSlow(JSGlobalData& globalData)
{
switch (structure()->indexingType()) {
Modified: trunk/Source/_javascript_Core/runtime/JSObject.h (136371 => 136372)
--- trunk/Source/_javascript_Core/runtime/JSObject.h 2012-12-03 08:56:42 UTC (rev 136371)
+++ trunk/Source/_javascript_Core/runtime/JSObject.h 2012-12-03 09:21:22 UTC (rev 136372)
@@ -679,6 +679,17 @@
return ensureContiguousSlow(globalData);
}
+ // Same as ensureContiguous(), except that if the indexed storage is in
+ // double mode, then it does a rage conversion to contiguous: it
+ // attempts to convert each double to an int32.
+ WriteBarrier<Unknown>* rageEnsureContiguous(JSGlobalData& globalData)
+ {
+ if (LIKELY(hasContiguous(structure()->indexingType())))
+ return m_butterfly->contiguous();
+
+ return rageEnsureContiguousSlow(globalData);
+ }
+
// Ensure that the object is in a mode where it has array storage. Use
// this if you're about to perform actions that would have required the
// object to be converted to have array storage, if it didn't have it
@@ -775,8 +786,9 @@
ArrayStorage* convertInt32ToArrayStorage(JSGlobalData&, NonPropertyTransition, unsigned neededLength);
ArrayStorage* convertInt32ToArrayStorage(JSGlobalData&, NonPropertyTransition);
ArrayStorage* convertInt32ToArrayStorage(JSGlobalData&);
-
+
WriteBarrier<Unknown>* convertDoubleToContiguous(JSGlobalData&);
+ WriteBarrier<Unknown>* rageConvertDoubleToContiguous(JSGlobalData&);
ArrayStorage* convertDoubleToArrayStorage(JSGlobalData&, NonPropertyTransition, unsigned neededLength);
ArrayStorage* convertDoubleToArrayStorage(JSGlobalData&, NonPropertyTransition);
ArrayStorage* convertDoubleToArrayStorage(JSGlobalData&);
@@ -965,8 +977,14 @@
WriteBarrier<Unknown>* ensureInt32Slow(JSGlobalData&);
double* ensureDoubleSlow(JSGlobalData&);
WriteBarrier<Unknown>* ensureContiguousSlow(JSGlobalData&);
+ WriteBarrier<Unknown>* rageEnsureContiguousSlow(JSGlobalData&);
ArrayStorage* ensureArrayStorageSlow(JSGlobalData&);
-
+
+ enum DoubleToContiguousMode { EncodeValueAsDouble, RageConvertDoubleToValue };
+ template<DoubleToContiguousMode mode>
+ WriteBarrier<Unknown>* genericConvertDoubleToContiguous(JSGlobalData&);
+ WriteBarrier<Unknown>* ensureContiguousSlow(JSGlobalData&, DoubleToContiguousMode);
+
protected:
Butterfly* m_butterfly;
};