зеркало из https://github.com/mozilla/gecko-dev.git
Bug 899139 - Part 1: Refactor value-to-int logic into IonMacroAssembler. (r=jandem)
This commit is contained in:
Родитель
f39b202b1a
Коммит
27393bfaa7
|
@ -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);
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -630,7 +630,8 @@ class MacroAssembler : public MacroAssemblerSpecific
|
|||
|
||||
using MacroAssemblerSpecific::ensureDouble;
|
||||
|
||||
void ensureDouble(const Address &source, FloatRegister dest, Label *failure) {
|
||||
template <typename S>
|
||||
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
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -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:
|
||||
|
|
|
@ -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)
|
||||
{
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
|
|
Загрузка…
Ссылка в новой задаче