Diff
Modified: trunk/Source/_javascript_Core/ChangeLog (153132 => 153133)
--- trunk/Source/_javascript_Core/ChangeLog 2013-07-25 03:59:04 UTC (rev 153132)
+++ trunk/Source/_javascript_Core/ChangeLog 2013-07-25 03:59:06 UTC (rev 153133)
@@ -1,5 +1,89 @@
2013-04-27 Filip Pizlo <fpi...@apple.com>
+ FTL should support double variables
+ https://bugs.webkit.org/show_bug.cgi?id=113624
+
+ Reviewed by Geoffrey Garen.
+
+ Made all of the operations that the FTL already supports, also support doubles.
+ OSR exit already basically had everything it needed, so no changes there. This
+ mostly just glues together bits of DFG IR to LLVM IR, in a straight-forward way.
+
+ * ftl/FTLAbbreviations.h:
+ (FTL):
+ (JSC::FTL::doubleType):
+ (JSC::FTL::constReal):
+ (JSC::FTL::buildPhi):
+ (JSC::FTL::addIncoming):
+ (JSC::FTL::buildFAdd):
+ (JSC::FTL::buildFSub):
+ (JSC::FTL::buildFMul):
+ (JSC::FTL::buildFNeg):
+ (JSC::FTL::buildSIToFP):
+ (JSC::FTL::buildUIToFP):
+ (JSC::FTL::buildBitCast):
+ (JSC::FTL::buildFCmp):
+ * ftl/FTLCapabilities.cpp:
+ (JSC::FTL::canCompile):
+ * ftl/FTLCommonValues.cpp:
+ (JSC::FTL::CommonValues::CommonValues):
+ * ftl/FTLCommonValues.h:
+ (CommonValues):
+ * ftl/FTLLowerDFGToLLVM.cpp:
+ (JSC::FTL::LowerDFGToLLVM::LowerDFGToLLVM):
+ (JSC::FTL::LowerDFGToLLVM::lower):
+ (JSC::FTL::LowerDFGToLLVM::compileGetLocal):
+ (JSC::FTL::LowerDFGToLLVM::compileSetLocal):
+ (JSC::FTL::LowerDFGToLLVM::compileAdd):
+ (JSC::FTL::LowerDFGToLLVM::compileArithSub):
+ (JSC::FTL::LowerDFGToLLVM::compileArithMul):
+ (JSC::FTL::LowerDFGToLLVM::compileArithNegate):
+ (JSC::FTL::LowerDFGToLLVM::compileUInt32ToNumber):
+ (JSC::FTL::LowerDFGToLLVM::compileGetByVal):
+ (JSC::FTL::LowerDFGToLLVM::compileCompareEq):
+ (JSC::FTL::LowerDFGToLLVM::compileCompareLess):
+ (JSC::FTL::LowerDFGToLLVM::lowDouble):
+ (LowerDFGToLLVM):
+ (JSC::FTL::LowerDFGToLLVM::lowJSValue):
+ (JSC::FTL::LowerDFGToLLVM::isCellOrMisc):
+ (JSC::FTL::LowerDFGToLLVM::unboxDouble):
+ (JSC::FTL::LowerDFGToLLVM::boxDouble):
+ (JSC::FTL::LowerDFGToLLVM::speculate):
+ (JSC::FTL::LowerDFGToLLVM::speculateNumber):
+ (JSC::FTL::LowerDFGToLLVM::speculateRealNumber):
+ (JSC::FTL::LowerDFGToLLVM::appendOSRExit):
+ (JSC::FTL::LowerDFGToLLVM::addExitArgumentForNode):
+ * ftl/FTLOutput.h:
+ (JSC::FTL::Output::constDouble):
+ (Output):
+ (JSC::FTL::Output::phi):
+ (JSC::FTL::Output::doubleAdd):
+ (JSC::FTL::Output::doubleSub):
+ (JSC::FTL::Output::doubleMul):
+ (JSC::FTL::Output::doubleNeg):
+ (JSC::FTL::Output::intToFP):
+ (JSC::FTL::Output::intToDouble):
+ (JSC::FTL::Output::unsignedToFP):
+ (JSC::FTL::Output::unsignedToDouble):
+ (JSC::FTL::Output::bitCast):
+ (JSC::FTL::Output::loadDouble):
+ (JSC::FTL::Output::storeDouble):
+ (JSC::FTL::Output::doubleEqual):
+ (JSC::FTL::Output::doubleNotEqualOrUnordered):
+ (JSC::FTL::Output::doubleLessThan):
+ (JSC::FTL::Output::doubleLessThanOrEqual):
+ (JSC::FTL::Output::doubleGreaterThan):
+ (JSC::FTL::Output::doubleGreaterThanOrEqual):
+ (JSC::FTL::Output::doubleEqualOrUnordered):
+ (JSC::FTL::Output::doubleNotEqual):
+ (JSC::FTL::Output::doubleLessThanOrUnordered):
+ (JSC::FTL::Output::doubleLessThanOrEqualOrUnordered):
+ (JSC::FTL::Output::doubleGreaterThanOrUnordered):
+ (JSC::FTL::Output::doubleGreaterThanOrEqualOrUnordered):
+ (JSC::FTL::Output::testIsZero64):
+
+2013-04-27 Filip Pizlo <fpi...@apple.com>
+
fourthTier: SymbolTable should be thread-safe
https://bugs.webkit.org/show_bug.cgi?id=115301
Modified: trunk/Source/_javascript_Core/ftl/FTLAbbreviations.h (153132 => 153133)
--- trunk/Source/_javascript_Core/ftl/FTLAbbreviations.h 2013-07-25 03:59:04 UTC (rev 153132)
+++ trunk/Source/_javascript_Core/ftl/FTLAbbreviations.h 2013-07-25 03:59:06 UTC (rev 153133)
@@ -47,6 +47,7 @@
typedef LLVMBuilderRef LBuilder;
typedef LLVMCallConv LCallConv;
typedef LLVMIntPredicate LIntPredicate;
+typedef LLVMRealPredicate LRealPredicate;
typedef LLVMLinkage LLinkage;
typedef LLVMModuleRef LModule;
typedef LLVMTypeRef LType;
@@ -57,6 +58,7 @@
static inline LType int32Type() { return LLVMInt32Type(); }
static inline LType int64Type() { return LLVMInt64Type(); }
static inline LType intPtrType() { return LLVMInt64Type(); }
+static inline LType doubleType() { return LLVMDoubleType(); }
static inline LType pointerType(LType type) { return LLVMPointerType(type, 0); }
@@ -134,17 +136,58 @@
enum BitExtension { ZeroExtend, SignExtend };
static inline LValue constInt(LType type, unsigned long long value, BitExtension extension) { return LLVMConstInt(type, value, extension == SignExtend); }
+static inline LValue constReal(LType type, double value) { return LLVMConstReal(type, value); }
static inline LValue constIntToPtr(LValue value, LType type) { return LLVMConstIntToPtr(value, type); }
static inline LValue constBitCast(LValue value, LType type) { return LLVMConstBitCast(value, type); }
static inline LBasicBlock appendBasicBlock(LValue function, const char* name = "") { return LLVMAppendBasicBlock(function, name); }
static inline LBasicBlock insertBasicBlock(LBasicBlock beforeBasicBlock, const char* name = "") { return LLVMInsertBasicBlock(beforeBasicBlock, name); }
+static inline LValue buildPhi(LBuilder builder, LType type) { return LLVMBuildPhi(builder, type, ""); }
+static inline void addIncoming(LValue phi, const LValue* values, const LBasicBlock* blocks, unsigned numPredecessors)
+{
+ LLVMAddIncoming(phi, const_cast<LValue*>(values), const_cast<LBasicBlock*>(blocks), numPredecessors);
+}
+template<typename ValueVectorType, typename BlockVectorType>
+static inline void addIncoming(LValue phi, const ValueVectorType& values, const BlockVectorType& blocks)
+{
+ ASSERT(values.size() == blocks.size());
+ addIncoming(phi, values.begin(), blocks.begin(), values.size());
+}
+static inline void addIncoming(LValue phi, LValue value1, LBasicBlock block1)
+{
+ addIncoming(phi, &value1, &block1, 1);
+}
+static inline void addIncoming(LValue phi, LValue value1, LBasicBlock block1, LValue value2, LBasicBlock block2)
+{
+ LValue values[] = { value1, value2 };
+ LBasicBlock blocks[] = { block1, block2 };
+ addIncoming(phi, values, blocks, 2);
+}
+static inline LValue buildPhi(LBuilder builder, LType type, LValue value1, LBasicBlock block1)
+{
+ LValue result = buildPhi(builder, type);
+ addIncoming(result, value1, block1);
+ return result;
+}
+static inline LValue buildPhi(
+ LBuilder builder, LType type, LValue value1, LBasicBlock block1, LValue value2,
+ LBasicBlock block2)
+{
+ LValue result = buildPhi(builder, type);
+ addIncoming(result, value1, block1, value2, block2);
+ return result;
+}
+
static inline LValue buildAlloca(LBuilder builder, LType type) { return LLVMBuildAlloca(builder, type, ""); }
static inline LValue buildAdd(LBuilder builder, LValue left, LValue right) { return LLVMBuildAdd(builder, left, right, ""); }
static inline LValue buildSub(LBuilder builder, LValue left, LValue right) { return LLVMBuildSub(builder, left, right, ""); }
static inline LValue buildMul(LBuilder builder, LValue left, LValue right) { return LLVMBuildMul(builder, left, right, ""); }
static inline LValue buildNeg(LBuilder builder, LValue value) { return LLVMBuildNeg(builder, value, ""); }
+static inline LValue buildFAdd(LBuilder builder, LValue left, LValue right) { return LLVMBuildFAdd(builder, left, right, ""); }
+static inline LValue buildFSub(LBuilder builder, LValue left, LValue right) { return LLVMBuildFSub(builder, left, right, ""); }
+static inline LValue buildFMul(LBuilder builder, LValue left, LValue right) { return LLVMBuildFMul(builder, left, right, ""); }
+static inline LValue buildFNeg(LBuilder builder, LValue value) { return LLVMBuildFNeg(builder, value, ""); }
static inline LValue buildAnd(LBuilder builder, LValue left, LValue right) { return LLVMBuildAnd(builder, left, right, ""); }
static inline LValue buildOr(LBuilder builder, LValue left, LValue right) { return LLVMBuildOr(builder, left, right, ""); }
static inline LValue buildXor(LBuilder builder, LValue left, LValue right) { return LLVMBuildXor(builder, left, right, ""); }
@@ -154,10 +197,14 @@
static inline LValue buildLoad(LBuilder builder, LValue pointer) { return LLVMBuildLoad(builder, pointer, ""); }
static inline LValue buildStore(LBuilder builder, LValue value, LValue pointer) { return LLVMBuildStore(builder, value, pointer); }
static inline LValue buildZExt(LBuilder builder, LValue value, LType type) { return LLVMBuildZExt(builder, value, type, ""); }
+static inline LValue buildSIToFP(LBuilder builder, LValue value, LType type) { return LLVMBuildSIToFP(builder, value, type, ""); }
+static inline LValue buildUIToFP(LBuilder builder, LValue value, LType type) { return LLVMBuildUIToFP(builder, value, type, ""); }
static inline LValue buildIntCast(LBuilder builder, LValue value, LType type) { return LLVMBuildIntCast(builder, value, type, ""); }
static inline LValue buildIntToPtr(LBuilder builder, LValue value, LType type) { return LLVMBuildIntToPtr(builder, value, type, ""); }
static inline LValue buildPtrToInt(LBuilder builder, LValue value, LType type) { return LLVMBuildPtrToInt(builder, value, type, ""); }
+static inline LValue buildBitCast(LBuilder builder, LValue value, LType type) { return LLVMBuildBitCast(builder, value, type, ""); }
static inline LValue buildICmp(LBuilder builder, LIntPredicate cond, LValue left, LValue right) { return LLVMBuildICmp(builder, cond, left, right, ""); }
+static inline LValue buildFCmp(LBuilder builder, LRealPredicate cond, LValue left, LValue right) { return LLVMBuildFCmp(builder, cond, left, right, ""); }
static inline LValue buildCall(LBuilder builder, LValue function, const LValue* args, unsigned numArgs)
{
return LLVMBuildCall(builder, function, const_cast<LValue*>(args), numArgs, "");
Modified: trunk/Source/_javascript_Core/ftl/FTLCapabilities.cpp (153132 => 153133)
--- trunk/Source/_javascript_Core/ftl/FTLCapabilities.cpp 2013-07-25 03:59:04 UTC (rev 153132)
+++ trunk/Source/_javascript_Core/ftl/FTLCapabilities.cpp 2013-07-25 03:59:06 UTC (rev 153133)
@@ -50,6 +50,9 @@
case UntypedUse:
case Int32Use:
case KnownInt32Use:
+ case NumberUse:
+ case KnownNumberUse:
+ case RealNumberUse:
case BooleanUse:
case CellUse:
case KnownCellUse:
@@ -90,22 +93,13 @@
case PutByOffset:
case GetGlobalVar:
case PutGlobalVar:
- // These are OK.
- break;
case ValueAdd:
case ArithAdd:
case ArithSub:
case ArithMul:
- if (node->binaryUseKind() == Int32Use)
- break;
- return false;
case ArithNegate:
- if (node->child1().useKind() == Int32Use)
- break;
- return false;
case UInt32ToNumber:
- if (!nodeCanSpeculateInteger(node->arithNodeFlags()))
- return false;
+ // These are OK.
break;
case GetArrayLength:
switch (node->arrayMode().type()) {
@@ -120,6 +114,7 @@
case GetByVal:
switch (node->arrayMode().type()) {
case Array::Int32:
+ case Array::Double:
case Array::Contiguous:
break;
default:
@@ -136,12 +131,16 @@
case CompareEq:
if (node->isBinaryUseKind(Int32Use))
break;
+ if (node->isBinaryUseKind(NumberUse))
+ break;
if (node->isBinaryUseKind(ObjectUse))
break;
return false;
case CompareLess:
if (node->isBinaryUseKind(Int32Use))
break;
+ if (node->isBinaryUseKind(NumberUse))
+ break;
return false;
case Branch:
if (node->child1().useKind() == BooleanUse)
Modified: trunk/Source/_javascript_Core/ftl/FTLCommonValues.cpp (153132 => 153133)
--- trunk/Source/_javascript_Core/ftl/FTLCommonValues.cpp 2013-07-25 03:59:04 UTC (rev 153132)
+++ trunk/Source/_javascript_Core/ftl/FTLCommonValues.cpp 2013-07-25 03:59:06 UTC (rev 153133)
@@ -36,9 +36,11 @@
, int32(int32Type())
, int64(int64Type())
, intPtr(intPtrType())
+ , doubleType(FTL::doubleType())
, ref32(pointerType(int32))
, ref64(pointerType(int64))
, refPtr(pointerType(intPtr))
+ , refDouble(pointerType(doubleType))
, booleanTrue(constInt(boolean, true, ZeroExtend))
, booleanFalse(constInt(boolean, false, ZeroExtend))
, int32Zero(constInt(int32, 0, SignExtend))
@@ -50,6 +52,7 @@
, intPtrFour(constInt(intPtr, 4, SignExtend))
, intPtrEight(constInt(intPtr, 8, SignExtend))
, intPtrPtr(constInt(intPtr, sizeof(void*), SignExtend))
+ , doubleZero(constReal(doubleType, 0))
, m_module(0)
{
}
Modified: trunk/Source/_javascript_Core/ftl/FTLCommonValues.h (153132 => 153133)
--- trunk/Source/_javascript_Core/ftl/FTLCommonValues.h 2013-07-25 03:59:04 UTC (rev 153132)
+++ trunk/Source/_javascript_Core/ftl/FTLCommonValues.h 2013-07-25 03:59:06 UTC (rev 153133)
@@ -48,9 +48,11 @@
const LType int32;
const LType int64;
const LType intPtr;
+ const LType doubleType;
const LType ref32;
const LType ref64;
const LType refPtr;
+ const LType refDouble;
const LValue booleanTrue;
const LValue booleanFalse;
const LValue int32Zero;
@@ -62,6 +64,7 @@
const LValue intPtrFour;
const LValue intPtrEight;
const LValue intPtrPtr;
+ const LValue doubleZero;
LModule m_module;
};
Modified: trunk/Source/_javascript_Core/ftl/FTLCompile.cpp (153132 => 153133)
--- trunk/Source/_javascript_Core/ftl/FTLCompile.cpp 2013-07-25 03:59:04 UTC (rev 153132)
+++ trunk/Source/_javascript_Core/ftl/FTLCompile.cpp 2013-07-25 03:59:06 UTC (rev 153133)
@@ -55,9 +55,10 @@
char* error = 0;
LLVMMCJITCompilerOptions options;
- memset(&options, 0, sizeof(options));
+ LLVMInitializeMCJITCompilerOptions(&options, sizeof(options));
options.OptLevel = Options::llvmOptimizationLevel();
options.NoFramePointerElim = true;
+ options.CodeModel = LLVMCodeModelSmall;
if (LLVMCreateMCJITCompilerForModule(&engine, state.module, &options, sizeof(options), &error)) {
dataLog("FATAL: Could not create LLVM execution engine: ", error, "\n");
Modified: trunk/Source/_javascript_Core/ftl/FTLLowerDFGToLLVM.cpp (153132 => 153133)
--- trunk/Source/_javascript_Core/ftl/FTLLowerDFGToLLVM.cpp 2013-07-25 03:59:04 UTC (rev 153132)
+++ trunk/Source/_javascript_Core/ftl/FTLLowerDFGToLLVM.cpp 2013-07-25 03:59:06 UTC (rev 153133)
@@ -62,6 +62,7 @@
, m_localsBoolean(OperandsLike, state.graph.m_blocks[0]->variablesAtHead)
, m_locals32(OperandsLike, state.graph.m_blocks[0]->variablesAtHead)
, m_locals64(OperandsLike, state.graph.m_blocks[0]->variablesAtHead)
+ , m_localsDouble(OperandsLike, state.graph.m_blocks[0]->variablesAtHead)
, m_valueSources(OperandsLike, state.graph.m_blocks[0]->variablesAtHead)
, m_lastSetOperand(std::numeric_limits<int>::max())
, m_exitThunkGenerator(state)
@@ -86,6 +87,7 @@
m_localsBoolean[index] = buildAlloca(m_out.m_builder, m_out.boolean);
m_locals32[index] = buildAlloca(m_out.m_builder, m_out.int32);
m_locals64[index] = buildAlloca(m_out.m_builder, m_out.int64);
+ m_localsDouble[index] = buildAlloca(m_out.m_builder, m_out.doubleType);
}
m_initialization = appendBasicBlock(m_ftlState.function);
@@ -422,9 +424,8 @@
if (variable->shouldUnboxIfPossible()) {
if (variable->shouldUseDoubleFormat()) {
- // FIXME: implement doubles in FTL.
- // https://bugs.webkit.org/show_bug.cgi?id=113624
- RELEASE_ASSERT_NOT_REACHED();
+ m_doubleValues.add(m_node, m_out.get(m_localsDouble.operand(variable->local())));
+ return;
}
// Locals that are marked shouldUnboxIfPossible() that aren't also forced to
@@ -456,9 +457,12 @@
if (variable->shouldUnboxIfPossible()) {
if (variable->shouldUseDoubleFormat()) {
- // FIXME: implement doubles in FTL.
- // https://bugs.webkit.org/show_bug.cgi?id=113624
- RELEASE_ASSERT_NOT_REACHED();
+ LValue value = lowDouble(m_node->child1());
+ m_out.set(value, m_localsDouble.operand(variable->local()));
+ if (needsFlushing) {
+ m_out.storeDouble(value, addressFor(variable->local()));
+ m_valueSources.operand(variable->local()) = ValueSource(DoubleInJSStack);
+ }
return;
}
@@ -552,6 +556,13 @@
break;
}
+ case NumberUse: {
+ m_doubleValues.add(
+ m_node,
+ m_out.doubleAdd(lowDouble(m_node->child1()), lowDouble(m_node->child2())));
+ break;
+ }
+
default:
RELEASE_ASSERT_NOT_REACHED();
break;
@@ -576,6 +587,13 @@
break;
}
+ case NumberUse: {
+ m_doubleValues.add(
+ m_node,
+ m_out.doubleSub(lowDouble(m_node->child1()), lowDouble(m_node->child2())));
+ break;
+ }
+
default:
RELEASE_ASSERT_NOT_REACHED();
break;
@@ -613,6 +631,13 @@
break;
}
+ case NumberUse: {
+ m_doubleValues.add(
+ m_node,
+ m_out.doubleMul(lowDouble(m_node->child1()), lowDouble(m_node->child2())));
+ break;
+ }
+
default:
RELEASE_ASSERT_NOT_REACHED();
break;
@@ -640,6 +665,11 @@
break;
}
+ case NumberUse: {
+ m_doubleValues.add(m_node, m_out.doubleNeg(lowDouble(m_node->child1())));
+ break;
+ }
+
default:
RELEASE_ASSERT_NOT_REACHED();
break;
@@ -693,15 +723,13 @@
void compileUInt32ToNumber()
{
+ LValue value = lowInt32(m_node->child1());
+
if (!nodeCanSpeculateInteger(m_node->arithNodeFlags())) {
- // FIXME: implement doubles in FTL.
- // https://bugs.webkit.org/show_bug.cgi?id=113624
-
- RELEASE_ASSERT_NOT_REACHED();
+ m_doubleValues.add(m_node, m_out.unsignedToDouble(value));
return;
}
- LValue value = lowInt32(m_node->child1());
speculateForward(
Overflow, noValue(), 0, m_out.lessThan(value, m_out.int32Zero),
FormattedValue(ValueFormatUInt32, value));
@@ -821,6 +849,36 @@
break;
}
+ case Array::Double: {
+ if (m_node->arrayMode().isInBounds()) {
+ if (m_node->arrayMode().isSaneChain()) {
+ // FIXME: Implement structure transition watchpoints.
+ // https://bugs.webkit.org/show_bug.cgi?id=113647
+ }
+
+ speculate(
+ OutOfBounds, noValue(), 0,
+ m_out.aboveOrEqual(
+ index, m_out.load32(storage, m_heaps.Butterfly_publicLength)));
+
+ LValue result = m_out.loadDouble(m_out.baseIndex(
+ m_heaps.indexedDoubleProperties,
+ storage, m_out.zeroExt(index, m_out.intPtr),
+ m_state.forNode(m_node->child2()).m_value));
+
+ if (!m_node->arrayMode().isSaneChain()) {
+ speculate(
+ LoadFromHole, noValue(), 0,
+ m_out.doubleNotEqualOrUnordered(result, result));
+ }
+ m_doubleValues.add(m_node, result);
+ break;
+ }
+
+ RELEASE_ASSERT_NOT_REACHED();
+ break;
+ }
+
default:
RELEASE_ASSERT_NOT_REACHED();
break;
@@ -874,6 +932,12 @@
return;
}
+ if (m_node->isBinaryUseKind(NumberUse)) {
+ m_booleanValues.add(
+ m_node,
+ m_out.doubleEqual(lowDouble(m_node->child1()), lowDouble(m_node->child2())));
+ }
+
if (m_node->isBinaryUseKind(ObjectUse)) {
m_booleanValues.add(
m_node,
@@ -893,6 +957,12 @@
return;
}
+ if (m_node->isBinaryUseKind(NumberUse)) {
+ m_booleanValues.add(
+ m_node,
+ m_out.doubleLessThan(lowDouble(m_node->child1()), lowDouble(m_node->child2())));
+ }
+
RELEASE_ASSERT_NOT_REACHED();
}
@@ -1042,6 +1112,57 @@
return m_out.booleanFalse;
}
+ LValue lowDouble(Edge edge, OperandSpeculationMode mode = AutomaticOperandSpeculation)
+ {
+ ASSERT_UNUSED(mode, mode == ManualOperandSpeculation || isDouble(edge.useKind()));
+
+ if (LValue result = m_doubleValues.get(edge.node()))
+ return result;
+
+ if (LValue intResult = m_int32Values.get(edge.node())) {
+ LValue result = m_out.intToDouble(intResult);
+ m_doubleValues.add(edge.node(), result);
+ return result;
+ }
+
+ if (LValue boxedResult = m_jsValueValues.get(edge.node())) {
+ LBasicBlock intCase = FTL_NEW_BLOCK(m_out, ("Double unboxing int case"));
+ LBasicBlock doubleCase = FTL_NEW_BLOCK(m_out, ("Double unboxing double case"));
+ LBasicBlock continuation = FTL_NEW_BLOCK(m_out, ("Double unboxing continuation"));
+
+ m_out.branch(isNotInt32(boxedResult), doubleCase, intCase);
+
+ LBasicBlock lastNext = m_out.appendTo(intCase, doubleCase);
+
+ LValue intToDouble = m_out.intToDouble(unboxInt32(boxedResult));
+ LBasicBlock intToDoubleBlock = m_out.m_block;
+ m_out.jump(continuation);
+
+ m_out.appendTo(doubleCase, continuation);
+
+ FTL_TYPE_CHECK(
+ jsValueValue(boxedResult), edge, SpecNumber, isCellOrMisc(boxedResult));
+
+ LValue unboxedDouble = unboxDouble(boxedResult);
+ LBasicBlock unboxedDoubleBlock = m_out.m_block;
+ m_out.jump(continuation);
+
+ m_out.appendTo(continuation, lastNext);
+
+ LValue result = m_out.phi(
+ m_out.doubleType,
+ intToDouble, intToDoubleBlock,
+ unboxedDouble, unboxedDoubleBlock);
+
+ m_doubleValues.add(edge.node(), result);
+ return result;
+ }
+
+ RELEASE_ASSERT(!(m_state.forNode(edge).m_type & SpecNumber));
+ terminate(Uncountable);
+ return m_out.doubleZero;
+ }
+
LValue lowJSValue(Edge edge, OperandSpeculationMode mode = AutomaticOperandSpeculation)
{
ASSERT_UNUSED(mode, mode == ManualOperandSpeculation || edge.useKind() == UntypedUse);
@@ -1061,6 +1182,12 @@
return result;
}
+ if (LValue unboxedResult = m_doubleValues.get(edge.node())) {
+ LValue result = boxDouble(unboxedResult);
+ m_jsValueValues.add(edge.node(), result);
+ return result;
+ }
+
RELEASE_ASSERT_NOT_REACHED();
return 0;
}
@@ -1088,6 +1215,19 @@
return m_out.add(m_out.zeroExt(value, m_out.int64), m_tagTypeNumber);
}
+ LValue isCellOrMisc(LValue jsValue)
+ {
+ return m_out.testIsZero64(jsValue, m_tagTypeNumber);
+ }
+ LValue unboxDouble(LValue jsValue)
+ {
+ return m_out.bitCast(m_out.add(jsValue, m_tagTypeNumber), m_out.doubleType);
+ }
+ LValue boxDouble(LValue doubleValue)
+ {
+ return m_out.sub(m_out.bitCast(doubleValue, m_out.int64), m_tagTypeNumber);
+ }
+
LValue isNotCell(LValue jsValue)
{
return m_out.testNonZero64(jsValue, m_tagMask);
@@ -1117,6 +1257,7 @@
case UntypedUse:
break;
case KnownInt32Use:
+ case KnownNumberUse:
ASSERT(!m_state.needsTypeCheck(edge));
break;
case Int32Use:
@@ -1131,6 +1272,12 @@
case ObjectUse:
speculateObject(edge);
break;
+ case RealNumberUse:
+ speculateRealNumber(edge);
+ break;
+ case NumberUse:
+ speculateNumber(edge);
+ break;
default:
RELEASE_ASSERT_NOT_REACHED();
}
@@ -1165,6 +1312,27 @@
speculateObject(edge, lowCell(edge));
}
+ void speculateNumber(Edge edge)
+ {
+ // Do an early return here because lowDouble() can create a lot of control flow.
+ if (!m_state.needsTypeCheck(edge))
+ return;
+
+ lowDouble(edge);
+ }
+
+ void speculateRealNumber(Edge edge)
+ {
+ // Do an early return here because lowDouble() can create a lot of control flow.
+ if (!m_state.needsTypeCheck(edge))
+ return;
+
+ LValue value = lowDouble(edge);
+ FTL_TYPE_CHECK(
+ doubleValue(value), edge, SpecRealNumber,
+ m_out.doubleNotEqualOrUnordered(value, value));
+ }
+
bool isLive(Node* node)
{
HashMap<Node*, unsigned>::iterator iter = m_timeToLive.find(node);
@@ -1315,9 +1483,8 @@
exit, arguments, i, ValueFormatBoolean, m_out.get(m_localsBoolean[i]));
break;
case DoubleInLocals:
- // FIXME: implement doubles in FTL.
- // https://bugs.webkit.org/show_bug.cgi?id=113624
- RELEASE_ASSERT_NOT_REACHED();
+ addExitArgument(
+ exit, arguments, i, ValueFormatDouble, m_out.get(m_localsDouble[i]));
break;
case ArgumentsSource:
// FIXME: implement PhantomArguments.
@@ -1454,8 +1621,11 @@
return;
}
- // FIXME: Implement doubles in the FTL.
- // https://bugs.webkit.org/show_bug.cgi?id=113624
+ if (LValue result = m_doubleValues.get(node)) {
+ addExitArgument(exit, arguments, index, ValueFormatDouble, result);
+ return;
+ }
+
RELEASE_ASSERT_NOT_REACHED();
}
@@ -1600,11 +1770,13 @@
HashMap<Node*, LValue> m_jsValueValues;
HashMap<Node*, LValue> m_booleanValues;
HashMap<Node*, LValue> m_storageValues;
+ HashMap<Node*, LValue> m_doubleValues;
HashMap<Node*, unsigned> m_timeToLive;
Operands<LValue> m_localsBoolean;
Operands<LValue> m_locals32;
Operands<LValue> m_locals64;
+ Operands<LValue> m_localsDouble;
Operands<ValueSource> m_valueSources;
int m_lastSetOperand;
Modified: trunk/Source/_javascript_Core/ftl/FTLOutput.h (153132 => 153133)
--- trunk/Source/_javascript_Core/ftl/FTLOutput.h 2013-07-25 03:59:04 UTC (rev 153132)
+++ trunk/Source/_javascript_Core/ftl/FTLOutput.h 2013-07-25 03:59:06 UTC (rev 153133)
@@ -109,11 +109,28 @@
template<typename T>
LValue constIntPtr(T value) { return constInt(intPtr, bitwise_cast<intptr_t>(value), SignExtend); }
LValue constInt64(int64_t value) { return constInt(int64, value, SignExtend); }
+ LValue constDouble(double value) { return constReal(doubleType, value); }
+ LValue phi(LType type) { return buildPhi(m_builder, type); }
+ LValue phi(LType type, LValue value1, LBasicBlock block1)
+ {
+ return buildPhi(m_builder, type, value1, block1);
+ }
+ LValue phi(LType type, LValue value1, LBasicBlock block1, LValue value2, LBasicBlock block2)
+ {
+ return buildPhi(m_builder, type, value1, block1, value2, block2);
+ }
+
LValue add(LValue left, LValue right) { return buildAdd(m_builder, left, right); }
LValue sub(LValue left, LValue right) { return buildSub(m_builder, left, right); }
LValue mul(LValue left, LValue right) { return buildMul(m_builder, left, right); }
LValue neg(LValue value) { return buildNeg(m_builder, value); }
+
+ LValue doubleAdd(LValue left, LValue right) { return buildFAdd(m_builder, left, right); }
+ LValue doubleSub(LValue left, LValue right) { return buildFSub(m_builder, left, right); }
+ LValue doubleMul(LValue left, LValue right) { return buildFMul(m_builder, left, right); }
+ LValue doubleNeg(LValue value) { return buildFNeg(m_builder, value); }
+
LValue bitAnd(LValue left, LValue right) { return buildAnd(m_builder, left, right); }
LValue bitOr(LValue left, LValue right) { return buildOr(m_builder, left, right); }
LValue bitXor(LValue left, LValue right) { return buildXor(m_builder, left, right); }
@@ -135,9 +152,14 @@
}
LValue zeroExt(LValue value, LType type) { return buildZExt(m_builder, value, type); }
+ LValue intToFP(LValue value, LType type) { return buildSIToFP(m_builder, value, type); }
+ LValue intToDouble(LValue value) { return intToFP(value, doubleType); }
+ LValue unsignedToFP(LValue value, LType type) { return buildUIToFP(m_builder, value, type); }
+ LValue unsignedToDouble(LValue value) { return unsignedToFP(value, doubleType); }
LValue intCast(LValue value, LType type) { return buildIntCast(m_builder, value, type); }
LValue castToInt32(LValue value) { return intCast(value, int32); }
LValue intToPtr(LValue value, LType type) { return buildIntToPtr(m_builder, value, type); }
+ LValue bitCast(LValue value, LType type) { return buildBitCast(m_builder, value, type); }
LValue get(LValue reference) { return buildLoad(m_builder, reference); }
LValue set(LValue value, LValue reference) { return buildStore(m_builder, value, reference); }
@@ -157,9 +179,11 @@
LValue load32(TypedPointer pointer) { return load(pointer, ref32); }
LValue load64(TypedPointer pointer) { return load(pointer, ref64); }
LValue loadPtr(TypedPointer pointer) { return load(pointer, refPtr); }
+ LValue loadDouble(TypedPointer pointer) { return load(pointer, refDouble); }
void store32(LValue value, TypedPointer pointer) { store(value, pointer, ref32); }
void store64(LValue value, TypedPointer pointer) { store(value, pointer, ref64); }
void storePtr(LValue value, TypedPointer pointer) { store(value, pointer, refPtr); }
+ void storeDouble(LValue value, TypedPointer pointer) { store(value, pointer, refDouble); }
LValue addPtr(LValue value, ptrdiff_t immediate = 0)
{
@@ -239,9 +263,23 @@
LValue lessThan(LValue left, LValue right) { return buildICmp(m_builder, LLVMIntSLT, left, right); }
LValue lessThanOrEqual(LValue left, LValue right) { return buildICmp(m_builder, LLVMIntSLE, left, right); }
+ LValue doubleEqual(LValue left, LValue right) { return buildFCmp(m_builder, LLVMRealOEQ, left, right); }
+ LValue doubleNotEqualOrUnordered(LValue left, LValue right) { return buildFCmp(m_builder, LLVMRealUNE, left, right); }
+ LValue doubleLessThan(LValue left, LValue right) { return buildFCmp(m_builder, LLVMRealOLT, left, right); }
+ LValue doubleLessThanOrEqual(LValue left, LValue right) { return buildFCmp(m_builder, LLVMRealOLE, left, right); }
+ LValue doubleGreaterThan(LValue left, LValue right) { return buildFCmp(m_builder, LLVMRealOGT, left, right); }
+ LValue doubleGreaterThanOrEqual(LValue left, LValue right) { return buildFCmp(m_builder, LLVMRealOGE, left, right); }
+ LValue doubleEqualOrUnordered(LValue left, LValue right) { return buildFCmp(m_builder, LLVMRealUEQ, left, right); }
+ LValue doubleNotEqual(LValue left, LValue right) { return buildFCmp(m_builder, LLVMRealONE, left, right); }
+ LValue doubleLessThanOrUnordered(LValue left, LValue right) { return buildFCmp(m_builder, LLVMRealULT, left, right); }
+ LValue doubleLessThanOrEqualOrUnordered(LValue left, LValue right) { return buildFCmp(m_builder, LLVMRealULE, left, right); }
+ LValue doubleGreaterThanOrUnordered(LValue left, LValue right) { return buildFCmp(m_builder, LLVMRealUGT, left, right); }
+ LValue doubleGreaterThanOrEqualOrUnordered(LValue left, LValue right) { return buildFCmp(m_builder, LLVMRealUGE, left, right); }
+
LValue isZero64(LValue value) { return equal(value, int64Zero); }
LValue notZero64(LValue value) { return notEqual(value, int64Zero); }
+ LValue testIsZero64(LValue value, LValue mask) { return isZero64(bitAnd(value, mask)); }
LValue testNonZero64(LValue value, LValue mask) { return notZero64(bitAnd(value, mask)); }
LValue select(LValue value, LValue taken, LValue notTaken) { return buildSelect(m_builder, value, taken, notTaken); }