--- a/js/src/ion/CodeGenerator.cpp
+++ b/js/src/ion/CodeGenerator.cpp
@@ -38,16 +38,17 @@
* the terms of any one of the MPL, the GPL or the LGPL.
*
* ***** END LICENSE BLOCK ***** */
#include "CodeGenerator.h"
#include "IonLinker.h"
#include "MIRGenerator.h"
#include "shared/CodeGenerator-shared-inl.h"
+#include "jsnum.h"
using namespace js;
using namespace js::ion;
CodeGenerator::CodeGenerator(MIRGenerator *gen, LIRGraph &graph)
: CodeGeneratorSpecific(gen, graph)
{
}
@@ -98,16 +99,69 @@ CodeGenerator::visitValueToInt32(LValueT
masm.bind(&isInt32);
masm.unboxInt32(operand, output);
masm.bind(&done);
return true;
}
+static const double DoubleZero = 0.0;
+
+bool
+CodeGenerator::visitValueToDouble(LValueToDouble *lir)
+{
+ ValueOperand operand = ToValue(lir, LValueToDouble::Input);
+ FloatRegister output = ToFloatRegister(lir->output());
+
+ Assembler::Condition cond;
+ Label isDouble, isInt32, isBool, isNull, done;
+
+ // Type-check switch.
+ cond = masm.testDouble(Assembler::Equal, operand);
+ masm.j(cond, &isDouble);
+ cond = masm.testInt32(Assembler::Equal, operand);
+ masm.j(cond, &isInt32);
+ cond = masm.testBoolean(Assembler::Equal, operand);
+ masm.j(cond, &isBool);
+ cond = masm.testNull(Assembler::Equal, operand);
+ masm.j(cond, &isNull);
+
+ cond = masm.testUndefined(Assembler::NotEqual, operand);
+ if (!bailoutIf(cond, lir->snapshot()))
+ return false;
+ masm.loadStaticDouble(&js_NaN, output);
+ masm.jump(&done);
+
+ masm.bind(&isNull);
+ masm.loadStaticDouble(&DoubleZero, output);
+ masm.jump(&done);
+
+ masm.bind(&isBool);
+ masm.boolValueToDouble(operand, output);
+ masm.jump(&done);
+
+ masm.bind(&isInt32);
+ masm.int32ValueToDouble(operand, output);
+ masm.jump(&done);
+
+ masm.bind(&isDouble);
+ masm.unboxDouble(operand, output);
+ masm.bind(&done);
+
+ return true;
+}
+
+bool
+CodeGenerator::visitInt32ToDouble(LInt32ToDouble *lir)
+{
+ masm.convertInt32ToDouble(ToRegister(lir->input()), ToFloatRegister(lir->output()));
+ return true;
+}
+
bool
CodeGenerator::generateBody()
{
for (size_t i = 0; i < graph.numBlocks(); i++) {
current = graph.getBlock(i);
masm.bind(current->label());
for (LInstructionIterator iter = current->begin(); iter != current->end(); iter++) {
if (!iter->accept(this))
--- a/js/src/ion/CodeGenerator.h
+++ b/js/src/ion/CodeGenerator.h
@@ -57,15 +57,17 @@ class CodeGenerator : public CodeGenerat
public:
CodeGenerator(MIRGenerator *gen, LIRGraph &graph);
public:
bool generate();
virtual bool visitValueToInt32(LValueToInt32 *lir);
+ virtual bool visitValueToDouble(LValueToDouble *lir);
+ virtual bool visitInt32ToDouble(LInt32ToDouble *lir);
};
} // namespace ion
} // namespace js
#endif // jsion_codegen_h__
--- a/js/src/ion/LIR-Common.h
+++ b/js/src/ion/LIR-Common.h
@@ -296,22 +296,42 @@ class LMathD : public LInstructionHelper
: jsop_(jsop)
{ }
JSOp jsop() const {
return jsop_;
}
};
+// Convert a 32-bit integer to a double.
+class LInt32ToDouble : public LInstructionHelper<1, 1, 0>
+{
+ public:
+ LIR_HEADER(Int32ToDouble);
+
+ LInt32ToDouble(const LAllocation &input) {
+ setOperand(0, input);
+ }
+
+ const LAllocation *input() {
+ return getOperand(0);
+ }
+ const LDefinition *output() {
+ return getDef(0);
+ }
+};
+
// Convert a value to a double.
class LValueToDouble : public LInstructionHelper<1, BOX_PIECES, 0>
{
public:
LIR_HEADER(ValueToDouble);
+ static const size_t Input = 0;
+
const LDefinition *output() {
return getDef(0);
}
};
// Convert a value to an int32.
// Input: components of a Value
// Output: 32-bit integer
--- a/js/src/ion/LOpcodes.h
+++ b/js/src/ion/LOpcodes.h
@@ -55,16 +55,17 @@
_(BitOp) \
_(Return) \
_(Phi) \
_(TestIAndBranch) \
_(TestDAndBranch) \
_(TestVAndBranch) \
_(AddI) \
_(MathD) \
+ _(Int32ToDouble) \
_(ValueToDouble) \
_(ValueToInt32)
#if defined(JS_CPU_X86)
# include "x86/LOpcodes-x86.h"
#elif defined(JS_CPU_X64)
# include "x64/LOpcodes-x64.h"
#elif defined(JS_CPU_ARM)
--- a/js/src/ion/Lowering.cpp
+++ b/js/src/ion/Lowering.cpp
@@ -236,17 +236,48 @@ LIRGenerator::visitStart(MStart *start)
{
// This is a no-op.
return true;
}
bool
LIRGenerator::visitToDouble(MToDouble *convert)
{
- JS_NOT_REACHED("NYI");
+ MDefinition *opd = convert->input();
+
+ switch (opd->type()) {
+ case MIRType_Value:
+ {
+ LValueToDouble *lir = new LValueToDouble();
+ if (!useBox(lir, LValueToDouble::Input, opd))
+ return false;
+ return define(lir, convert) && assignSnapshot(lir);
+ }
+
+ case MIRType_Null:
+ return lowerConstantDouble(0, convert);
+
+ case MIRType_Undefined:
+ return lowerConstantDouble(js_NaN, convert);
+
+ case MIRType_Int32:
+ case MIRType_Boolean:
+ {
+ LInt32ToDouble *lir = new LInt32ToDouble(useRegister(opd));
+ return define(lir, convert);
+ }
+
+ case MIRType_Double:
+ return redefine(convert, opd);
+
+ default:
+ // Objects might not be idempotent.
+ // Strings are complicated - we don't handle them yet.
+ JS_NOT_REACHED("unexpected type");
+ }
return false;
}
bool
LIRGenerator::visitToInt32(MToInt32 *convert)
{
MDefinition *opd = convert->input();
--- a/js/src/ion/shared/Assembler-x86-shared.h
+++ b/js/src/ion/shared/Assembler-x86-shared.h
@@ -547,16 +547,29 @@ class AssemblerX86Shared
break;
default:
JS_NOT_REACHED("unexpected operand kind");
}
}
void psrlq(Imm32 shift, const FloatRegister &dest) {
masm.psrldq_rr(dest.code(), shift.value);
}
+
+ void cvtsi2sd(const Operand &src, const FloatRegister &dest) {
+ switch (src.kind()) {
+ case Operand::REG:
+ masm.cvtsi2sd_rr(src.reg(), dest.code());
+ break;
+ case Operand::REG_DISP:
+ masm.cvtsi2sd_mr(src.disp(), src.base(), dest.code());
+ break;
+ default:
+ JS_NOT_REACHED("unexpected operand kind");
+ }
+ }
void cvttsd2si(const FloatRegister &src, const Register &dest) {
masm.cvttsd2si_rr(src.code(), dest.code());
}
void cvtsi2sd(const Register &src, const FloatRegister &dest) {
masm.cvtsi2sd_rr(src.code(), dest.code());
}
void movmskpd(const FloatRegister &src, const Register &dest) {
masm.movmskpd_rr(src.code(), dest.code());
--- a/js/src/ion/shared/MacroAssembler-x86-shared.h
+++ b/js/src/ion/shared/MacroAssembler-x86-shared.h
@@ -66,16 +66,19 @@ class MacroAssemblerX86Shared : public A
: framePushed_(0)
{ }
void Push(const Register ®) {
push(reg);
framePushed_ += STACK_SLOT_SIZE;
}
+ void convertInt32ToDouble(const Register &src, const FloatRegister &dest) {
+ cvtsi2sd(Operand(src), dest);
+ }
void jump(Label *label) {
jmp(label);
}
uint32 framePushed() const {
return framePushed_;
}
};
--- a/js/src/ion/x64/CodeGenerator-x64.cpp
+++ b/js/src/ion/x64/CodeGenerator-x64.cpp
@@ -57,27 +57,17 @@ CodeGeneratorX64::ToValue(LInstruction *
{
return ValueOperand(ToRegister(ins->getOperand(pos)));
}
bool
CodeGeneratorX64::visitDouble(LDouble *ins)
{
const LDefinition *out = ins->output();
-
- jsdpun dpun;
- dpun.d = ins->getDouble();
-
- if (dpun.u64 == 0) {
- masm.xorpd(ToFloatRegister(out), ToFloatRegister(out));
- return true;
- }
-
- masm.movq(ImmWord(dpun.u64), ScratchReg);
- masm.movqsd(ScratchReg, ToFloatRegister(out));
+ masm.loadDouble(ins->getDouble(), ToFloatRegister(out));
return true;
}
FrameSizeClass
FrameSizeClass::FromDepth(uint32 frameDepth)
{
return FrameSizeClass::None();
}
--- a/js/src/ion/x64/MacroAssembler-x64.h
+++ b/js/src/ion/x64/MacroAssembler-x64.h
@@ -38,16 +38,17 @@
* the terms of any one of the MPL, the GPL or the LGPL.
*
* ***** END LICENSE BLOCK ***** */
#ifndef jsion_macro_assembler_x64_h__
#define jsion_macro_assembler_x64_h__
#include "ion/shared/MacroAssembler-x86-shared.h"
+#include "jsnum.h"
namespace js {
namespace ion {
struct ImmShiftedTag : public ImmWord
{
ImmShiftedTag(JSValueShiftedTag shtag)
: ImmWord((uintptr_t)shtag)
@@ -144,26 +145,53 @@ class MacroAssemblerX64 : public MacroAs
cmpq(src.value(), ScratchReg);
return (cond == NotEqual) ? Above : BelowOrEqual;
}
Condition testNull(Condition cond, const ValueOperand &src) {
JS_ASSERT(cond == Equal || cond == NotEqual);
cmpTag(src, ImmTag(JSVAL_TAG_NULL));
return cond;
}
+ Condition testUndefined(Condition cond, const ValueOperand &src) {
+ JS_ASSERT(cond == Equal || cond == NotEqual);
+ cmpTag(src, ImmTag(JSVAL_TAG_UNDEFINED));
+ return cond;
+ }
void unboxInt32(const ValueOperand &src, const Register &dest) {
movl(src.value(), dest);
}
void unboxBoolean(const ValueOperand &src, const Register &dest) {
movl(src.value(), dest);
}
void unboxDouble(const ValueOperand &src, const FloatRegister &dest) {
movqsd(src.valueReg(), dest);
}
+
+ // These two functions use the low 32-bits of the full value register.
+ void boolValueToDouble(const ValueOperand &operand, const FloatRegister &dest) {
+ cvtsi2sd(operand.value(), dest);
+ }
+ void int32ValueToDouble(const ValueOperand &operand, const FloatRegister &dest) {
+ cvtsi2sd(operand.value(), dest);
+ }
+
+ void loadDouble(double d, const FloatRegister &dest) {
+ jsdpun dpun;
+ dpun.d = d;
+ if (dpun.u64 == 0) {
+ xorpd(dest, dest);
+ } else {
+ movq(ImmWord(dpun.u64), ScratchReg);
+ movqsd(ScratchReg, dest);
+ }
+ }
+ void loadStaticDouble(const double *dp, const FloatRegister &dest) {
+ loadDouble(*dp, dest);
+ }
};
typedef MacroAssemblerX64 MacroAssemblerSpecific;
} // namespace ion
} // namespace js
#endif // jsion_macro_assembler_x64_h__
--- a/js/src/ion/x86/Assembler-x86.h
+++ b/js/src/ion/x86/Assembler-x86.h
@@ -253,16 +253,19 @@ class Assembler : public AssemblerX86Sha
JmpSrc src = masm.jmp();
addPendingJump(src, target, reloc);
}
void j(Condition cond, void *target, Relocation::Kind reloc) {
JmpSrc src = masm.jCC(static_cast<JSC::X86Assembler::Condition>(cond));
addPendingJump(src, target, reloc);
}
+ void movsd(const double *dp, const FloatRegister &dest) {
+ masm.movsd_mr((const void *)dp, dest.code());
+ }
void movsd(AbsoluteLabel *label, const FloatRegister &dest) {
JS_ASSERT(!label->bound());
// Thread the patch list through the unpatched address word in the
// instruction stream.
masm.movsd_mr(reinterpret_cast<void *>(label->prev()), dest.code());
label->setPrev(masm.size());
}
};
--- a/js/src/ion/x86/MacroAssembler-x86.h
+++ b/js/src/ion/x86/MacroAssembler-x86.h
@@ -120,16 +120,21 @@ class MacroAssemblerX86 : public MacroAs
cmpl(ImmTag(JSVAL_TAG_CLEAR), value.typeReg());
return actual;
}
Condition testNull(Condition cond, const ValueOperand &value) {
JS_ASSERT(cond == Assembler::Equal || cond == Assembler::NotEqual);
cmpl(ImmType(JSVAL_TYPE_NULL), value.typeReg());
return cond;
}
+ Condition testUndefined(Condition cond, const ValueOperand &value) {
+ JS_ASSERT(cond == Assembler::Equal || cond == Assembler::NotEqual);
+ cmpl(ImmType(JSVAL_TYPE_UNDEFINED), value.typeReg());
+ return cond;
+ }
void unboxInt32(const ValueOperand &operand, const Register &dest) {
movl(operand.payloadReg(), dest);
}
void unboxBoolean(const ValueOperand &operand, const Register &dest) {
movl(operand.payloadReg(), dest);
}
void unboxDouble(const ValueOperand &operand, const FloatRegister &dest) {
@@ -138,16 +143,27 @@ class MacroAssemblerX86 : public MacroAs
movd(operand.payloadReg(), dest);
pinsrd(operand.typeReg(), dest);
} else {
movd(operand.payloadReg(), dest);
movd(operand.typeReg(), ScratchFloatReg);
unpcklps(ScratchFloatReg, dest);
}
}
+
+ void boolValueToDouble(const ValueOperand &operand, const FloatRegister &dest) {
+ cvtsi2sd(operand.payloadReg(), dest);
+ }
+ void int32ValueToDouble(const ValueOperand &operand, const FloatRegister &dest) {
+ cvtsi2sd(operand.payloadReg(), dest);
+ }
+
+ void loadStaticDouble(const double *dp, const FloatRegister &dest) {
+ movsd(dp, dest);
+ }
};
typedef MacroAssemblerX86 MacroAssemblerSpecific;
} // namespace ion
} // namespace js
#endif // jsion_macro_assembler_x86_h__
--- a/js/src/jsgc.cpp
+++ b/js/src/jsgc.cpp
@@ -236,17 +236,17 @@ Arena::finalize(JSContext *cx)
#ifdef DEBUG
nmarked++;
#endif
if (newFreeSpanStart) {
JS_ASSERT(thing >= thingsStart(sizeof(T)) + sizeof(T));
newListTail->first = newFreeSpanStart;
newListTail->last = thing - sizeof(T);
newListTail = newListTail->nextSpanUnchecked(sizeof(T));
- newFreeSpanStart = NULL;
+ newFreeSpanStart = 0;
}
} else {
if (!newFreeSpanStart)
newFreeSpanStart = thing;
t->finalize(cx);
memset(t, JS_FREE_PATTERN, sizeof(T));
}
}