From 27393bfaa7565a7801719b525488c34660a9951b Mon Sep 17 00:00:00 2001 From: Shu-yu Guo Date: Mon, 9 Sep 2013 18:55:52 -0700 Subject: [PATCH] Bug 899139 - Part 1: Refactor value-to-int logic into IonMacroAssembler. (r=jandem) --- js/src/jit/AsmJS.cpp | 3 +- js/src/jit/CodeGenerator.cpp | 137 ++------ js/src/jit/IonMacroAssembler.cpp | 308 ++++++++++++++++-- js/src/jit/IonMacroAssembler.h | 151 ++++++++- js/src/jit/LIR-Common.h | 3 + js/src/jit/Lowering.cpp | 2 +- js/src/jit/arm/MacroAssembler-arm.cpp | 16 + js/src/jit/arm/MacroAssembler-arm.h | 3 + js/src/jit/shared/MacroAssembler-x86-shared.h | 3 + js/src/jit/x86/MacroAssembler-x86.h | 6 + 10 files changed, 493 insertions(+), 139 deletions(-) diff --git a/js/src/jit/AsmJS.cpp b/js/src/jit/AsmJS.cpp index 50630549bae4..27686b8ddaeb 100644 --- a/js/src/jit/AsmJS.cpp +++ b/js/src/jit/AsmJS.cpp @@ -5981,7 +5981,8 @@ GenerateFFIIonExit(ModuleCompiler &m, const ModuleCompiler::ExitDescriptor &exit case RetType::Void: break; case RetType::Signed: - masm.convertValueToInt32(JSReturnOperand, ReturnFloatReg, ReturnReg, &oolConvert); + masm.convertValueToInt32(JSReturnOperand, ReturnFloatReg, ReturnReg, &oolConvert, + /* -0 check */ false); break; case RetType::Double: masm.convertValueToDouble(JSReturnOperand, ReturnFloatReg, &oolConvert); diff --git a/js/src/jit/CodeGenerator.cpp b/js/src/jit/CodeGenerator.cpp index b3a83d7a5828..bd47a4d95b8f 100644 --- a/js/src/jit/CodeGenerator.cpp +++ b/js/src/jit/CodeGenerator.cpp @@ -157,89 +157,36 @@ CodeGenerator::visitValueToInt32(LValueToInt32 *lir) { ValueOperand operand = ToValue(lir, LValueToInt32::Input); Register output = ToRegister(lir->output()); + FloatRegister temp = ToFloatRegister(lir->tempFloat()); - Register tag = masm.splitTagForTest(operand); - - Label done, simple, isInt32, isBool, isString, notDouble; - // Type-check switch. MDefinition *input; if (lir->mode() == LValueToInt32::NORMAL) input = lir->mirNormal()->input(); else input = lir->mirTruncate()->input(); - masm.branchEqualTypeIfNeeded(MIRType_Int32, input, tag, &isInt32); - masm.branchEqualTypeIfNeeded(MIRType_Boolean, input, tag, &isBool); - // Only convert strings to int if we are in a truncation context, like - // bitwise operations. - if (lir->mode() == LValueToInt32::TRUNCATE) - masm.branchEqualTypeIfNeeded(MIRType_String, input, tag, &isString); - masm.branchTestDouble(Assembler::NotEqual, tag, ¬Double); - // If the value is a double, see if it fits in a 32-bit int. We need to ask - // the platform-specific codegenerator to do this. - FloatRegister temp = ToFloatRegister(lir->tempFloat()); - masm.unboxDouble(operand, temp); - - Label fails, isDouble; - masm.bind(&isDouble); + Label fails; if (lir->mode() == LValueToInt32::TRUNCATE) { - if (!emitTruncateDouble(temp, output)) - return false; + // We can only handle strings in truncation contexts, like bitwise + // operations. + if (input->mightBeType(MIRType_String)) { + Register stringReg = ToRegister(lir->temp()); + OutOfLineCode *ool = oolCallVM(StringToNumberInfo, lir, (ArgList(), stringReg), + StoreFloatRegisterTo(temp)); + if (!ool) + return false; + + masm.truncateValueToInt32(operand, input, ool->entry(), ool->rejoin(), stringReg, + temp, output, &fails); + } else { + masm.truncateValueToInt32(operand, input, temp, output, &fails); + } } else { - masm.convertDoubleToInt32(temp, output, &fails, lir->mirNormal()->canBeNegativeZero()); - } - masm.jump(&done); - - masm.bind(¬Double); - - if (lir->mode() == LValueToInt32::NORMAL) { - // If the value is not null, it's a string, object, or undefined, - // which we can't handle here. - masm.branchTestNull(Assembler::NotEqual, tag, &fails); - } else { - // Test for object - then fallthrough to null, which will also handle - // undefined. - masm.branchEqualTypeIfNeeded(MIRType_Object, input, tag, &fails); + masm.convertValueToInt32(operand, input, temp, output, &fails, + lir->mirNormal()->canBeNegativeZero()); } - if (fails.used() && !bailoutFrom(&fails, lir->snapshot())) - return false; - - // The value is null - just emit 0. - masm.mov(Imm32(0), output); - masm.jump(&done); - - // Unbox a string, call StringToNumber to get a double back, and jump back - // to the snippet generated above about dealing with doubles. - if (isString.used()) { - masm.bind(&isString); - Register str = masm.extractString(operand, ToRegister(lir->temp())); - OutOfLineCode *ool = oolCallVM(StringToNumberInfo, lir, (ArgList(), str), - StoreFloatRegisterTo(temp)); - if (!ool) - return false; - - masm.jump(ool->entry()); - masm.bind(ool->rejoin()); - masm.jump(&isDouble); - } - - // Just unbox a bool, the result is 0 or 1. - if (isBool.used()) { - masm.bind(&isBool); - masm.unboxBoolean(operand, output); - masm.jump(&done); - } - - // Integers can be unboxed. - if (isInt32.used()) { - masm.bind(&isInt32); - masm.unboxInt32(operand, output); - } - - masm.bind(&done); - - return true; + return bailoutFrom(&fails, lir->snapshot()); } static const double DoubleZero = 0.0; @@ -6790,46 +6737,24 @@ CodeGenerator::visitClampDToUint8(LClampDToUint8 *lir) bool CodeGenerator::visitClampVToUint8(LClampVToUint8 *lir) { - ValueOperand input = ToValue(lir, LClampVToUint8::Input); + ValueOperand operand = ToValue(lir, LClampVToUint8::Input); FloatRegister tempFloat = ToFloatRegister(lir->tempFloat()); Register output = ToRegister(lir->output()); + MDefinition *input = lir->mir()->input(); - Register tag = masm.splitTagForTest(input); + Label fails; + if (input->mightBeType(MIRType_String)) { + OutOfLineCode *ool = oolCallVM(StringToNumberInfo, lir, (ArgList(), output), + StoreFloatRegisterTo(tempFloat)); + masm.clampValueToUint8(operand, input, ool->entry(), ool->rejoin(), output, + tempFloat, output, &fails); - Label done; - Label isInt32, isDouble, isBoolean; - masm.branchTestInt32(Assembler::Equal, tag, &isInt32); - masm.branchTestDouble(Assembler::Equal, tag, &isDouble); - masm.branchTestBoolean(Assembler::Equal, tag, &isBoolean); - - // Undefined, null and objects are always 0. - Label isZero; - masm.branchTestUndefined(Assembler::Equal, tag, &isZero); - masm.branchTestNull(Assembler::Equal, tag, &isZero); - masm.branchTestObject(Assembler::Equal, tag, &isZero); - - // Bailout for everything else (strings). - if (!bailout(lir->snapshot())) + } else { + masm.clampValueToUint8(operand, input, tempFloat, output, &fails); + } + if (!bailoutFrom(&fails, lir->snapshot())) return false; - masm.bind(&isInt32); - masm.unboxInt32(input, output); - masm.clampIntToUint8(output, output); - masm.jump(&done); - - masm.bind(&isDouble); - masm.unboxDouble(input, tempFloat); - masm.clampDoubleToUint8(tempFloat, output); - masm.jump(&done); - - masm.bind(&isBoolean); - masm.unboxBoolean(input, output); - masm.jump(&done); - - masm.bind(&isZero); - masm.move32(Imm32(0), output); - - masm.bind(&done); return true; } diff --git a/js/src/jit/IonMacroAssembler.cpp b/js/src/jit/IonMacroAssembler.cpp index bcce43e24a96..34943a9a7e82 100644 --- a/js/src/jit/IonMacroAssembler.cpp +++ b/js/src/jit/IonMacroAssembler.cpp @@ -1376,6 +1376,7 @@ MacroAssembler::convertInt32ValueToDouble(const Address &address, Register scrat } static const double DoubleZero = 0.0; +static const double DoubleOne = 1.0; void MacroAssembler::convertValueToDouble(ValueOperand value, FloatRegister output, Label *fail) @@ -1411,39 +1412,45 @@ MacroAssembler::convertValueToDouble(ValueOperand value, FloatRegister output, L bind(&done); } -void -MacroAssembler::convertValueToInt32(ValueOperand value, FloatRegister temp, - Register output, Label *fail) +bool +MacroAssembler::convertValueToDouble(JSContext *cx, const Value &v, FloatRegister output, Label *fail) { - Register tag = splitTagForTest(value); + if (v.isNumber() || v.isString()) { + double d; + if (v.isNumber()) + d = v.toNumber(); + else if (!StringToNumber(cx, v.toString(), &d)) + return false; - Label done, simple, isInt32, isBool, isDouble; + if (d == js_NaN) + loadStaticDouble(&js_NaN, output); + else + loadConstantDouble(d, output); - branchTestInt32(Assembler::Equal, tag, &isInt32); - branchTestBoolean(Assembler::Equal, tag, &isBool); - branchTestDouble(Assembler::Equal, tag, &isDouble); - branchTestNull(Assembler::NotEqual, tag, fail); + return true; + } - // The value is null - just emit 0. - mov(Imm32(0), output); - jump(&done); + if (v.isBoolean()) { + if (v.toBoolean()) + loadStaticDouble(&DoubleOne, output); + else + loadStaticDouble(&DoubleZero, output); + return true; + } - // Try converting double into integer - bind(&isDouble); - unboxDouble(value, temp); - convertDoubleToInt32(temp, output, fail, /* -0 check */ false); - jump(&done); + if (v.isNull()) { + loadStaticDouble(&DoubleZero, output); + return true; + } - // Just unbox a bool, the result is 0 or 1. - bind(&isBool); - unboxBoolean(value, output); - jump(&done); + if (v.isUndefined()) { + loadStaticDouble(&js_NaN, output); + return true; + } - // Integers can be unboxed. - bind(&isInt32); - unboxInt32(value, output); - - bind(&done); + JS_ASSERT(v.isObject()); + jump(fail); + return true; } void @@ -1485,6 +1492,251 @@ MacroAssembler::popRooted(VMFunction::RootType rootType, Register cellReg, } } +bool +MacroAssembler::convertConstantOrRegisterToDouble(JSContext *cx, ConstantOrRegister src, + FloatRegister output, Label *fail) +{ + if (src.constant()) + return convertValueToDouble(cx, src.value(), output, fail); + + convertTypedOrValueToDouble(src.reg(), output, fail); + return true; +} + +void +MacroAssembler::convertTypedOrValueToDouble(TypedOrValueRegister src, FloatRegister output, + Label *fail) +{ + if (src.hasValue()) { + convertValueToDouble(src.valueReg(), output, fail); + return; + } + + switch (src.type()) { + case MIRType_Null: + loadStaticDouble(&DoubleZero, output); + break; + case MIRType_Boolean: + case MIRType_Int32: + convertInt32ToDouble(src.typedReg().gpr(), output); + break; + case MIRType_Double: + if (src.typedReg().fpu() != output) + moveDouble(src.typedReg().fpu(), output); + break; + case MIRType_Object: + case MIRType_String: + jump(fail); + break; + case MIRType_Undefined: + loadStaticDouble(&js_NaN, output); + break; + default: + MOZ_ASSUME_UNREACHABLE("Bad MIRType"); + } +} + +void +MacroAssembler::convertDoubleToInt(FloatRegister src, Register output, Label *fail, + IntConversionBehavior behavior) +{ + switch (behavior) { + case IntConversion_Normal: + case IntConversion_NegativeZeroCheck: + convertDoubleToInt32(src, output, fail, behavior == IntConversion_NegativeZeroCheck); + break; + case IntConversion_Truncate: + branchTruncateDouble(src, output, fail); + break; + case IntConversion_ClampToUint8: + clampDoubleToUint8(src, output); + break; + } +} + +void +MacroAssembler::convertValueToInt(ValueOperand value, MDefinition *maybeInput, + Label *handleStringEntry, Label *handleStringRejoin, + Register stringReg, FloatRegister temp, Register output, + Label *fail, IntConversionBehavior behavior) +{ + Register tag = splitTagForTest(value); + bool handleStrings = (behavior == IntConversion_Truncate || + behavior == IntConversion_ClampToUint8) && + handleStringEntry && + handleStringRejoin; + bool zeroObjects = behavior == IntConversion_ClampToUint8; + + Label done, isInt32, isBool, isDouble, isNull, isString; + + branchEqualTypeIfNeeded(MIRType_Int32, maybeInput, tag, &isInt32); + branchEqualTypeIfNeeded(MIRType_Boolean, maybeInput, tag, &isBool); + branchEqualTypeIfNeeded(MIRType_Double, maybeInput, tag, &isDouble); + + // If we are not truncating, we fail for anything that's not + // null. Otherwise we might be able to handle strings and objects. + switch (behavior) { + case IntConversion_Normal: + case IntConversion_NegativeZeroCheck: + branchTestNull(Assembler::NotEqual, tag, fail); + break; + + case IntConversion_Truncate: + case IntConversion_ClampToUint8: + branchEqualTypeIfNeeded(MIRType_Null, maybeInput, tag, &isNull); + if (handleStrings) + branchEqualTypeIfNeeded(MIRType_String, maybeInput, tag, &isString); + if (zeroObjects) + branchEqualTypeIfNeeded(MIRType_Object, maybeInput, tag, &isNull); + branchTestUndefined(Assembler::NotEqual, tag, fail); + break; + } + + // The value is null or undefined in truncation contexts - just emit 0. + if (isNull.used()) + bind(&isNull); + mov(Imm32(0), output); + jump(&done); + + // Try converting a string into a double, then jump to the double case. + if (handleStrings) { + bind(&isString); + unboxString(value, stringReg); + jump(handleStringEntry); + } + + // Try converting double into integer. + if (isDouble.used() || handleStrings) { + if (isDouble.used()) { + bind(&isDouble); + unboxDouble(value, temp); + } + + if (handleStrings) + bind(handleStringRejoin); + + convertDoubleToInt(temp, output, fail, behavior); + jump(&done); + } + + // Just unbox a bool, the result is 0 or 1. + if (isBool.used()) { + bind(&isBool); + unboxBoolean(value, output); + jump(&done); + } + + // Integers can be unboxed. + if (isInt32.used()) { + bind(&isInt32); + unboxInt32(value, output); + if (behavior == IntConversion_ClampToUint8) + clampIntToUint8(output, output); + } + + bind(&done); +} + +bool +MacroAssembler::convertValueToInt(JSContext *cx, const Value &v, Register output, Label *fail, + IntConversionBehavior behavior) +{ + bool handleStrings = (behavior == IntConversion_Truncate || + behavior == IntConversion_ClampToUint8); + bool zeroObjects = behavior == IntConversion_ClampToUint8; + + if (v.isNumber() || (handleStrings && v.isString())) { + double d; + if (v.isNumber()) + d = v.toNumber(); + else if (!StringToNumber(cx, v.toString(), &d)) + return false; + + switch (behavior) { + case IntConversion_Normal: + case IntConversion_NegativeZeroCheck: { + // -0 is checked anyways if we have a constant value. + int i; + if (mozilla::DoubleIsInt32(d, &i)) + move32(Imm32(i), output); + else + jump(fail); + break; + } + case IntConversion_Truncate: + move32(Imm32(ToInt32(d)), output); + break; + case IntConversion_ClampToUint8: + move32(Imm32(ClampDoubleToUint8(d)), output); + break; + } + + return true; + } + + if (v.isBoolean()) { + move32(Imm32(v.toBoolean() ? 1 : 0), output); + return true; + } + + if (v.isNull() || v.isUndefined()) { + move32(Imm32(0), output); + return true; + } + + JS_ASSERT(v.isObject()); + + if (zeroObjects) + move32(Imm32(0), output); + else + jump(fail); + return true; +} + +bool +MacroAssembler::convertConstantOrRegisterToInt(JSContext *cx, ConstantOrRegister src, + FloatRegister temp, Register output, + Label *fail, IntConversionBehavior behavior) +{ + if (src.constant()) + return convertValueToInt(cx, src.value(), output, fail, behavior); + + convertTypedOrValueToInt(src.reg(), temp, output, fail, behavior); + return true; +} + +void +MacroAssembler::convertTypedOrValueToInt(TypedOrValueRegister src, FloatRegister temp, + Register output, Label *fail, + IntConversionBehavior behavior) +{ + if (src.hasValue()) { + convertValueToInt(src.valueReg(), temp, output, fail, behavior); + return; + } + + switch (src.type()) { + case MIRType_Undefined: + case MIRType_Null: + move32(Imm32(0), output); + break; + case MIRType_Boolean: + case MIRType_Int32: + if (src.typedReg().gpr() != output) + move32(src.typedReg().gpr(), output); + break; + case MIRType_Double: + convertDoubleToInt(src.typedReg().fpu(), output, fail, behavior); + break; + case MIRType_String: + case MIRType_Object: + jump(fail); + break; + default: + MOZ_ASSUME_UNREACHABLE("Bad MIRType"); + } +} + void MacroAssembler::finish() { @@ -1542,10 +1794,10 @@ MacroAssembler::branchIfNotInterpretedConstructor(Register fun, Register scratch } void -MacroAssembler::branchEqualTypeIfNeeded(MIRType type, MDefinition *def, const Register &tag, +MacroAssembler::branchEqualTypeIfNeeded(MIRType type, MDefinition *maybeDef, const Register &tag, Label *label) { - if (def->mightBeType(type)) { + if (!maybeDef || maybeDef->mightBeType(type)) { switch (type) { case MIRType_Null: branchTestNull(Equal, tag, label); diff --git a/js/src/jit/IonMacroAssembler.h b/js/src/jit/IonMacroAssembler.h index f40b8c96fb94..dad4c482f7f4 100644 --- a/js/src/jit/IonMacroAssembler.h +++ b/js/src/jit/IonMacroAssembler.h @@ -630,7 +630,8 @@ class MacroAssembler : public MacroAssemblerSpecific using MacroAssemblerSpecific::ensureDouble; - void ensureDouble(const Address &source, FloatRegister dest, Label *failure) { + template + void ensureDouble(const S &source, FloatRegister dest, Label *failure) { Label isDouble, done; branchTestDouble(Assembler::Equal, source, &isDouble); branchTestInt32(Assembler::NotEqual, source, failure); @@ -646,7 +647,7 @@ class MacroAssembler : public MacroAssemblerSpecific // Emit type case branch on tag matching if the type tag in the definition // might actually be that type. - void branchEqualTypeIfNeeded(MIRType type, MDefinition *def, const Register &tag, + void branchEqualTypeIfNeeded(MIRType type, MDefinition *maybeDef, const Register &tag, Label *label); // Inline allocation. @@ -997,7 +998,151 @@ class MacroAssembler : public MacroAssemblerSpecific void convertInt32ValueToDouble(const Address &address, Register scratch, Label *done); void convertValueToDouble(ValueOperand value, FloatRegister output, Label *fail); - void convertValueToInt32(ValueOperand value, FloatRegister temp, Register output, Label *fail); + bool convertValueToDouble(JSContext *cx, const Value &v, FloatRegister output, Label *fail); + bool convertConstantOrRegisterToDouble(JSContext *cx, ConstantOrRegister src, + FloatRegister output, Label *fail); + void convertTypedOrValueToDouble(TypedOrValueRegister src, FloatRegister output, Label *fail); + + enum IntConversionBehavior { + IntConversion_Normal, + IntConversion_NegativeZeroCheck, + IntConversion_Truncate, + IntConversion_ClampToUint8, + }; + + // + // Functions for converting values to int. + // + void convertDoubleToInt(FloatRegister src, Register output, Label *fail, + IntConversionBehavior behavior); + + // Strings may be handled by providing labels to jump to when the behavior + // is truncation or clamping. The subroutine, usually an OOL call, is + // passed the unboxed string in |stringReg| and should convert it to a + // double store into |temp|. + void convertValueToInt(ValueOperand value, MDefinition *input, + Label *handleStringEntry, Label *handleStringRejoin, + Register stringReg, FloatRegister temp, Register output, + Label *fail, IntConversionBehavior behavior); + void convertValueToInt(ValueOperand value, FloatRegister temp, Register output, Label *fail, + IntConversionBehavior behavior) + { + convertValueToInt(value, NULL, NULL, NULL, InvalidReg, temp, output, fail, behavior); + } + bool convertValueToInt(JSContext *cx, const Value &v, Register output, Label *fail, + IntConversionBehavior behavior); + bool convertConstantOrRegisterToInt(JSContext *cx, ConstantOrRegister src, FloatRegister temp, + Register output, Label *fail, IntConversionBehavior behavior); + void convertTypedOrValueToInt(TypedOrValueRegister src, FloatRegister temp, Register output, + Label *fail, IntConversionBehavior behavior); + + // + // Convenience functions for converting values to int32. + // + void convertValueToInt32(ValueOperand value, FloatRegister temp, Register output, Label *fail, + bool negativeZeroCheck) + { + convertValueToInt(value, temp, output, fail, negativeZeroCheck + ? IntConversion_NegativeZeroCheck + : IntConversion_Normal); + } + void convertValueToInt32(ValueOperand value, MDefinition *input, + FloatRegister temp, Register output, Label *fail, + bool negativeZeroCheck) + { + convertValueToInt(value, input, NULL, NULL, InvalidReg, temp, output, fail, + negativeZeroCheck + ? IntConversion_NegativeZeroCheck + : IntConversion_Normal); + } + bool convertValueToInt32(JSContext *cx, const Value &v, Register output, Label *fail, + bool negativeZeroCheck) + { + return convertValueToInt(cx, v, output, fail, negativeZeroCheck + ? IntConversion_NegativeZeroCheck + : IntConversion_Normal); + } + bool convertConstantOrRegisterToInt32(JSContext *cx, ConstantOrRegister src, FloatRegister temp, + Register output, Label *fail, bool negativeZeroCheck) + { + return convertConstantOrRegisterToInt(cx, src, temp, output, fail, negativeZeroCheck + ? IntConversion_NegativeZeroCheck + : IntConversion_Normal); + } + void convertTypedOrValueToInt32(TypedOrValueRegister src, FloatRegister temp, Register output, + Label *fail, bool negativeZeroCheck) + { + convertTypedOrValueToInt(src, temp, output, fail, negativeZeroCheck + ? IntConversion_NegativeZeroCheck + : IntConversion_Normal); + } + + // + // Convenience functions for truncating values to int32. + // + void truncateValueToInt32(ValueOperand value, FloatRegister temp, Register output, Label *fail) { + convertValueToInt(value, temp, output, fail, IntConversion_Truncate); + } + void truncateValueToInt32(ValueOperand value, MDefinition *input, + Label *handleStringEntry, Label *handleStringRejoin, + Register stringReg, FloatRegister temp, Register output, + Label *fail) + { + convertValueToInt(value, input, handleStringEntry, handleStringRejoin, + stringReg, temp, output, fail, IntConversion_Truncate); + } + void truncateValueToInt32(ValueOperand value, MDefinition *input, + FloatRegister temp, Register output, Label *fail) + { + convertValueToInt(value, input, NULL, NULL, InvalidReg, temp, output, fail, + IntConversion_Truncate); + } + bool truncateValueToInt32(JSContext *cx, const Value &v, Register output, Label *fail) { + return convertValueToInt(cx, v, output, fail, IntConversion_Truncate); + } + bool truncateConstantOrRegisterToInt32(JSContext *cx, ConstantOrRegister src, FloatRegister temp, + Register output, Label *fail) + { + return convertConstantOrRegisterToInt(cx, src, temp, output, fail, IntConversion_Truncate); + } + void truncateTypedOrValueToInt32(TypedOrValueRegister src, FloatRegister temp, Register output, + Label *fail) + { + convertTypedOrValueToInt(src, temp, output, fail, IntConversion_Truncate); + } + + // Convenience functions for clamping values to uint8. + void clampValueToUint8(ValueOperand value, FloatRegister temp, Register output, Label *fail) { + convertValueToInt(value, temp, output, fail, IntConversion_ClampToUint8); + } + void clampValueToUint8(ValueOperand value, MDefinition *input, + Label *handleStringEntry, Label *handleStringRejoin, + Register stringReg, FloatRegister temp, Register output, + Label *fail) + { + convertValueToInt(value, input, handleStringEntry, handleStringRejoin, + stringReg, temp, output, fail, IntConversion_ClampToUint8); + } + void clampValueToUint8(ValueOperand value, MDefinition *input, + FloatRegister temp, Register output, Label *fail) + { + convertValueToInt(value, input, NULL, NULL, InvalidReg, temp, output, fail, + IntConversion_ClampToUint8); + } + bool clampValueToUint8(JSContext *cx, const Value &v, Register output, Label *fail) { + return convertValueToInt(cx, v, output, fail, IntConversion_ClampToUint8); + } + bool clampConstantOrRegisterToUint8(JSContext *cx, ConstantOrRegister src, FloatRegister temp, + Register output, Label *fail) + { + return convertConstantOrRegisterToInt(cx, src, temp, output, fail, + IntConversion_ClampToUint8); + } + void clampTypedOrValueToUint8(TypedOrValueRegister src, FloatRegister temp, Register output, + Label *fail) + { + convertTypedOrValueToInt(src, temp, output, fail, IntConversion_ClampToUint8); + } }; static inline Assembler::DoubleCondition diff --git a/js/src/jit/LIR-Common.h b/js/src/jit/LIR-Common.h index b39fc390e8d3..aac294742420 100644 --- a/js/src/jit/LIR-Common.h +++ b/js/src/jit/LIR-Common.h @@ -3647,6 +3647,9 @@ class LClampVToUint8 : public LInstructionHelper<1, BOX_PIECES, 1> const LDefinition *tempFloat() { return getTemp(0); } + const MClampToUint8 *mir() const { + return mir_->toClampToUint8(); + } }; // Load a boxed value from an object's fixed slot. diff --git a/js/src/jit/Lowering.cpp b/js/src/jit/Lowering.cpp index 6ff369e8cd91..425a0cc2dea5 100644 --- a/js/src/jit/Lowering.cpp +++ b/js/src/jit/Lowering.cpp @@ -2366,7 +2366,7 @@ LIRGenerator::visitClampToUint8(MClampToUint8 *ins) LClampVToUint8 *lir = new LClampVToUint8(tempFloat()); if (!useBox(lir, LClampVToUint8::Input, in)) return false; - return assignSnapshot(lir) && define(lir, ins); + return assignSnapshot(lir) && define(lir, ins) && assignSafepoint(lir, ins); } default: diff --git a/js/src/jit/arm/MacroAssembler-arm.cpp b/js/src/jit/arm/MacroAssembler-arm.cpp index ce7603a72e57..513434c61739 100644 --- a/js/src/jit/arm/MacroAssembler-arm.cpp +++ b/js/src/jit/arm/MacroAssembler-arm.cpp @@ -1734,6 +1734,12 @@ MacroAssemblerARMCompat::move32(const Imm32 &imm, const Register &dest) { ma_mov(imm, dest); } + +void +MacroAssemblerARMCompat::move32(const Register &src, const Register &dest) { + ma_mov(src, dest); +} + void MacroAssemblerARMCompat::movePtr(const Register &src, const Register &dest) { @@ -2582,6 +2588,16 @@ MacroAssemblerARMCompat::unboxDouble(const Address &src, const FloatRegister &de ma_vldr(Operand(src), dest); } +void +MacroAssemblerARMCompat::unboxString(const ValueOperand &operand, const Register &dest) { + ma_mov(operand.payloadReg(), dest); +} + +void +MacroAssemblerARMCompat::unboxString(const Address &src, const Register &dest) { + ma_ldr(payloadOf(src), dest); +} + void MacroAssemblerARMCompat::unboxValue(const ValueOperand &src, AnyRegister dest) { diff --git a/js/src/jit/arm/MacroAssembler-arm.h b/js/src/jit/arm/MacroAssembler-arm.h index 9541ff7a2b19..d63fdcaf5829 100644 --- a/js/src/jit/arm/MacroAssembler-arm.h +++ b/js/src/jit/arm/MacroAssembler-arm.h @@ -718,6 +718,8 @@ class MacroAssemblerARMCompat : public MacroAssemblerARM void unboxBoolean(const Address &src, const Register &dest); void unboxDouble(const ValueOperand &operand, const FloatRegister &dest); void unboxDouble(const Address &src, const FloatRegister &dest); + void unboxString(const ValueOperand &operand, const Register &dest); + void unboxString(const Address &src, const Register &dest); void unboxValue(const ValueOperand &src, AnyRegister dest); void unboxPrivate(const ValueOperand &src, Register dest); @@ -1176,6 +1178,7 @@ class MacroAssemblerARMCompat : public MacroAssemblerARM void addPtr(const Address &src, Register dest); void move32(const Imm32 &imm, const Register &dest); + void move32(const Register &src, const Register &dest); void movePtr(const Register &src, const Register &dest); void movePtr(const ImmWord &imm, const Register &dest); diff --git a/js/src/jit/shared/MacroAssembler-x86-shared.h b/js/src/jit/shared/MacroAssembler-x86-shared.h index ebaea6b60ece..2e4293ff04e5 100644 --- a/js/src/jit/shared/MacroAssembler-x86-shared.h +++ b/js/src/jit/shared/MacroAssembler-x86-shared.h @@ -99,6 +99,9 @@ class MacroAssemblerX86Shared : public Assembler void move32(const Imm32 &imm, const Operand &dest) { movl(imm, dest); } + void move32(const Register &src, const Register &dest) { + movl(src, dest); + } void and32(const Imm32 &imm, const Register &dest) { andl(imm, dest); } diff --git a/js/src/jit/x86/MacroAssembler-x86.h b/js/src/jit/x86/MacroAssembler-x86.h index 080a6b13b72a..a671b38db399 100644 --- a/js/src/jit/x86/MacroAssembler-x86.h +++ b/js/src/jit/x86/MacroAssembler-x86.h @@ -774,6 +774,12 @@ class MacroAssemblerX86 : public MacroAssemblerX86Shared unpcklps(ScratchFloatReg, dest); } } + void unboxString(const ValueOperand &src, const Register &dest) { + movl(src.payloadReg(), dest); + } + void unboxString(const Address &src, const Register &dest) { + movl(payloadOf(src), dest); + } void unboxValue(const ValueOperand &src, AnyRegister dest) { if (dest.isFloat()) { Label notInt32, end;