Skip to content

Instantly share code, notes, and snippets.

@evilpie
Created July 30, 2012 18:30
Show Gist options
  • Save evilpie/3208984 to your computer and use it in GitHub Desktop.
Save evilpie/3208984 to your computer and use it in GitHub Desktop.
diff --git a/js/src/ion/CodeGenerator.cpp b/js/src/ion/CodeGenerator.cpp
--- a/js/src/ion/CodeGenerator.cpp
+++ b/js/src/ion/CodeGenerator.cpp
@@ -133,16 +133,24 @@ CodeGenerator::visitValueToDouble(LValue
bool
CodeGenerator::visitInt32ToDouble(LInt32ToDouble *lir)
{
masm.convertInt32ToDouble(ToRegister(lir->input()), ToFloatRegister(lir->output()));
return true;
}
+
+bool
+CodeGenerator::visitUint32ToDouble(LUint32ToDouble *lir)
+{
+ masm.convertUint32ToDouble(ToRegister(lir->input()), ToFloatRegister(lir->output()));
+ return true;
+}
+
bool
CodeGenerator::visitDoubleToInt32(LDoubleToInt32 *lir)
{
Label fail;
FloatRegister input = ToFloatRegister(lir->input());
Register output = ToRegister(lir->output());
emitDoubleToInt32(input, output, &fail, lir->mir()->canBeNegativeZero());
if (!bailoutFrom(&fail, lir->snapshot()))
@@ -3378,34 +3386,29 @@ CodeGenerator::visitLoadElementHole(LLoa
masm.bind(&done);
return true;
}
bool
CodeGenerator::visitLoadTypedArrayElement(LLoadTypedArrayElement *lir)
{
Register elements = ToRegister(lir->elements());
- Register temp = lir->temp()->isBogusTemp() ? InvalidReg : ToRegister(lir->temp());
AnyRegister out = ToAnyRegister(lir->output());
int arrayType = lir->mir()->arrayType();
int shift = TypedArray::slotWidth(arrayType);
Label fail;
if (lir->index()->isConstant()) {
Address source(elements, ToInt32(lir->index()) * shift);
- masm.loadFromTypedArray(arrayType, source, out, temp, &fail);
+ masm.loadFromTypedArray(arrayType, source, out);
} else {
BaseIndex source(elements, ToRegister(lir->index()), ScaleFromShift(shift));
- masm.loadFromTypedArray(arrayType, source, out, temp, &fail);
+ masm.loadFromTypedArray(arrayType, source, out);
}
-
- if (fail.used() && !bailoutFrom(&fail, lir->snapshot()))
- return false;
-
return true;
}
class OutOfLineLoadTypedArray : public OutOfLineCodeBase<CodeGenerator>
{
LLoadTypedArrayElementHole *ins_;
public:
diff --git a/js/src/ion/CodeGenerator.h b/js/src/ion/CodeGenerator.h
--- a/js/src/ion/CodeGenerator.h
+++ b/js/src/ion/CodeGenerator.h
@@ -51,16 +51,17 @@ class CodeGenerator : public CodeGenerat
bool visitReturn(LReturn *ret);
bool visitDefVar(LDefVar *lir);
bool visitOsrEntry(LOsrEntry *lir);
bool visitOsrScopeChain(LOsrScopeChain *lir);
bool visitStackArg(LStackArg *lir);
bool visitValueToInt32(LValueToInt32 *lir);
bool visitValueToDouble(LValueToDouble *lir);
bool visitInt32ToDouble(LInt32ToDouble *lir);
+ bool visitUint32ToDouble(LUint32ToDouble *lir);
bool visitTestVAndBranch(LTestVAndBranch *lir);
bool visitPolyInlineDispatch(LPolyInlineDispatch *lir);
bool visitIntToString(LIntToString *lir);
bool visitInteger(LInteger *lir);
bool visitRegExp(LRegExp *lir);
bool visitLambda(LLambda *lir);
bool visitLambdaForSingleton(LLambdaForSingleton *lir);
bool visitPointer(LPointer *lir);
diff --git a/js/src/ion/Ion.cpp b/js/src/ion/Ion.cpp
--- a/js/src/ion/Ion.cpp
+++ b/js/src/ion/Ion.cpp
@@ -1011,17 +1011,17 @@ ion::CanEnterAtBranch(JSContext *cx, JSS
// Mark as forbidden if frame can't be handled.
if (!CheckFrame(fp)) {
ForbidCompilation(script);
return Method_CantCompile;
}
// Attempt compilation. Returns Method_Compiled if already compiled.
JSFunction *fun = fp->isFunctionFrame() ? fp->fun() : NULL;
- MethodStatus status = Compile<TestCompiler>(cx, script, fun, pc, false);
+ MethodStatus status = ::Compile<TestCompiler>(cx, script, fun, pc, false);
if (status != Method_Compiled) {
if (status == Method_CantCompile)
ForbidCompilation(script);
return status;
}
if (script->ion->osrPc() != pc)
return Method_Skipped;
@@ -1063,17 +1063,17 @@ ion::CanEnter(JSContext *cx, JSScript *s
// Mark as forbidden if frame can't be handled.
if (!CheckFrame(fp)) {
ForbidCompilation(script);
return Method_CantCompile;
}
// Attempt compilation. Returns Method_Compiled if already compiled.
JSFunction *fun = fp->isFunctionFrame() ? fp->fun() : NULL;
- MethodStatus status = Compile<TestCompiler>(cx, script, fun, NULL, fp->isConstructing());
+ MethodStatus status = ::Compile<TestCompiler>(cx, script, fun, NULL, fp->isConstructing());
if (status != Method_Compiled) {
if (status == Method_CantCompile)
ForbidCompilation(script);
return status;
}
// This can GC, so afterward, script->ion is not guaranteed to be valid.
if (!cx->compartment->ionCompartment()->enterJIT(cx))
diff --git a/js/src/ion/IonBuilder.cpp b/js/src/ion/IonBuilder.cpp
--- a/js/src/ion/IonBuilder.cpp
+++ b/js/src/ion/IonBuilder.cpp
@@ -751,22 +751,24 @@ IonBuilder::inspectOpcode(JSOp op)
return pushConstant(UndefinedValue());
case JSOP_IFEQ:
return jsop_ifeq(JSOP_IFEQ);
case JSOP_BITNOT:
return jsop_bitnot();
+ case JSOP_URSH:
+ return jsop_ursh();
+
case JSOP_BITAND:
case JSOP_BITOR:
case JSOP_BITXOR:
case JSOP_LSH:
case JSOP_RSH:
- case JSOP_URSH:
return jsop_bitop(op);
case JSOP_ADD:
case JSOP_SUB:
case JSOP_MUL:
case JSOP_DIV:
case JSOP_MOD:
return jsop_binary(op);
@@ -2587,16 +2589,33 @@ IonBuilder::jsop_bitnot()
current->add(ins);
ins->infer(oracle->unaryOp(script, pc));
current->push(ins);
if (ins->isEffectful() && !resumeAfter(ins))
return false;
return true;
}
+
+bool
+IonBuilder::jsop_ursh()
+{
+ MDefinition *right = current->pop();
+ MDefinition *left = current->pop();
+ MUrsh *ins = MUrsh::New(left, right);
+
+ current->add(ins);
+ ins->infer(oracle->binaryOp(script, pc));
+
+ current->push(ins);
+ if (ins->isEffectful() && !resumeAfter(ins))
+ return false;
+ return true;
+}
+
bool
IonBuilder::jsop_bitop(JSOp op)
{
// Pop inputs.
MDefinition *right = current->pop();
MDefinition *left = current->pop();
MBinaryBitwiseInstruction *ins;
@@ -2616,20 +2635,16 @@ IonBuilder::jsop_bitop(JSOp op)
case JSOP_LSH:
ins = MLsh::New(left, right);
break;
case JSOP_RSH:
ins = MRsh::New(left, right);
break;
- case JSOP_URSH:
- ins = MUrsh::New(left, right);
- break;
-
default:
JS_NOT_REACHED("unexpected bitop");
return false;
}
current->add(ins);
ins->infer(oracle->binaryOp(script, pc));
@@ -4485,17 +4500,17 @@ IonBuilder::jsop_getelem_typed(int array
case TypedArray::TYPE_UINT8:
case TypedArray::TYPE_UINT8_CLAMPED:
case TypedArray::TYPE_INT16:
case TypedArray::TYPE_UINT16:
case TypedArray::TYPE_INT32:
knownType = MIRType_Int32;
break;
case TypedArray::TYPE_UINT32:
- knownType = allowDouble ? MIRType_Double : MIRType_Int32;
+ knownType = MIRType_Uint32;
break;
case TypedArray::TYPE_FLOAT32:
case TypedArray::TYPE_FLOAT64:
knownType = MIRType_Double;
break;
default:
JS_NOT_REACHED("Unknown typed array type");
return false;
@@ -4518,16 +4533,17 @@ IonBuilder::jsop_getelem_typed(int array
current->push(load);
load->setResultType(knownType);
// Note: we can ignore the type barrier here, we know the type must
// be valid and unbarriered.
JS_ASSERT_IF(knownType == MIRType_Int32, types->hasType(types::Type::Int32Type()));
JS_ASSERT_IF(knownType == MIRType_Double, types->hasType(types::Type::DoubleType()));
+ // XXX add assert back
return true;
} else {
// Assume we will read out-of-bound values. In this case the
// bounds check will be part of the instruction, and the instruction
// will always return a Value.
MLoadTypedArrayElementHole *load = MLoadTypedArrayElementHole::New(obj, id, arrayType, allowDouble);
current->add(load);
current->push(load);
diff --git a/js/src/ion/IonBuilder.h b/js/src/ion/IonBuilder.h
--- a/js/src/ion/IonBuilder.h
+++ b/js/src/ion/IonBuilder.h
@@ -285,16 +285,17 @@ class IonBuilder : public MIRGenerator
bool invalidatedIdempotentCache();
bool loadSlot(MDefinition *obj, Shape *shape, MIRType rvalType);
bool storeSlot(MDefinition *obj, Shape *shape, MDefinition *value, bool needsBarrier);
bool jsop_add(MDefinition *left, MDefinition *right);
bool jsop_bitnot();
+ bool jsop_ursh();
bool jsop_bitop(JSOp op);
bool jsop_binary(JSOp op);
bool jsop_binary(JSOp op, MDefinition *left, MDefinition *right);
bool jsop_pos();
bool jsop_neg();
bool jsop_defvar(uint32 index);
bool jsop_notearg();
bool jsop_funcall(uint32 argc);
diff --git a/js/src/ion/IonFrames.cpp b/js/src/ion/IonFrames.cpp
--- a/js/src/ion/IonFrames.cpp
+++ b/js/src/ion/IonFrames.cpp
@@ -730,16 +730,22 @@ SnapshotIterator::slotValue(const Slot &
return NullValue();
case SnapshotReader::JS_INT32:
return Int32Value(slot.int32Value());
case SnapshotReader::CONSTANT:
return ionScript_->getConstant(slot.constantIndex());
+ case SnapshotReader::UINT32_REG:
+ return NumberValue(machine_.read(slot.reg()));
+
+ case SnapshotReader::UINT32_STACK:
+ return NumberValue(ReadFrameSlot(fp_, slot.stackSlot()));
+
default:
JS_NOT_REACHED("huh?");
return UndefinedValue();
}
}
IonScript *
IonFrameIterator::ionScript() const
diff --git a/js/src/ion/IonMacroAssembler.cpp b/js/src/ion/IonMacroAssembler.cpp
--- a/js/src/ion/IonMacroAssembler.cpp
+++ b/js/src/ion/IonMacroAssembler.cpp
@@ -147,18 +147,17 @@ MacroAssembler::branchTestValueTruthy(co
cond = testDoubleTruthy(false, fr);
j(cond, &ifFalse);
jump(ifTrue);
bind(&ifFalse);
}
template<typename T>
void
-MacroAssembler::loadFromTypedArray(int arrayType, const T &src, AnyRegister dest, Register temp,
- Label *fail)
+MacroAssembler::loadFromTypedArray(int arrayType, const T &src, AnyRegister dest)
{
switch (arrayType) {
case TypedArray::TYPE_INT8:
load8SignExtend(src, dest.gpr());
break;
case TypedArray::TYPE_UINT8:
case TypedArray::TYPE_UINT8_CLAMPED:
load8ZeroExtend(src, dest.gpr());
@@ -168,24 +167,17 @@ MacroAssembler::loadFromTypedArray(int a
break;
case TypedArray::TYPE_UINT16:
load16ZeroExtend(src, dest.gpr());
break;
case TypedArray::TYPE_INT32:
load32(src, dest.gpr());
break;
case TypedArray::TYPE_UINT32:
- if (dest.isFloat()) {
- load32(src, temp);
- convertUInt32ToDouble(temp, dest.fpu());
- } else {
- load32(src, dest.gpr());
- test32(dest.gpr(), dest.gpr());
- j(Assembler::Signed, fail);
- }
+ load32(src, dest.gpr());
break;
case TypedArray::TYPE_FLOAT32:
case TypedArray::TYPE_FLOAT64:
{
if (arrayType == js::TypedArray::TYPE_FLOAT32)
loadFloatAsDouble(src, dest.fpu());
else
loadDouble(src, dest.fpu());
@@ -200,34 +192,32 @@ MacroAssembler::loadFromTypedArray(int a
break;
}
default:
JS_NOT_REACHED("Invalid typed array type");
break;
}
}
-template void MacroAssembler::loadFromTypedArray(int arrayType, const Address &src, AnyRegister dest,
- Register temp, Label *fail);
-template void MacroAssembler::loadFromTypedArray(int arrayType, const BaseIndex &src, AnyRegister dest,
- Register temp, Label *fail);
+template void MacroAssembler::loadFromTypedArray(int arrayType, const Address &src, AnyRegister dest);
+template void MacroAssembler::loadFromTypedArray(int arrayType, const BaseIndex &src, AnyRegister dest);
template<typename T>
void
MacroAssembler::loadFromTypedArray(int arrayType, const T &src, const ValueOperand &dest,
bool allowDouble, Label *fail)
{
switch (arrayType) {
case TypedArray::TYPE_INT8:
case TypedArray::TYPE_UINT8:
case TypedArray::TYPE_UINT8_CLAMPED:
case TypedArray::TYPE_INT16:
case TypedArray::TYPE_UINT16:
case TypedArray::TYPE_INT32:
- loadFromTypedArray(arrayType, src, AnyRegister(dest.scratchReg()), InvalidReg, NULL);
+ loadFromTypedArray(arrayType, src, AnyRegister(dest.scratchReg()));
tagValue(JSVAL_TYPE_INT32, dest.scratchReg(), dest);
break;
case TypedArray::TYPE_UINT32:
load32(src, dest.scratchReg());
test32(dest.scratchReg(), dest.scratchReg());
if (allowDouble) {
// If the value fits in an int32, store an int32 type tag.
// Else, convert the value to double and box it.
@@ -246,17 +236,17 @@ MacroAssembler::loadFromTypedArray(int a
} else {
// Bailout if the value does not fit in an int32.
j(Assembler::Signed, fail);
tagValue(JSVAL_TYPE_INT32, dest.scratchReg(), dest);
}
break;
case TypedArray::TYPE_FLOAT32:
case TypedArray::TYPE_FLOAT64:
- loadFromTypedArray(arrayType, src, AnyRegister(ScratchFloatReg), dest.scratchReg(), NULL);
+ loadFromTypedArray(arrayType, src, AnyRegister(ScratchFloatReg));
boxDouble(ScratchFloatReg, dest);
break;
default:
JS_NOT_REACHED("Invalid typed array type");
break;
}
}
diff --git a/js/src/ion/IonMacroAssembler.h b/js/src/ion/IonMacroAssembler.h
--- a/js/src/ion/IonMacroAssembler.h
+++ b/js/src/ion/IonMacroAssembler.h
@@ -248,16 +248,20 @@ class MacroAssembler : public MacroAssem
using MacroAssemblerSpecific::Push;
void Push(TypedOrValueRegister v) {
if (v.hasValue())
Push(v.valueReg());
else if (v.type() == MIRType_Double)
Push(v.typedReg().fpu());
+ else if (v.type() == MIRType_Uint32) {
+ convertUint32ToDouble(v.typedReg().gpr(), ScratchFloatReg);
+ Push(ScratchFloatReg); // XXX we shouldn't deoptimize that much
+ }
else
Push(ValueTypeFromMIRType(v.type()), v.typedReg().gpr());
}
void Push(ConstantOrRegister v) {
if (v.constant())
Push(v.value());
else
@@ -352,21 +356,20 @@ class MacroAssembler : public MacroAssem
jump(&done);
align(8);
bind(&done);
return nopJump;
}
template<typename T>
- void loadFromTypedArray(int arrayType, const T &src, AnyRegister dest, Register temp, Label *fail);
+ void loadFromTypedArray(int arrayType, const T &src, AnyRegister dest);
template<typename T>
- void loadFromTypedArray(int arrayType, const T &src, const ValueOperand &dest, bool allowDouble,
- Label *fail);
+ void loadFromTypedArray(int arrayType, const T &src, const ValueOperand &dest, bool allowDouble, Label *fail);
template<typename S, typename T>
void storeToTypedIntArray(int arrayType, const S &value, const T &dest) {
switch (arrayType) {
case TypedArray::TYPE_INT8:
case TypedArray::TYPE_UINT8:
case TypedArray::TYPE_UINT8_CLAMPED:
store8(value, dest);
diff --git a/js/src/ion/LIR-Common.h b/js/src/ion/LIR-Common.h
--- a/js/src/ion/LIR-Common.h
+++ b/js/src/ion/LIR-Common.h
@@ -1428,16 +1428,34 @@ class LInt32ToDouble : public LInstructi
const LAllocation *input() {
return getOperand(0);
}
const LDefinition *output() {
return getDef(0);
}
};
+// Convert a 32-bit unsigned integer to a double.
+class LUint32ToDouble : public LInstructionHelper<1, 1, 0>
+{
+ public:
+ LIR_HEADER(Uint32ToDouble);
+
+ LUint32ToDouble(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;
@@ -2182,21 +2200,19 @@ class LArrayPushT : public LInstructionH
};
// Load a typed value from a typed array's elements vector.
class LLoadTypedArrayElement : public LInstructionHelper<1, 2, 1>
{
public:
LIR_HEADER(LoadTypedArrayElement);
- LLoadTypedArrayElement(const LAllocation &elements, const LAllocation &index,
- const LDefinition &temp) {
+ LLoadTypedArrayElement(const LAllocation &elements, const LAllocation &index) {
setOperand(0, elements);
setOperand(1, index);
- setTemp(0, temp);
}
const MLoadTypedArrayElement *mir() const {
return mir_->toLoadTypedArrayElement();
}
const LAllocation *elements() {
return getOperand(0);
}
const LAllocation *index() {
diff --git a/js/src/ion/LIR.h b/js/src/ion/LIR.h
--- a/js/src/ion/LIR.h
+++ b/js/src/ion/LIR.h
@@ -507,16 +507,17 @@ class LDefinition
JS_ASSERT(policy() == LDefinition::MUST_REUSE_INPUT);
return output_.toConstantIndex()->index();
}
static inline Type TypeFrom(MIRType type) {
switch (type) {
case MIRType_Boolean:
case MIRType_Int32:
+ case MIRType_Uint32:
return LDefinition::GENERAL;
case MIRType_String:
case MIRType_Object:
return LDefinition::OBJECT;
case MIRType_Double:
return LDefinition::DOUBLE;
#if defined(JS_PUNBOX64)
case MIRType_Value:
diff --git a/js/src/ion/LOpcodes.h b/js/src/ion/LOpcodes.h
--- a/js/src/ion/LOpcodes.h
+++ b/js/src/ion/LOpcodes.h
@@ -71,16 +71,17 @@
_(MulI) \
_(MathD) \
_(ModD) \
_(BinaryV) \
_(Concat) \
_(CharCodeAt) \
_(FromCharCode) \
_(Int32ToDouble) \
+ _(Uint32ToDouble) \
_(ValueToDouble) \
_(ValueToInt32) \
_(DoubleToInt32) \
_(TruncateDToInt32) \
_(IntToString) \
_(Start) \
_(OsrEntry) \
_(OsrValue) \
diff --git a/js/src/ion/Lowering.cpp b/js/src/ion/Lowering.cpp
--- a/js/src/ion/Lowering.cpp
+++ b/js/src/ion/Lowering.cpp
@@ -580,39 +580,25 @@ LIRGenerator::visitBitXor(MBitXor *ins)
bool
LIRGenerator::lowerShiftOp(JSOp op, MInstruction *ins)
{
MDefinition *lhs = ins->getOperand(0);
MDefinition *rhs = ins->getOperand(1);
if (lhs->type() == MIRType_Int32 && rhs->type() == MIRType_Int32) {
LShiftOp *lir = new LShiftOp(op);
- if (op == JSOP_URSH) {
- MUrsh *ursh = ins->toUrsh();
- if (ursh->fallible() && !assignSnapshot(lir))
- return false;
- }
return lowerForShift(lir, ins, lhs, rhs);
}
- if (op == JSOP_URSH) {
- LBinaryV *lir = new LBinaryV(op);
- if (!useBox(lir, LBinaryV::LhsInput, lhs))
- return false;
- if (!useBox(lir, LBinaryV::RhsInput, rhs))
- return false;
- return defineVMReturn(lir, ins) && assignSafepoint(lir, ins);
- } else {
- LBitOpV *lir = new LBitOpV(op);
- if (!useBox(lir, LBitOpV::LhsInput, lhs))
- return false;
- if (!useBox(lir, LBitOpV::RhsInput, rhs))
- return false;
- return defineVMReturn(lir, ins) && assignSafepoint(lir, ins);
- }
+ LBitOpV *lir = new LBitOpV(op);
+ if (!useBox(lir, LBitOpV::LhsInput, lhs))
+ return false;
+ if (!useBox(lir, LBitOpV::RhsInput, rhs))
+ return false;
+ return defineVMReturn(lir, ins) && assignSafepoint(lir, ins);
}
bool
LIRGenerator::visitLsh(MLsh *ins)
{
return lowerShiftOp(JSOP_LSH, ins);
}
@@ -620,17 +606,30 @@ bool
LIRGenerator::visitRsh(MRsh *ins)
{
return lowerShiftOp(JSOP_RSH, ins);
}
bool
LIRGenerator::visitUrsh(MUrsh *ins)
{
- return lowerShiftOp(JSOP_URSH, ins);
+ MDefinition *lhs = ins->getOperand(0);
+ MDefinition *rhs = ins->getOperand(1);
+
+ if (lhs->type() == MIRType_Uint32 && rhs->type() == MIRType_Uint32) {
+ LShiftOp *lir = new LShiftOp(JSOP_URSH);
+ return lowerForShift(lir, ins, lhs, rhs);
+ }
+
+ LBinaryV *lir = new LBinaryV(JSOP_URSH);
+ if (!useBox(lir, LBinaryV::LhsInput, lhs))
+ return false;
+ if (!useBox(lir, LBinaryV::RhsInput, rhs))
+ return false;
+ return defineVMReturn(lir, ins) && assignSafepoint(lir, ins);
}
bool
LIRGenerator::visitFloor(MFloor *ins)
{
JS_ASSERT(ins->num()->type() == MIRType_Double);
LFloor *lir = new LFloor(useRegister(ins->num()));
if (!assignSnapshot(lir))
@@ -906,16 +905,22 @@ LIRGenerator::visitToDouble(MToDouble *c
}
case MIRType_Null:
return lowerConstantDouble(0, convert);
case MIRType_Undefined:
return lowerConstantDouble(js_NaN, convert);
+ case MIRType_Uint32:
+ {
+ LUint32ToDouble *lir = new LUint32ToDouble(useRegister(opd));
+ return define(lir, convert);
+ }
+
case MIRType_Int32:
case MIRType_Boolean:
{
LInt32ToDouble *lir = new LInt32ToDouble(useRegister(opd));
return define(lir, convert);
}
case MIRType_Double:
@@ -951,16 +956,20 @@ LIRGenerator::visitToInt32(MToInt32 *con
return redefine(convert, opd);
case MIRType_Double:
{
LDoubleToInt32 *lir = new LDoubleToInt32(useRegister(opd));
return assignSnapshot(lir) && define(lir, convert);
}
+ case MIRType_Uint32:
+ IonSpew(IonSpew_Abort, "Uint32 to Int32 not supported yet.");
+ break;
+
case MIRType_String:
// Strings are complicated - we don't handle them yet.
IonSpew(IonSpew_Abort, "String to Int32 not supported yet.");
break;
case MIRType_Object:
// Objects might be effectful.
IonSpew(IonSpew_Abort, "Object to Int32 not supported yet.");
@@ -992,16 +1001,17 @@ LIRGenerator::visitTruncateToInt32(MTrun
return assignSnapshot(lir) && define(lir, truncate);
}
case MIRType_Null:
case MIRType_Undefined:
return define(new LInteger(0), truncate);
case MIRType_Int32:
+ case MIRType_Uint32:
case MIRType_Boolean:
return redefine(truncate, opd);
case MIRType_Double:
{
LTruncateDToInt32 *lir = new LTruncateDToInt32(useRegister(opd), tempFloat());
return assignSnapshot(lir) && define(lir, truncate);
}
@@ -1422,26 +1432,19 @@ bool
LIRGenerator::visitLoadTypedArrayElement(MLoadTypedArrayElement *ins)
{
JS_ASSERT(ins->elements()->type() == MIRType_Elements);
JS_ASSERT(ins->index()->type() == MIRType_Int32);
const LUse elements = useRegister(ins->elements());
const LAllocation index = useRegisterOrConstant(ins->index());
- JS_ASSERT(IsNumberType(ins->type()));
+ JS_ASSERT(IsNumberType(ins->type()) || ins->type() == MIRType_Uint32);
- // We need a temp register for Uint32Array with known double result.
- LDefinition tempDef = LDefinition::BogusTemp();
- if (ins->arrayType() == TypedArray::TYPE_UINT32 && ins->type() == MIRType_Double)
- tempDef = temp();
-
- LLoadTypedArrayElement *lir = new LLoadTypedArrayElement(elements, index, tempDef);
- if (ins->fallible() && !assignSnapshot(lir))
- return false;
+ LLoadTypedArrayElement *lir = new LLoadTypedArrayElement(elements, index);
return define(lir, ins);
}
bool
LIRGenerator::visitClampToUint8(MClampToUint8 *ins)
{
MDefinition *in = ins->input();
diff --git a/js/src/ion/MIR.cpp b/js/src/ion/MIR.cpp
--- a/js/src/ion/MIR.cpp
+++ b/js/src/ion/MIR.cpp
@@ -547,19 +547,20 @@ MShiftInstruction::infer(const TypeOracl
specialization_ = MIRType_None;
else
specialization_ = MIRType_Int32;
}
void
MUrsh::infer(const TypeOracle::Binary &b)
{
- this->MShiftInstruction::infer(b);
- if (specialization_ != MIRType_Int32)
- setResultType(MIRType_Value);
+ if (b.lhs == MIRType_Object || b.rhs == MIRType_Object)
+ specialization_ = MIRType_None;
+ else
+ specialization_ = MIRType_Uint32;
}
static inline bool
NeedNegativeZeroCheck(MDefinition *def)
{
// Test if all uses have the same symantic for -0 and 0
for (MUseIterator use = def->usesBegin(); use != def->usesEnd(); use++) {
if (use->node()->isResumePoint())
@@ -1174,28 +1175,31 @@ MToInt32::analyzeEdgeCasesBackward()
{
canBeNegativeZero_ = NeedNegativeZeroCheck(this);
}
MDefinition *
MTruncateToInt32::foldsTo(bool useValueNumbers)
{
MDefinition *input = getOperand(0);
- if (input->type() == MIRType_Int32)
+ if (input->type() == type())
return input;
+/*
if (input->type() == MIRType_Double && input->isConstant()) {
const Value &v = input->toConstant()->value();
uint32 ret = ToInt32(v.toDouble());
return MConstant::New(Int32Value(ret));
}
+*/
return this;
}
+
MDefinition *
MToDouble::foldsTo(bool useValueNumbers)
{
if (input()->isConstant()) {
const Value &v = input()->toConstant()->value();
if (v.isPrimitive()) {
double out;
DebugOnly<bool> ok = ToNumber(GetIonContext()->cx, v, &out);
diff --git a/js/src/ion/MIR.h b/js/src/ion/MIR.h
--- a/js/src/ion/MIR.h
+++ b/js/src/ion/MIR.h
@@ -1800,33 +1800,33 @@ class MToInt32 : public MUnaryInstructio
return congruentIfOperandsEqual(ins);
}
AliasSet getAliasSet() const {
return AliasSet::None();
}
};
-// Converts a value or typed input to a truncated int32, for use with bitwise
+// Converts a value or typed input to a truncated int32 or uint32, for use with bitwise
// operations. This is an infallible ValueToECMAInt32.
class MTruncateToInt32 : public MUnaryInstruction
{
- MTruncateToInt32(MDefinition *def)
+ MTruncateToInt32(MDefinition *def, MIRType type)
: MUnaryInstruction(def)
{
- setResultType(MIRType_Int32);
+ setResultType(type);
setMovable();
range()->set(JSVAL_INT_MIN, JSVAL_INT_MAX);
}
public:
INSTRUCTION_HEADER(TruncateToInt32);
- static MTruncateToInt32 *New(MDefinition *def)
+ static MTruncateToInt32 *New(MDefinition *def, MIRType type)
{
- return new MTruncateToInt32(def);
+ return new MTruncateToInt32(def, type);
}
MDefinition *input() const {
return getOperand(0);
}
MDefinition *foldsTo(bool useValueNumbers);
@@ -2122,62 +2122,45 @@ class MRsh : public MShiftInstruction
return false;
int32 c = right->toConstant()->value().toInt32();
Range *other = getOperand(0)->range();
return range()->update(Range::shr(other, c));
}
};
-class MUrsh : public MShiftInstruction
+class MUrsh : public MBinaryInstruction, public Uint32Policy
{
bool canOverflow_;
MUrsh(MDefinition *left, MDefinition *right)
- : MShiftInstruction(left, right),
+ : MBinaryInstruction(left, right),
canOverflow_(true)
- { }
+ {
+ setResultType(MIRType_Uint32);
+ setMovable();
+ }
public:
INSTRUCTION_HEADER(Ursh);
static MUrsh *New(MDefinition *left, MDefinition *right);
+ TypePolicy *typePolicy() {
+ return this;
+ }
+
MDefinition *foldIfZero(size_t operand) {
// 0 >>> x => 0
if (operand == 0)
return getOperand(0);
return this;
}
void infer(const TypeOracle::Binary &b);
-
- bool canOverflow() {
- // solution is only negative when lhs < 0 and rhs & 0x1f == 0
- MDefinition *lhs = getOperand(0);
- MDefinition *rhs = getOperand(1);
-
- if (lhs->isConstant()) {
- Value lhsv = lhs->toConstant()->value();
- if (lhsv.isInt32() && lhsv.toInt32() >= 0)
- return false;
- }
-
- if (rhs->isConstant()) {
- Value rhsv = rhs->toConstant()->value();
- if (rhsv.isInt32() && rhsv.toInt32() % 32 != 0)
- return false;
- }
-
- return canOverflow_;
- }
-
- bool fallible() {
- return canOverflow();
- }
};
class MBinaryArithInstruction
: public MBinaryInstruction,
public ArithPolicy
{
public:
MBinaryArithInstruction(MDefinition *left, MDefinition *right)
@@ -3668,20 +3651,16 @@ class MLoadTypedArrayElement
static MLoadTypedArrayElement *New(MDefinition *elements, MDefinition *index, int arrayType) {
return new MLoadTypedArrayElement(elements, index, arrayType);
}
int arrayType() const {
return arrayType_;
}
- bool fallible() const {
- // Bailout if the result does not fit in an int32.
- return arrayType_ == TypedArray::TYPE_UINT32 && type() == MIRType_Int32;
- }
MDefinition *elements() const {
return getOperand(0);
}
MDefinition *index() const {
return getOperand(1);
}
AliasSet getAliasSet() const {
return AliasSet::Load(AliasSet::TypedArrayElement);
@@ -3770,16 +3749,19 @@ class MStoreTypedArrayElement
return (arrayType_ == TypedArray::TYPE_INT8 ||
arrayType_ == TypedArray::TYPE_UINT8 ||
arrayType_ == TypedArray::TYPE_UINT8_CLAMPED);
}
bool isFloatArray() const {
return (arrayType_ == TypedArray::TYPE_FLOAT32 ||
arrayType_ == TypedArray::TYPE_FLOAT64);
}
+ bool isUint32Array() const {
+ return arrayType_ == TypedArray::TYPE_UINT32;
+ }
TypePolicy *typePolicy() {
return this;
}
MDefinition *elements() const {
return getOperand(0);
}
MDefinition *index() const {
return getOperand(1);
diff --git a/js/src/ion/SnapshotReader.h b/js/src/ion/SnapshotReader.h
--- a/js/src/ion/SnapshotReader.h
+++ b/js/src/ion/SnapshotReader.h
@@ -63,17 +63,19 @@ class SnapshotReader
{
CONSTANT, // An index into the constant pool.
DOUBLE_REG, // Type is double, payload is in a register.
TYPED_REG, // Type is constant, payload is in a register.
TYPED_STACK, // Type is constant, payload is on the stack.
UNTYPED, // Type is not known.
JS_UNDEFINED, // UndefinedValue()
JS_NULL, // NullValue()
- JS_INT32 // Int32Value(n)
+ JS_INT32, // Int32Value(n)
+ UINT32_REG,
+ UINT32_STACK
};
class Location
{
friend class SnapshotReader;
Register::Code reg_;
int32 stackSlot_;
@@ -163,25 +165,26 @@ class SnapshotReader
JS_ASSERT(mode() == JS_INT32);
return value_;
}
JSValueType knownType() const {
JS_ASSERT(mode() == TYPED_REG || mode() == TYPED_STACK);
return known_type_.type;
}
Register reg() const {
- JS_ASSERT(mode() == TYPED_REG && knownType() != JSVAL_TYPE_DOUBLE);
+ JS_ASSERT_IF(mode() == TYPED_REG, knownType() != JSVAL_TYPE_DOUBLE);
+ JS_ASSERT_IF(mode() != TYPED_REG, mode() == UINT32_REG);
return known_type_.payload.reg();
}
FloatRegister floatReg() const {
JS_ASSERT(mode() == DOUBLE_REG);
return FloatRegister::FromCode(fpu_);
}
int32 stackSlot() const {
- JS_ASSERT(mode() == TYPED_STACK);
+ JS_ASSERT(mode() == TYPED_STACK || mode() == UINT32_STACK);
return known_type_.payload.stackSlot();
}
#if defined(JS_NUNBOX32)
Location payload() const {
JS_ASSERT(mode() == UNTYPED);
return unknown_type_.payload;
}
Location type() const {
diff --git a/js/src/ion/SnapshotWriter.h b/js/src/ion/SnapshotWriter.h
--- a/js/src/ion/SnapshotWriter.h
+++ b/js/src/ion/SnapshotWriter.h
@@ -39,16 +39,18 @@ class SnapshotWriter
void trackFrame(uint32 pcOpcode, uint32 mirOpcode, uint32 mirId,
uint32 lirOpcode, uint32 lirId);
#endif
void endFrame();
void addSlot(const FloatRegister &reg);
void addSlot(JSValueType type, const Register &reg);
void addSlot(JSValueType type, int32 stackIndex);
+ void addUint32Slot(const Register &reg);
+ void addUint32Slot(int32 stackIndex);
void addUndefinedSlot();
void addNullSlot();
void addInt32Slot(int32 value);
void addConstantPoolSlot(uint32 index);
#if defined(JS_NUNBOX32)
void addSlot(const Register &type, const Register &payload);
void addSlot(const Register &type, int32 payloadStackIndex);
void addSlot(int32 typeStackIndex, const Register &payload);
diff --git a/js/src/ion/Snapshots.cpp b/js/src/ion/Snapshots.cpp
--- a/js/src/ion/Snapshots.cpp
+++ b/js/src/ion/Snapshots.cpp
@@ -237,16 +237,25 @@ SnapshotReader::readSlot()
Location loc;
if (reg2 != ESC_REG_FIELD_INDEX)
loc = Location::From(Register::FromCode(reg2));
else
loc = Location::From(reader_.readSigned());
return Slot(TYPED_REG, type, loc);
}
+ if (code == ESC_REG_FIELD_INDEX) {
+ printf ("Reading uint32\n");
+ uint8 code = reader_.readByte();
+ printf ("code: %d\n", code);
+ if (code != Registers::Invalid)
+ return Slot(UINT32_REG, type, Location::From(Register::FromCode(code)));
+ return Slot(UINT32_STACK, type, Location::From(reader_.readSigned()));
+ }
+
Slot slot(UNTYPED);
#ifdef JS_NUNBOX32
switch (code) {
case NUNBOX32_STACK_STACK:
slot.unknown_type_.type = Location::From(reader_.readSigned());
slot.unknown_type_.payload = Location::From(reader_.readSigned());
return slot;
case NUNBOX32_STACK_REG:
@@ -416,16 +425,37 @@ SnapshotWriter::addSlot(JSValueType type
if (type == JSVAL_TYPE_DOUBLE)
writeSlotHeader(type, FloatRegisters::Invalid);
else
writeSlotHeader(type, Registers::Invalid);
writer_.writeSigned(stackIndex);
}
+void
+SnapshotWriter::addUint32Slot(const Register &reg)
+{
+ IonSpew(IonSpew_Snapshots, " slot %u: uint32 (%s)",
+ slotsWritten_, reg.name());
+
+ writeSlotHeader(JSVAL_TYPE_MAGIC, ESC_REG_FIELD_INDEX);
+ writer_.writeByte(reg.code());
+}
+
+void
+SnapshotWriter::addUint32Slot(int32 stackIndex)
+{
+ IonSpew(IonSpew_Snapshots, " slot %u: uint32 (stack %d)",
+ slotsWritten_, stackIndex);
+
+ writeSlotHeader(JSVAL_TYPE_MAGIC, ESC_REG_FIELD_INDEX);
+ writer_.writeByte(Registers::Invalid);
+ writer_.writeSigned(stackIndex);
+}
+
#if defined(JS_NUNBOX32)
void
SnapshotWriter::addSlot(const Register &type, const Register &payload)
{
IonSpew(IonSpew_Snapshots, " slot %u: value (t=%s, d=%s)",
slotsWritten_, type.name(), payload.name());
writeSlotHeader(JSVAL_TYPE_MAGIC, NUNBOX32_REG_REG);
diff --git a/js/src/ion/TypeOracle.h b/js/src/ion/TypeOracle.h
--- a/js/src/ion/TypeOracle.h
+++ b/js/src/ion/TypeOracle.h
@@ -18,16 +18,17 @@ namespace ion {
// specialized type. Furthermore, anything < String has trivial conversion to
// a number.
enum MIRType
{
MIRType_Undefined,
MIRType_Null,
MIRType_Boolean,
MIRType_Int32,
+ MIRType_Uint32, // Type special to Ion, converted to int/double on bailout.
MIRType_Double,
MIRType_String,
MIRType_Object,
MIRType_Magic,
MIRType_Value,
MIRType_Any, // Any type.
MIRType_None, // Invalid, used as a placeholder.
MIRType_Slots, // A slots vector
@@ -332,16 +333,18 @@ StringFromMIRType(MIRType type)
case MIRType_Undefined:
return "Undefined";
case MIRType_Null:
return "Null";
case MIRType_Boolean:
return "Bool";
case MIRType_Int32:
return "Int32";
+ case MIRType_Uint32:
+ return "Uint32";
case MIRType_Double:
return "Double";
case MIRType_String:
return "String";
case MIRType_Object:
return "Object";
case MIRType_Magic:
return "Magic";
diff --git a/js/src/ion/TypePolicy.cpp b/js/src/ion/TypePolicy.cpp
--- a/js/src/ion/TypePolicy.cpp
+++ b/js/src/ion/TypePolicy.cpp
@@ -215,17 +215,40 @@ BitwisePolicy::adjustInputs(MInstruction
MDefinition *in = ins->getOperand(i);
if (in->type() == ins->type())
continue;
// See BinaryArithPolicy::adjustInputs for an explanation of the following
if (in->type() == MIRType_Object || in->type() == MIRType_String)
in = boxAt(ins, in);
- MInstruction *replace = MTruncateToInt32::New(in);
+ MInstruction *replace = MTruncateToInt32::New(in, MIRType_Int32);
+ ins->block()->insertBefore(ins, replace);
+ ins->replaceOperand(i, replace);
+ }
+
+ return true;
+}
+
+bool
+Uint32Policy::adjustInputs(MInstruction *ins)
+{
+ if (specialization_ == MIRType_None)
+ return BoxInputsPolicy::adjustInputs(ins);
+
+ for (size_t i = 0; i < ins->numOperands(); i++) {
+ MDefinition *in = ins->getOperand(i);
+ if (in->type() == ins->type())
+ continue;
+
+ // See BinaryArithPolicy::adjustInputs for an explanation of the following
+ if (in->type() == MIRType_Object || in->type() == MIRType_String)
+ in = boxAt(ins, in);
+
+ MInstruction *replace = MTruncateToInt32::New(in, MIRType_Uint32);
ins->block()->insertBefore(ins, replace);
ins->replaceOperand(i, replace);
}
return true;
}
bool
@@ -395,16 +418,17 @@ StoreTypedArrayPolicy::adjustInputs(MIns
int arrayType = store->arrayType();
MDefinition *value = store->value();
// First, ensure the value is int32, boolean, double or Value.
// The conversion is based on TypedArrayTemplate::setElementTail.
switch (value->type()) {
case MIRType_Int32:
+ case MIRType_Uint32:
case MIRType_Double:
case MIRType_Boolean:
case MIRType_Value:
break;
case MIRType_Null:
value = MConstant::New(Int32Value(0));
ins->block()->insertBefore(ins, value->toInstruction());
break;
@@ -420,32 +444,36 @@ StoreTypedArrayPolicy::adjustInputs(MIns
JS_NOT_REACHED("Unexpected type");
break;
}
if (value != store->value())
ins->replaceOperand(2, value);
JS_ASSERT(value->type() == MIRType_Int32 ||
+ value->type() == MIRType_Uint32 ||
value->type() == MIRType_Boolean ||
value->type() == MIRType_Double ||
value->type() == MIRType_Value);
switch (arrayType) {
case TypedArray::TYPE_INT8:
case TypedArray::TYPE_UINT8:
case TypedArray::TYPE_INT16:
case TypedArray::TYPE_UINT16:
case TypedArray::TYPE_INT32:
- case TypedArray::TYPE_UINT32:
if (value->type() != MIRType_Int32) {
- value = MTruncateToInt32::New(value);
+ value = MTruncateToInt32::New(value, MIRType_Int32);
ins->block()->insertBefore(ins, value->toInstruction());
}
break;
+ case TypedArray::TYPE_UINT32:
+ value = MTruncateToInt32::New(value, MIRType_Uint32);
+ ins->block()->insertBefore(ins, value->toInstruction());
+ break;
case TypedArray::TYPE_UINT8_CLAMPED:
// IonBuilder should have inserted ClampToUint8.
JS_ASSERT(value->type() == MIRType_Int32);
break;
case TypedArray::TYPE_FLOAT32:
case TypedArray::TYPE_FLOAT64:
if (value->type() != MIRType_Double) {
value = MToDouble::New(value);
diff --git a/js/src/ion/TypePolicy.h b/js/src/ion/TypePolicy.h
--- a/js/src/ion/TypePolicy.h
+++ b/js/src/ion/TypePolicy.h
@@ -66,16 +66,25 @@ class BitwisePolicy : public BoxInputsPo
// - == Any. Inputs are probably primitive.
// - == None. This op should not be specialized.
MIRType specialization_;
public:
bool adjustInputs(MInstruction *def);
};
+class Uint32Policy : public BoxInputsPolicy
+{
+ protected:
+ MIRType specialization_;
+
+ public:
+ bool adjustInputs(MInstruction *def);
+};
+
class TableSwitchPolicy : public BoxInputsPolicy
{
public:
bool adjustInputs(MInstruction *def);
};
class ComparePolicy : public BoxInputsPolicy
{
diff --git a/js/src/ion/shared/CodeGenerator-shared.cpp b/js/src/ion/shared/CodeGenerator-shared.cpp
--- a/js/src/ion/shared/CodeGenerator-shared.cpp
+++ b/js/src/ion/shared/CodeGenerator-shared.cpp
@@ -86,16 +86,27 @@ CodeGeneratorShared::encodeSlots(LSnapsh
switch (type) {
case MIRType_Undefined:
snapshots_.addUndefinedSlot();
break;
case MIRType_Null:
snapshots_.addNullSlot();
break;
+ case MIRType_Uint32:
+ {
+ LAllocation *payload = snapshot->payloadOfSlot(i);
+ if (payload->isMemory()) {
+ snapshots_.addUint32Slot(ToStackIndex(payload));
+ } else {
+ JS_ASSERT(payload->isGeneralReg());
+ snapshots_.addUint32Slot(ToRegister(payload));
+ }
+ break;
+ }
case MIRType_Int32:
case MIRType_String:
case MIRType_Object:
case MIRType_Boolean:
case MIRType_Double:
{
LAllocation *payload = snapshot->payloadOfSlot(i);
JSValueType type = ValueTypeFromMIRType(mir->type());
diff --git a/js/src/ion/shared/CodeGenerator-x86-shared.cpp b/js/src/ion/shared/CodeGenerator-x86-shared.cpp
--- a/js/src/ion/shared/CodeGenerator-x86-shared.cpp
+++ b/js/src/ion/shared/CodeGenerator-x86-shared.cpp
@@ -757,21 +757,21 @@ CodeGeneratorX86Shared::visitShiftOp(LSh
// Note: this is an unsigned operation.
// We don't have a UINT32 type, so we will emulate this with INT32
// The bit representation of an integer from ToInt32 and ToUint32 are the same.
// So the inputs are ok.
// But we need to bring the output back again from UINT32 to INT32.
// Both representation overlap each other in the positive numbers. (in INT32)
// So there is only a problem when solution (in INT32) is negative.
- if (ursh->canOverflow()) {
- masm.cmpl(ToOperand(lhs), Imm32(0));
- if (!bailoutIf(Assembler::LessThan, ins->snapshot()))
- return false;
- }
+ // if (ursh->canOverflow()) {
+ // masm.cmpl(ToOperand(lhs), Imm32(0));
+ // if (!bailoutIf(Assembler::LessThan, ins->snapshot()))
+ // return false;
+ // }
break;
}
default:
JS_NOT_REACHED("unexpected shift opcode");
}
return true;
}
diff --git a/js/src/ion/shared/Lowering-shared-inl.h b/js/src/ion/shared/Lowering-shared-inl.h
--- a/js/src/ion/shared/Lowering-shared-inl.h
+++ b/js/src/ion/shared/Lowering-shared-inl.h
@@ -163,20 +163,18 @@ LIRGeneratorShared::defineVMReturn(LInst
// When snapshotting, we recover the actual JS type from MIR. This function
// checks that when making redefinitions, we don't accidentally coerce two
// incompatible types.
static inline bool
IsCompatibleLIRCoercion(MIRType to, MIRType from)
{
if (to == from)
return true;
- if ((to == MIRType_Int32 || to == MIRType_Boolean) &&
- (from == MIRType_Int32 || from == MIRType_Boolean)) {
- return true;
- }
+ if (to == MIRType_Int32 || to == MIRType_Uint32 || to == MIRType_Boolean)
+ return (from == MIRType_Int32 || from == MIRType_Uint32 || from == MIRType_Boolean);
return false;
}
bool
LIRGeneratorShared::redefine(MDefinition *def, MDefinition *as)
{
JS_ASSERT(IsCompatibleLIRCoercion(def->type(), as->type()));
if (!ensureDefined(as))
diff --git a/js/src/ion/shared/MacroAssembler-x86-shared.h b/js/src/ion/shared/MacroAssembler-x86-shared.h
--- a/js/src/ion/shared/MacroAssembler-x86-shared.h
+++ b/js/src/ion/shared/MacroAssembler-x86-shared.h
@@ -172,16 +172,29 @@ class MacroAssemblerX86Shared : public A
}
void jump(RepatchLabel *label) {
jmp(label);
}
void convertInt32ToDouble(const Register &src, const FloatRegister &dest) {
cvtsi2sd(Operand(src), dest);
}
+ void convertUint32ToDouble(const Register &src, const FloatRegister &dest) {
+ Label done;
+ cvtsi2sd(Operand(src), dest);
+
+ cmpl(src, Imm32(0));
+ j(Assembler::GreaterThanOrEqual, &done);
+
+ xorpd(ScratchFloatReg, ScratchFloatReg);
+ subsd(dest, ScratchFloatReg);
+ movsd(ScratchFloatReg, dest);
+
+ bind(&done);
+ }
Condition testDoubleTruthy(bool truthy, const FloatRegister &reg) {
xorpd(ScratchFloatReg, ScratchFloatReg);
ucomisd(ScratchFloatReg, reg);
return truthy ? NonZero : Zero;
}
void branchTruncateDouble(const FloatRegister &src, const Register &dest, Label *fail) {
JS_STATIC_ASSERT(INT_MIN == int(0x80000000));
cvttsd2si(src, dest);
diff --git a/js/src/ion/x64/CodeGenerator-x64.cpp b/js/src/ion/x64/CodeGenerator-x64.cpp
--- a/js/src/ion/x64/CodeGenerator-x64.cpp
+++ b/js/src/ion/x64/CodeGenerator-x64.cpp
@@ -76,20 +76,23 @@ CodeGeneratorX64::visitOsrValue(LOsrValu
}
bool
CodeGeneratorX64::visitBox(LBox *box)
{
const LAllocation *in = box->getOperand(0);
const LDefinition *result = box->getDef(0);
- if (box->type() != MIRType_Double)
+ if (box->type() == MIRType_Double)
+ masm.movqsd(ToFloatRegister(in), ToRegister(result));
+ else if (box->type() == MIRType_Uint32)
+ masm.boxUint32(ToRegister(in), ToRegister(result));
+ else
masm.boxValue(ValueTypeFromMIRType(box->type()), ToRegister(in), ToRegister(result));
- else
- masm.movqsd(ToFloatRegister(in), ToRegister(result));
+
return true;
}
bool
CodeGeneratorX64::visitUnbox(LUnbox *unbox)
{
const ValueOperand value = ToValue(unbox, LUnbox::Input);
const LDefinition *result = unbox->output();
@@ -208,16 +211,22 @@ CodeGeneratorX64::storeUnboxedValue(cons
else
masm.movl(Imm32(val.toBoolean() ? 1 : 0), dest);
} else {
masm.movl(ToRegister(value), dest);
}
return;
}
+ if (valueType == MIRType_Uint32) {
+ masm.boxUint32(ToRegister(value), ScratchReg);
+ masm.movq(ScratchReg, dest);
+ return;
+ }
+
if (value->isConstant()) {
masm.moveValue(*value->toConstant(), ScratchReg);
masm.movq(ScratchReg, dest);
} else {
JSValueType type = ValueTypeFromMIRType(valueType);
masm.boxValue(type, ToRegister(value), ScratchReg);
masm.movq(ScratchReg, dest);
}
diff --git a/js/src/ion/x64/Lowering-x64.cpp b/js/src/ion/x64/Lowering-x64.cpp
--- a/js/src/ion/x64/Lowering-x64.cpp
+++ b/js/src/ion/x64/Lowering-x64.cpp
@@ -144,18 +144,19 @@ LIRGeneratorX64::lowerDivI(MDiv *div)
}
bool
LIRGeneratorX64::visitStoreTypedArrayElement(MStoreTypedArrayElement *ins)
{
JS_ASSERT(ins->elements()->type() == MIRType_Elements);
JS_ASSERT(ins->index()->type() == MIRType_Int32);
- if (ins->isFloatArray())
- JS_ASSERT(ins->value()->type() == MIRType_Double);
- else
- JS_ASSERT(ins->value()->type() == MIRType_Int32);
+
+ JS_ASSERT_IF(ins->isFloatArray(), ins->value()->type() == MIRType_Double);
+ JS_ASSERT_IF(ins->isUint32Array(), ins->value()->type() == MIRType_Uint32);
+ JS_ASSERT_IF(!ins->isFloatArray() && !ins->isUint32Array(),
+ ins->value()->type() == MIRType_Int32);
LUse elements = useRegister(ins->elements());
LAllocation index = useRegisterOrConstant(ins->index());
LAllocation value = useRegisterOrNonDoubleConstant(ins->value());
return add(new LStoreTypedArrayElement(elements, index, value), ins);
}
diff --git a/js/src/ion/x64/MacroAssembler-x64.h b/js/src/ion/x64/MacroAssembler-x64.h
--- a/js/src/ion/x64/MacroAssembler-x64.h
+++ b/js/src/ion/x64/MacroAssembler-x64.h
@@ -160,16 +160,34 @@ class MacroAssemblerX64 : public MacroAs
// register may be filled, we can't clobber the tag bits. This can
// happen when instructions automatically sign-extend their result.
// To account for this, we clear the top bits of the register, which
// is safe since those bits aren't required.
if (type == JSVAL_TYPE_INT32 || type == JSVAL_TYPE_BOOLEAN)
movl(src, src);
orq(src, dest);
}
+ void boxUint32(Register src, Register dest) {
+ Label positive, done;
+
+ cmpl(src, Imm32(0));
+ j(Assembler::GreaterThanOrEqual, &positive);
+
+ convertUInt32ToDouble(src, ScratchFloatReg);
+ movqsd(ScratchFloatReg, dest);
+ jump(&done);
+
+ bind(&positive);
+ JSValueShiftedTag tag = (JSValueShiftedTag)JSVAL_TYPE_TO_SHIFTED_TAG(JSVAL_TYPE_INT32);
+ movq(ImmShiftedTag(tag), dest);
+ movl(src, src);
+ orq(src, dest);
+
+ bind(&done);
+ }
Condition testUndefined(Condition cond, Register tag) {
JS_ASSERT(cond == Equal || cond == NotEqual);
cmpl(tag, ImmTag(JSVAL_TAG_UNDEFINED));
return cond;
}
Condition testInt32(Condition cond, Register tag) {
JS_ASSERT(cond == Equal || cond == NotEqual);
diff --git a/js/src/jit-test/tests/basic/testShiftRightLogical.js b/js/src/jit-test/tests/basic/testShiftRightLogical.js
--- a/js/src/jit-test/tests/basic/testShiftRightLogical.js
+++ b/js/src/jit-test/tests/basic/testShiftRightLogical.js
@@ -1,13 +1,13 @@
/* Test the proper operation of the logical right shift operator. This is
* especially important on ARM as an explicit mask is required at the native
* instruction level. */
-load(libdir + 'range.js');
+//load(libdir + 'range.js');
function testShiftRightLogical()
{
var r = [];
var i = 0;
var j = 0;
var shifts = [0,1,7,8,15,16,23,24,31];
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment