Modified: branches/dfgFourthTier/Source/_javascript_Core/ftl/FTLLowerDFGToLLVM.cpp (147285 => 147286)
--- branches/dfgFourthTier/Source/_javascript_Core/ftl/FTLLowerDFGToLLVM.cpp 2013-03-31 04:30:59 UTC (rev 147285)
+++ branches/dfgFourthTier/Source/_javascript_Core/ftl/FTLLowerDFGToLLVM.cpp 2013-03-31 19:33:53 UTC (rev 147286)
@@ -171,18 +171,18 @@
SpeculatedType prediction = variable->prediction();
if (isInt32Speculation(prediction)) {
- speculateBackward(BadType, jsValue, node, checkNotInt32(jsValue));
+ speculateBackward(BadType, jsValue, node, isNotInt32(jsValue));
m_out.set(unboxInt32(jsValue), m_locals32.operand(variable->local()));
continue;
}
if (isCellSpeculation(prediction)) {
- speculateBackward(BadType, jsValue, node, checkNotCell(jsValue));
+ speculateBackward(BadType, jsValue, node, isNotCell(jsValue));
m_out.set(jsValue, m_locals64.operand(variable->local()));
continue;
}
if (isBooleanSpeculation(prediction)) {
- speculateBackward(BadType, jsValue, node, checkNotBoolean(jsValue));
+ speculateBackward(BadType, jsValue, node, isNotBoolean(jsValue));
m_out.set(unboxBoolean(jsValue), m_localsBoolean.operand(variable->local()));
continue;
}
@@ -285,6 +285,24 @@
case BitLShift:
compileBitLShift();
break;
+ case CheckStructure:
+ compileCheckStructure();
+ break;
+ case GetButterfly:
+ compileGetButterfly();
+ break;
+ case GetArrayLength:
+ compileGetArrayLength();
+ break;
+ case GetByVal:
+ compileGetByVal();
+ break;
+ case GetByOffset:
+ compileGetByOffset();
+ break;
+ case CompareEq:
+ compileCompareEq();
+ break;
case CompareLess:
compileCompareLess();
break;
@@ -517,6 +535,127 @@
m_out.bitAnd(lowInt32(m_node->child2()), m_out.constInt32(31))));
}
+ void compileCheckStructure()
+ {
+ LValue cell = lowCell(m_node->child1());
+
+ ExitKind exitKind;
+ if (m_node->child1()->op() == WeakJSConstant)
+ exitKind = BadWeakConstantCache;
+ else
+ exitKind = BadCache;
+
+ LValue structure = m_out.loadPtr(cell, JSCell::structureOffset());
+
+ if (m_node->structureSet().size() == 1) {
+ speculate(
+ exitKind, cell, 0,
+ m_out.notEqual(structure, weakPointer(m_node->structureSet()[0])));
+ return;
+ }
+
+ LBasicBlock continuation = m_out.newBlock();
+
+ LBasicBlock lastNext = m_out.insertNewBlocksBefore(continuation);
+ for (unsigned i = 0; i < m_node->structureSet().size() - 1; ++i) {
+ LBasicBlock nextStructure = m_out.newBlock();
+ m_out.branch(
+ m_out.equal(structure, weakPointer(m_node->structureSet()[i])),
+ continuation, nextStructure);
+ m_out.appendTo(nextStructure);
+ }
+
+ speculate(
+ exitKind, cell, 0,
+ m_out.notEqual(structure, weakPointer(m_node->structureSet().last())));
+
+ m_out.appendTo(continuation, lastNext);
+ }
+
+ void compileGetButterfly()
+ {
+ m_storageValues.add(
+ m_node, m_out.loadPtr(lowCell(m_node->child1()), JSObject::butterflyOffset()));
+ }
+
+ void compileGetArrayLength()
+ {
+ switch (m_node->arrayMode().type()) {
+ case Array::Int32:
+ case Array::Double:
+ case Array::Contiguous: {
+ m_int32Values.add(
+ m_node, m_out.load32(lowStorage(m_node->child2()), Butterfly::offsetOfPublicLength()));
+ break;
+ }
+
+ default:
+ RELEASE_ASSERT_NOT_REACHED();
+ break;
+ }
+ }
+
+ void compileGetByVal()
+ {
+ LValue index = lowInt32(m_node->child2());
+ LValue storage = lowStorage(m_node->child3());
+
+ switch (m_node->arrayMode().type()) {
+ case Array::Contiguous: {
+ if (m_node->arrayMode().isInBounds()) {
+ speculate(
+ OutOfBounds, 0, 0,
+ m_out.aboveOrEqual(
+ index, m_out.load32(storage, Butterfly::offsetOfPublicLength())));
+
+ LValue result = m_out.load64(
+ m_out.baseIndex(storage, m_out.zeroExt(index, m_out.intPtr), ScaleEight));
+ speculate(LoadFromHole, 0, 0, m_out.isZero64(result));
+ m_jsValueValues.add(m_node, result);
+ break;
+ }
+
+ RELEASE_ASSERT_NOT_REACHED();
+ break;
+ }
+
+ default:
+ RELEASE_ASSERT_NOT_REACHED();
+ break;
+ }
+ }
+
+ void compileGetByOffset()
+ {
+ StorageAccessData& storageAccessData =
+ m_graph.m_storageAccessData[m_node->storageAccessDataIndex()];
+
+ m_jsValueValues.add(
+ m_node,
+ m_out.load64(
+ lowStorage(m_node->child1()),
+ storageAccessData.offset * sizeof(EncodedJSValue)));
+ }
+
+ void compileCompareEq()
+ {
+ if (m_node->isBinaryUseKind(Int32Use)) {
+ m_booleanValues.add(
+ m_node,
+ m_out.equal(lowInt32(m_node->child1()), lowInt32(m_node->child2())));
+ return;
+ }
+
+ if (m_node->isBinaryUseKind(ObjectUse)) {
+ m_booleanValues.add(
+ m_node,
+ m_out.equal(lowObject(m_node->child1()), lowObject(m_node->child2())));
+ return;
+ }
+
+ RELEASE_ASSERT_NOT_REACHED();
+ }
+
void compileCompareLess()
{
if (m_node->isBinaryUseKind(Int32Use)) {
@@ -610,7 +749,7 @@
return result;
if (LValue boxedResult = m_jsValueValues.get(edge.node())) {
- FTL_TYPE_CHECK(boxedResult, edge, SpecInt32, checkNotInt32(boxedResult));
+ FTL_TYPE_CHECK(boxedResult, edge, SpecInt32, isNotInt32(boxedResult));
LValue result = unboxInt32(boxedResult);
m_int32Values.add(edge.node(), result);
return result;
@@ -626,7 +765,7 @@
ASSERT_UNUSED(mode, mode == ManualOperandSpeculation || isCell(edge.useKind()));
if (LValue uncheckedResult = m_jsValueValues.get(edge.node())) {
- FTL_TYPE_CHECK(uncheckedResult, edge, SpecCell, checkNotCell(uncheckedResult));
+ FTL_TYPE_CHECK(uncheckedResult, edge, SpecCell, isNotCell(uncheckedResult));
return uncheckedResult;
}
@@ -635,6 +774,15 @@
return m_out.intPtrZero;
}
+ LValue lowObject(Edge edge, OperandSpeculationMode mode = AutomaticOperandSpeculation)
+ {
+ ASSERT_UNUSED(mode, mode == ManualOperandSpeculation || edge.useKind() == ObjectUse);
+
+ LValue result = lowCell(edge, mode);
+ speculateObject(edge, result);
+ return result;
+ }
+
LValue lowBoolean(Edge edge, OperandSpeculationMode mode = AutomaticOperandSpeculation)
{
ASSERT_UNUSED(mode, mode == ManualOperandSpeculation || edge.useKind() == BooleanUse);
@@ -643,8 +791,10 @@
return result;
if (LValue unboxedResult = m_jsValueValues.get(edge.node())) {
- FTL_TYPE_CHECK(unboxedResult, edge, SpecBoolean, checkNotBoolean(unboxedResult));
- return unboxBoolean(unboxedResult);
+ FTL_TYPE_CHECK(unboxedResult, edge, SpecBoolean, isNotBoolean(unboxedResult));
+ LValue result = unboxBoolean(unboxedResult);
+ m_booleanValues.add(edge.node(), result);
+ return result;
}
RELEASE_ASSERT(!(m_state.forNode(edge).m_type & SpecBoolean));
@@ -659,18 +809,34 @@
if (LValue result = m_jsValueValues.get(edge.node()))
return result;
- if (LValue unboxedResult = m_int32Values.get(edge.node()))
- return boxInt32(unboxedResult);
+ if (LValue unboxedResult = m_int32Values.get(edge.node())) {
+ LValue result = boxInt32(unboxedResult);
+ m_jsValueValues.add(edge.node(), result);
+ return result;
+ }
- if (LValue unboxedResult = m_booleanValues.get(edge.node()))
- return boxBoolean(unboxedResult);
+ if (LValue unboxedResult = m_booleanValues.get(edge.node())) {
+ LValue result = boxBoolean(unboxedResult);
+ m_jsValueValues.add(edge.node(), result);
+ return result;
+ }
RELEASE_ASSERT_NOT_REACHED();
return 0;
}
- LValue checkNotInt32(LValue jsValue)
+ LValue lowStorage(Edge edge)
{
+ if (LValue result = m_storageValues.get(edge.node()))
+ return result;
+
+ LValue result = lowCell(edge);
+ m_storageValues.add(edge.node(), result);
+ return result;
+ }
+
+ LValue isNotInt32(LValue jsValue)
+ {
return m_out.below(jsValue, m_tagTypeNumber);
}
LValue unboxInt32(LValue jsValue)
@@ -682,12 +848,12 @@
return m_out.add(m_out.zeroExt(value, m_out.int64), m_tagTypeNumber);
}
- LValue checkNotCell(LValue jsValue)
+ LValue isNotCell(LValue jsValue)
{
return m_out.testNonZero64(jsValue, m_tagMask);
}
- LValue checkNotBoolean(LValue jsValue)
+ LValue isNotBoolean(LValue jsValue)
{
return m_out.testNonZero64(
m_out.bitXor(jsValue, m_out.constInt64(ValueFalse)),
@@ -716,6 +882,15 @@
case Int32Use:
speculateInt32(edge);
break;
+ case CellUse:
+ speculateCell(edge);
+ break;
+ case KnownCellUse:
+ ASSERT(!m_state.needsTypeCheck(edge));
+ break;
+ case ObjectUse:
+ speculateObject(edge);
+ break;
default:
RELEASE_ASSERT_NOT_REACHED();
}
@@ -731,6 +906,36 @@
lowInt32(edge);
}
+ void speculateCell(Edge edge)
+ {
+ lowCell(edge);
+ }
+
+ void speculateObject(Edge edge, LValue cell)
+ {
+ FTL_TYPE_CHECK(
+ cell, edge, SpecObject,
+ m_out.equal(
+ m_out.loadPtr(cell, JSCell::structureOffset()),
+ accountedPointer(globalData().structureStructure.get())));
+ }
+
+ void speculateObject(Edge edge)
+ {
+ speculateObject(edge, lowCell(edge));
+ }
+
+ LValue accountedPointer(JSCell* pointer)
+ {
+ return m_out.constIntPtr(bitwise_cast<intptr_t>(pointer));
+ }
+
+ LValue weakPointer(JSCell* pointer)
+ {
+ codeBlock()->appendWeakReference(pointer);
+ return accountedPointer(pointer);
+ }
+
LValue addressFor(LValue base, int operand)
{
return m_out.add(base, m_out.constIntPtr(operand * sizeof(Register)));
Modified: branches/dfgFourthTier/Source/_javascript_Core/ftl/FTLOutput.h (147285 => 147286)
--- branches/dfgFourthTier/Source/_javascript_Core/ftl/FTLOutput.h 2013-03-31 04:30:59 UTC (rev 147285)
+++ branches/dfgFourthTier/Source/_javascript_Core/ftl/FTLOutput.h 2013-03-31 19:33:53 UTC (rev 147286)
@@ -51,6 +51,8 @@
// These translate the pointer + offset into a reference (or, a pointer in LLVM-speak)
// and use get and set on them (or, load and store in LLVM-speak).
+enum Scale { ScaleOne, ScaleTwo, ScaleFour, ScaleEight, ScalePtr };
+
class Output {
public:
Output()
@@ -67,6 +69,12 @@
, int32Zero(constInt(int32, 0, SignExtend))
, int64Zero(constInt(int64, 0, SignExtend))
, intPtrZero(constInt(intPtr, 0, SignExtend))
+ , intPtrOne(constInt(intPtr, 1, SignExtend))
+ , intPtrTwo(constInt(intPtr, 2, SignExtend))
+ , intPtrThree(constInt(intPtr, 3, SignExtend))
+ , intPtrFour(constInt(intPtr, 4, SignExtend))
+ , intPtrEight(constInt(intPtr, 8, SignExtend))
+ , intPtrPtr(constInt(intPtr, sizeof(void*), SignExtend))
, m_function(0)
, m_builder(LLVMCreateBuilder())
, m_block(0)
@@ -87,15 +95,19 @@
m_function = function;
}
- LBasicBlock appendTo(LBasicBlock block, LBasicBlock nextBlock)
+ LBasicBlock insertNewBlocksBefore(LBasicBlock nextBlock)
{
LBasicBlock lastNextBlock = m_nextBlock;
m_nextBlock = nextBlock;
-
- appendTo(block);
return lastNextBlock;
}
+ LBasicBlock appendTo(LBasicBlock block, LBasicBlock nextBlock)
+ {
+ appendTo(block);
+ return insertNewBlocksBefore(nextBlock);
+ }
+
void appendTo(LBasicBlock block)
{
m_block = block;
@@ -154,6 +166,32 @@
void store64(LValue value, LValue pointer, ptrdiff_t offset = 0) { store(value, pointer, offset, ref64); }
void storePtr(LValue value, LValue pointer, ptrdiff_t offset = 0) { store(value, pointer, offset, refPtr); }
+ LValue baseIndex(LValue base, LValue index, Scale scale, ptrdiff_t offset = 0)
+ {
+ LValue accumulatedOffset;
+
+ switch (scale) {
+ case ScaleOne:
+ accumulatedOffset = index;
+ break;
+ case ScaleTwo:
+ accumulatedOffset = shl(index, intPtrOne);
+ break;
+ case ScaleFour:
+ accumulatedOffset = shl(index, intPtrTwo);
+ break;
+ case ScaleEight:
+ case ScalePtr:
+ accumulatedOffset = shl(index, intPtrThree);
+ break;
+ }
+
+ if (offset)
+ accumulatedOffset = add(accumulatedOffset, constIntPtr(offset));
+
+ return add(base, accumulatedOffset);
+ }
+
LValue equal(LValue left, LValue right) { return buildICmp(m_builder, LLVMIntEQ, left, right); }
LValue notEqual(LValue left, LValue right) { return buildICmp(m_builder, LLVMIntNE, left, right); }
LValue above(LValue left, LValue right) { return buildICmp(m_builder, LLVMIntUGT, left, right); }
@@ -218,6 +256,12 @@
const LValue int32Zero;
const LValue int64Zero;
const LValue intPtrZero;
+ const LValue intPtrOne;
+ const LValue intPtrTwo;
+ const LValue intPtrThree;
+ const LValue intPtrFour;
+ const LValue intPtrEight;
+ const LValue intPtrPtr;
LModule m_module;
LValue m_function;