Created
July 30, 2012 18:30
-
-
Save evilpie/3208984 to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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 ®); | |
void addSlot(JSValueType type, const Register ®); | |
void addSlot(JSValueType type, int32 stackIndex); | |
+ void addUint32Slot(const Register ®); | |
+ 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 ®) | |
+{ | |
+ 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 ®) { | |
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