1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/js/src/jit/TypePolicy.cpp Wed Dec 31 06:09:35 2014 +0100 1.3 @@ -0,0 +1,858 @@ 1.4 +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- 1.5 + * vim: set ts=8 sts=4 et sw=4 tw=99: 1.6 + * This Source Code Form is subject to the terms of the Mozilla Public 1.7 + * License, v. 2.0. If a copy of the MPL was not distributed with this 1.8 + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 1.9 + 1.10 +#include "jit/TypePolicy.h" 1.11 + 1.12 +#include "jit/Lowering.h" 1.13 +#include "jit/MIR.h" 1.14 +#include "jit/MIRGraph.h" 1.15 + 1.16 +using namespace js; 1.17 +using namespace js::jit; 1.18 + 1.19 +using JS::DoubleNaNValue; 1.20 + 1.21 +static void 1.22 +EnsureOperandNotFloat32(TempAllocator &alloc, MInstruction *def, unsigned op) 1.23 +{ 1.24 + MDefinition *in = def->getOperand(op); 1.25 + if (in->type() == MIRType_Float32) { 1.26 + MToDouble *replace = MToDouble::New(alloc, in); 1.27 + def->block()->insertBefore(def, replace); 1.28 + def->replaceOperand(op, replace); 1.29 + } 1.30 +} 1.31 + 1.32 +MDefinition * 1.33 +BoxInputsPolicy::boxAt(TempAllocator &alloc, MInstruction *at, MDefinition *operand) 1.34 +{ 1.35 + if (operand->isUnbox()) 1.36 + return operand->toUnbox()->input(); 1.37 + return alwaysBoxAt(alloc, at, operand); 1.38 +} 1.39 + 1.40 +MDefinition * 1.41 +BoxInputsPolicy::alwaysBoxAt(TempAllocator &alloc, MInstruction *at, MDefinition *operand) 1.42 +{ 1.43 + MDefinition *boxedOperand = operand; 1.44 + // Replace Float32 by double 1.45 + if (operand->type() == MIRType_Float32) { 1.46 + MInstruction *replace = MToDouble::New(alloc, operand); 1.47 + at->block()->insertBefore(at, replace); 1.48 + boxedOperand = replace; 1.49 + } 1.50 + MBox *box = MBox::New(alloc, boxedOperand); 1.51 + at->block()->insertBefore(at, box); 1.52 + return box; 1.53 +} 1.54 + 1.55 +bool 1.56 +BoxInputsPolicy::adjustInputs(TempAllocator &alloc, MInstruction *ins) 1.57 +{ 1.58 + for (size_t i = 0, e = ins->numOperands(); i < e; i++) { 1.59 + MDefinition *in = ins->getOperand(i); 1.60 + if (in->type() == MIRType_Value) 1.61 + continue; 1.62 + ins->replaceOperand(i, boxAt(alloc, ins, in)); 1.63 + } 1.64 + return true; 1.65 +} 1.66 + 1.67 +bool 1.68 +ArithPolicy::adjustInputs(TempAllocator &alloc, MInstruction *ins) 1.69 +{ 1.70 + if (specialization_ == MIRType_None) 1.71 + return BoxInputsPolicy::adjustInputs(alloc, ins); 1.72 + 1.73 + JS_ASSERT(ins->type() == MIRType_Double || ins->type() == MIRType_Int32 || ins->type() == MIRType_Float32); 1.74 + 1.75 + for (size_t i = 0, e = ins->numOperands(); i < e; i++) { 1.76 + MDefinition *in = ins->getOperand(i); 1.77 + if (in->type() == ins->type()) 1.78 + continue; 1.79 + 1.80 + MInstruction *replace; 1.81 + 1.82 + // If the input is a string or an object, the conversion is not 1.83 + // possible, at least, we can't specialize. So box the input. 1.84 + if (in->type() == MIRType_Object || in->type() == MIRType_String || 1.85 + (in->type() == MIRType_Undefined && specialization_ == MIRType_Int32)) 1.86 + { 1.87 + in = boxAt(alloc, ins, in); 1.88 + } 1.89 + 1.90 + if (ins->type() == MIRType_Double) 1.91 + replace = MToDouble::New(alloc, in); 1.92 + else if (ins->type() == MIRType_Float32) 1.93 + replace = MToFloat32::New(alloc, in); 1.94 + else 1.95 + replace = MToInt32::New(alloc, in); 1.96 + 1.97 + ins->block()->insertBefore(ins, replace); 1.98 + ins->replaceOperand(i, replace); 1.99 + } 1.100 + 1.101 + return true; 1.102 +} 1.103 + 1.104 +bool 1.105 +ComparePolicy::adjustInputs(TempAllocator &alloc, MInstruction *def) 1.106 +{ 1.107 + JS_ASSERT(def->isCompare()); 1.108 + MCompare *compare = def->toCompare(); 1.109 + 1.110 + // Convert Float32 operands to doubles 1.111 + for (size_t i = 0; i < 2; i++) { 1.112 + MDefinition *in = def->getOperand(i); 1.113 + if (in->type() == MIRType_Float32) { 1.114 + MInstruction *replace = MToDouble::New(alloc, in); 1.115 + def->block()->insertBefore(def, replace); 1.116 + def->replaceOperand(i, replace); 1.117 + } 1.118 + } 1.119 + 1.120 + // Box inputs to get value 1.121 + if (compare->compareType() == MCompare::Compare_Unknown || 1.122 + compare->compareType() == MCompare::Compare_Value) 1.123 + { 1.124 + return BoxInputsPolicy::adjustInputs(alloc, def); 1.125 + } 1.126 + 1.127 + // Compare_Boolean specialization is done for "Anything === Bool" 1.128 + // If the LHS is boolean, we set the specialization to Compare_Int32. 1.129 + // This matches other comparisons of the form bool === bool and 1.130 + // generated code of Compare_Int32 is more efficient. 1.131 + if (compare->compareType() == MCompare::Compare_Boolean && 1.132 + def->getOperand(0)->type() == MIRType_Boolean) 1.133 + { 1.134 + compare->setCompareType(MCompare::Compare_Int32MaybeCoerceBoth); 1.135 + } 1.136 + 1.137 + // Compare_Boolean specialization is done for "Anything === Bool" 1.138 + // As of previous line Anything can't be Boolean 1.139 + if (compare->compareType() == MCompare::Compare_Boolean) { 1.140 + // Unbox rhs that is definitely Boolean 1.141 + MDefinition *rhs = def->getOperand(1); 1.142 + if (rhs->type() != MIRType_Boolean) { 1.143 + if (rhs->type() != MIRType_Value) 1.144 + rhs = boxAt(alloc, def, rhs); 1.145 + MInstruction *unbox = MUnbox::New(alloc, rhs, MIRType_Boolean, MUnbox::Infallible); 1.146 + def->block()->insertBefore(def, unbox); 1.147 + def->replaceOperand(1, unbox); 1.148 + } 1.149 + 1.150 + JS_ASSERT(def->getOperand(0)->type() != MIRType_Boolean); 1.151 + JS_ASSERT(def->getOperand(1)->type() == MIRType_Boolean); 1.152 + return true; 1.153 + } 1.154 + 1.155 + // Compare_StrictString specialization is done for "Anything === String" 1.156 + // If the LHS is string, we set the specialization to Compare_String. 1.157 + if (compare->compareType() == MCompare::Compare_StrictString && 1.158 + def->getOperand(0)->type() == MIRType_String) 1.159 + { 1.160 + compare->setCompareType(MCompare::Compare_String); 1.161 + } 1.162 + 1.163 + // Compare_StrictString specialization is done for "Anything === String" 1.164 + // As of previous line Anything can't be String 1.165 + if (compare->compareType() == MCompare::Compare_StrictString) { 1.166 + // Unbox rhs that is definitely String 1.167 + MDefinition *rhs = def->getOperand(1); 1.168 + if (rhs->type() != MIRType_String) { 1.169 + if (rhs->type() != MIRType_Value) 1.170 + rhs = boxAt(alloc, def, rhs); 1.171 + MInstruction *unbox = MUnbox::New(alloc, rhs, MIRType_String, MUnbox::Infallible); 1.172 + def->block()->insertBefore(def, unbox); 1.173 + def->replaceOperand(1, unbox); 1.174 + } 1.175 + 1.176 + JS_ASSERT(def->getOperand(0)->type() != MIRType_String); 1.177 + JS_ASSERT(def->getOperand(1)->type() == MIRType_String); 1.178 + return true; 1.179 + } 1.180 + 1.181 + if (compare->compareType() == MCompare::Compare_Undefined || 1.182 + compare->compareType() == MCompare::Compare_Null) 1.183 + { 1.184 + // Nothing to do for undefined and null, lowering handles all types. 1.185 + return true; 1.186 + } 1.187 + 1.188 + // Convert all inputs to the right input type 1.189 + MIRType type = compare->inputType(); 1.190 + JS_ASSERT(type == MIRType_Int32 || type == MIRType_Double || 1.191 + type == MIRType_Object || type == MIRType_String || type == MIRType_Float32); 1.192 + for (size_t i = 0; i < 2; i++) { 1.193 + MDefinition *in = def->getOperand(i); 1.194 + if (in->type() == type) 1.195 + continue; 1.196 + 1.197 + MInstruction *replace; 1.198 + 1.199 + // See BinaryArithPolicy::adjustInputs for an explanation of the following 1.200 + if (in->type() == MIRType_Object || in->type() == MIRType_String || 1.201 + in->type() == MIRType_Undefined) 1.202 + { 1.203 + in = boxAt(alloc, def, in); 1.204 + } 1.205 + 1.206 + switch (type) { 1.207 + case MIRType_Double: { 1.208 + MToDouble::ConversionKind convert = MToDouble::NumbersOnly; 1.209 + if (compare->compareType() == MCompare::Compare_DoubleMaybeCoerceLHS && i == 0) 1.210 + convert = MToDouble::NonNullNonStringPrimitives; 1.211 + else if (compare->compareType() == MCompare::Compare_DoubleMaybeCoerceRHS && i == 1) 1.212 + convert = MToDouble::NonNullNonStringPrimitives; 1.213 + if (in->type() == MIRType_Null || 1.214 + (in->type() == MIRType_Boolean && convert == MToDouble::NumbersOnly)) 1.215 + { 1.216 + in = boxAt(alloc, def, in); 1.217 + } 1.218 + replace = MToDouble::New(alloc, in, convert); 1.219 + break; 1.220 + } 1.221 + case MIRType_Float32: { 1.222 + MToFloat32::ConversionKind convert = MToFloat32::NumbersOnly; 1.223 + if (compare->compareType() == MCompare::Compare_DoubleMaybeCoerceLHS && i == 0) 1.224 + convert = MToFloat32::NonNullNonStringPrimitives; 1.225 + else if (compare->compareType() == MCompare::Compare_DoubleMaybeCoerceRHS && i == 1) 1.226 + convert = MToFloat32::NonNullNonStringPrimitives; 1.227 + if (in->type() == MIRType_Null || 1.228 + (in->type() == MIRType_Boolean && convert == MToFloat32::NumbersOnly)) 1.229 + { 1.230 + in = boxAt(alloc, def, in); 1.231 + } 1.232 + replace = MToFloat32::New(alloc, in, convert); 1.233 + break; 1.234 + } 1.235 + case MIRType_Int32: { 1.236 + MacroAssembler::IntConversionInputKind convert = MacroAssembler::IntConversion_NumbersOnly; 1.237 + if (compare->compareType() == MCompare::Compare_Int32MaybeCoerceBoth || 1.238 + (compare->compareType() == MCompare::Compare_Int32MaybeCoerceLHS && i == 0) || 1.239 + (compare->compareType() == MCompare::Compare_Int32MaybeCoerceRHS && i == 1)) 1.240 + { 1.241 + convert = MacroAssembler::IntConversion_NumbersOrBoolsOnly; 1.242 + } 1.243 + if (convert == MacroAssembler::IntConversion_NumbersOnly) { 1.244 + if (in->type() != MIRType_Int32 && in->type() != MIRType_Value) 1.245 + in = boxAt(alloc, def, in); 1.246 + } else { 1.247 + MOZ_ASSERT(convert == MacroAssembler::IntConversion_NumbersOrBoolsOnly); 1.248 + if (in->type() != MIRType_Int32 && 1.249 + in->type() != MIRType_Boolean && 1.250 + in->type() != MIRType_Value) 1.251 + { 1.252 + in = boxAt(alloc, def, in); 1.253 + } 1.254 + } 1.255 + replace = MToInt32::New(alloc, in, convert); 1.256 + break; 1.257 + } 1.258 + case MIRType_Object: 1.259 + replace = MUnbox::New(alloc, in, MIRType_Object, MUnbox::Infallible); 1.260 + break; 1.261 + case MIRType_String: 1.262 + replace = MUnbox::New(alloc, in, MIRType_String, MUnbox::Infallible); 1.263 + break; 1.264 + default: 1.265 + MOZ_ASSUME_UNREACHABLE("Unknown compare specialization"); 1.266 + } 1.267 + 1.268 + def->block()->insertBefore(def, replace); 1.269 + def->replaceOperand(i, replace); 1.270 + } 1.271 + 1.272 + return true; 1.273 +} 1.274 + 1.275 +bool 1.276 +TypeBarrierPolicy::adjustInputs(TempAllocator &alloc, MInstruction *def) 1.277 +{ 1.278 + MTypeBarrier *ins = def->toTypeBarrier(); 1.279 + MIRType inputType = ins->getOperand(0)->type(); 1.280 + MIRType outputType = ins->type(); 1.281 + 1.282 + // Input and output type are already in accordance. 1.283 + if (inputType == outputType) 1.284 + return true; 1.285 + 1.286 + // Output is a value, currently box the input. 1.287 + if (outputType == MIRType_Value) { 1.288 + // XXX: Possible optimization: decrease resultTypeSet to only include 1.289 + // the inputType. This will remove the need for boxing. 1.290 + JS_ASSERT(inputType != MIRType_Value); 1.291 + ins->replaceOperand(0, boxAt(alloc, ins, ins->getOperand(0))); 1.292 + return true; 1.293 + } 1.294 + 1.295 + // Input is a value. Unbox the input to the requested type. 1.296 + if (inputType == MIRType_Value) { 1.297 + JS_ASSERT(outputType != MIRType_Value); 1.298 + 1.299 + // We can't unbox a value to null/undefined/lazyargs. So keep output 1.300 + // also a value. 1.301 + if (IsNullOrUndefined(outputType) || outputType == MIRType_MagicOptimizedArguments) { 1.302 + JS_ASSERT(ins->defUseCount() == 0); 1.303 + ins->setResultType(MIRType_Value); 1.304 + return true; 1.305 + } 1.306 + 1.307 + MUnbox *unbox = MUnbox::New(alloc, ins->getOperand(0), outputType, MUnbox::TypeBarrier); 1.308 + ins->block()->insertBefore(ins, unbox); 1.309 + ins->replaceOperand(0, unbox); 1.310 + return true; 1.311 + } 1.312 + 1.313 + // In the remaining cases we will alway bail. OutputType doesn't matter. 1.314 + // Take inputType so we can use redefine during lowering. 1.315 + JS_ASSERT(ins->alwaysBails()); 1.316 + ins->setResultType(inputType); 1.317 + 1.318 + return true; 1.319 +} 1.320 + 1.321 +bool 1.322 +TestPolicy::adjustInputs(TempAllocator &alloc, MInstruction *ins) 1.323 +{ 1.324 + MDefinition *op = ins->getOperand(0); 1.325 + switch (op->type()) { 1.326 + case MIRType_Value: 1.327 + case MIRType_Null: 1.328 + case MIRType_Undefined: 1.329 + case MIRType_Boolean: 1.330 + case MIRType_Int32: 1.331 + case MIRType_Double: 1.332 + case MIRType_Float32: 1.333 + case MIRType_Object: 1.334 + break; 1.335 + 1.336 + case MIRType_String: 1.337 + { 1.338 + MStringLength *length = MStringLength::New(alloc, op); 1.339 + ins->block()->insertBefore(ins, length); 1.340 + ins->replaceOperand(0, length); 1.341 + break; 1.342 + } 1.343 + 1.344 + default: 1.345 + ins->replaceOperand(0, boxAt(alloc, ins, op)); 1.346 + break; 1.347 + } 1.348 + return true; 1.349 +} 1.350 + 1.351 +bool 1.352 +BitwisePolicy::adjustInputs(TempAllocator &alloc, MInstruction *ins) 1.353 +{ 1.354 + if (specialization_ == MIRType_None) 1.355 + return BoxInputsPolicy::adjustInputs(alloc, ins); 1.356 + 1.357 + JS_ASSERT(ins->type() == specialization_); 1.358 + JS_ASSERT(specialization_ == MIRType_Int32 || specialization_ == MIRType_Double); 1.359 + 1.360 + // This policy works for both unary and binary bitwise operations. 1.361 + for (size_t i = 0, e = ins->numOperands(); i < e; i++) { 1.362 + MDefinition *in = ins->getOperand(i); 1.363 + if (in->type() == MIRType_Int32) 1.364 + continue; 1.365 + 1.366 + // See BinaryArithPolicy::adjustInputs for an explanation of the following 1.367 + if (in->type() == MIRType_Object || in->type() == MIRType_String) 1.368 + in = boxAt(alloc, ins, in); 1.369 + 1.370 + MInstruction *replace = MTruncateToInt32::New(alloc, in); 1.371 + ins->block()->insertBefore(ins, replace); 1.372 + ins->replaceOperand(i, replace); 1.373 + } 1.374 + 1.375 + return true; 1.376 +} 1.377 + 1.378 +bool 1.379 +PowPolicy::adjustInputs(TempAllocator &alloc, MInstruction *ins) 1.380 +{ 1.381 + JS_ASSERT(specialization_ == MIRType_Int32 || specialization_ == MIRType_Double); 1.382 + 1.383 + // Input must be a double. 1.384 + if (!DoublePolicy<0>::staticAdjustInputs(alloc, ins)) 1.385 + return false; 1.386 + 1.387 + // Power may be an int32 or a double. Integers receive a faster path. 1.388 + if (specialization_ == MIRType_Double) 1.389 + return DoublePolicy<1>::staticAdjustInputs(alloc, ins); 1.390 + return IntPolicy<1>::staticAdjustInputs(alloc, ins); 1.391 +} 1.392 + 1.393 +template <unsigned Op> 1.394 +bool 1.395 +StringPolicy<Op>::staticAdjustInputs(TempAllocator &alloc, MInstruction *ins) 1.396 +{ 1.397 + MDefinition *in = ins->getOperand(Op); 1.398 + if (in->type() == MIRType_String) 1.399 + return true; 1.400 + 1.401 + if (in->type() != MIRType_Value) 1.402 + in = boxAt(alloc, ins, in); 1.403 + 1.404 + MUnbox *replace = MUnbox::New(alloc, in, MIRType_String, MUnbox::Fallible); 1.405 + ins->block()->insertBefore(ins, replace); 1.406 + ins->replaceOperand(Op, replace); 1.407 + return true; 1.408 +} 1.409 + 1.410 +template bool StringPolicy<0>::staticAdjustInputs(TempAllocator &alloc, MInstruction *ins); 1.411 +template bool StringPolicy<1>::staticAdjustInputs(TempAllocator &alloc, MInstruction *ins); 1.412 +template bool StringPolicy<2>::staticAdjustInputs(TempAllocator &alloc, MInstruction *ins); 1.413 + 1.414 +template <unsigned Op> 1.415 +bool 1.416 +ConvertToStringPolicy<Op>::staticAdjustInputs(TempAllocator &alloc, MInstruction *ins) 1.417 +{ 1.418 + MDefinition *in = ins->getOperand(Op); 1.419 + if (in->type() == MIRType_String) 1.420 + return true; 1.421 + 1.422 + MInstruction *replace; 1.423 + if (in->mightBeType(MIRType_Object)) { 1.424 + if (in->type() != MIRType_Value) 1.425 + in = boxAt(alloc, ins, in); 1.426 + 1.427 + replace = MUnbox::New(alloc, in, MIRType_String, MUnbox::Fallible); 1.428 + } else { 1.429 + // TODO remove these two lines once 966957 has landed 1.430 + EnsureOperandNotFloat32(alloc, ins, Op); 1.431 + in = ins->getOperand(Op); 1.432 + replace = MToString::New(alloc, in); 1.433 + } 1.434 + 1.435 + ins->block()->insertBefore(ins, replace); 1.436 + ins->replaceOperand(Op, replace); 1.437 + return true; 1.438 +} 1.439 + 1.440 +template bool ConvertToStringPolicy<0>::staticAdjustInputs(TempAllocator &alloc, MInstruction *ins); 1.441 +template bool ConvertToStringPolicy<1>::staticAdjustInputs(TempAllocator &alloc, MInstruction *ins); 1.442 + 1.443 +template <unsigned Op> 1.444 +bool 1.445 +IntPolicy<Op>::staticAdjustInputs(TempAllocator &alloc, MInstruction *def) 1.446 +{ 1.447 + MDefinition *in = def->getOperand(Op); 1.448 + if (in->type() == MIRType_Int32) 1.449 + return true; 1.450 + 1.451 + if (in->type() != MIRType_Value) 1.452 + in = boxAt(alloc, def, in); 1.453 + 1.454 + MUnbox *replace = MUnbox::New(alloc, in, MIRType_Int32, MUnbox::Fallible); 1.455 + def->block()->insertBefore(def, replace); 1.456 + def->replaceOperand(Op, replace); 1.457 + return true; 1.458 +} 1.459 + 1.460 +template bool IntPolicy<0>::staticAdjustInputs(TempAllocator &alloc, MInstruction *def); 1.461 +template bool IntPolicy<1>::staticAdjustInputs(TempAllocator &alloc, MInstruction *def); 1.462 +template bool IntPolicy<2>::staticAdjustInputs(TempAllocator &alloc, MInstruction *def); 1.463 + 1.464 +template <unsigned Op> 1.465 +bool 1.466 +ConvertToInt32Policy<Op>::staticAdjustInputs(TempAllocator &alloc, MInstruction *def) 1.467 +{ 1.468 + MDefinition *in = def->getOperand(Op); 1.469 + if (in->type() == MIRType_Int32) 1.470 + return true; 1.471 + 1.472 + MToInt32 *replace = MToInt32::New(alloc, in); 1.473 + def->block()->insertBefore(def, replace); 1.474 + def->replaceOperand(Op, replace); 1.475 + return true; 1.476 +} 1.477 + 1.478 +template bool ConvertToInt32Policy<0>::staticAdjustInputs(TempAllocator &alloc, MInstruction *def); 1.479 + 1.480 +template <unsigned Op> 1.481 +bool 1.482 +DoublePolicy<Op>::staticAdjustInputs(TempAllocator &alloc, MInstruction *def) 1.483 +{ 1.484 + MDefinition *in = def->getOperand(Op); 1.485 + if (in->type() == MIRType_Double) 1.486 + return true; 1.487 + 1.488 + // Force a bailout. Objects may be effectful; strings are currently unhandled. 1.489 + if (in->type() == MIRType_Object || in->type() == MIRType_String) { 1.490 + MBox *box = MBox::New(alloc, in); 1.491 + def->block()->insertBefore(def, box); 1.492 + 1.493 + MUnbox *unbox = MUnbox::New(alloc, box, MIRType_Double, MUnbox::Fallible); 1.494 + def->block()->insertBefore(def, unbox); 1.495 + def->replaceOperand(Op, unbox); 1.496 + return true; 1.497 + } 1.498 + 1.499 + MToDouble *replace = MToDouble::New(alloc, in); 1.500 + def->block()->insertBefore(def, replace); 1.501 + def->replaceOperand(Op, replace); 1.502 + return true; 1.503 +} 1.504 + 1.505 +template bool DoublePolicy<0>::staticAdjustInputs(TempAllocator &alloc, MInstruction *def); 1.506 +template bool DoublePolicy<1>::staticAdjustInputs(TempAllocator &alloc, MInstruction *def); 1.507 + 1.508 +template <unsigned Op> 1.509 +bool 1.510 +Float32Policy<Op>::staticAdjustInputs(TempAllocator &alloc, MInstruction *def) 1.511 +{ 1.512 + MDefinition *in = def->getOperand(Op); 1.513 + if (in->type() == MIRType_Float32) 1.514 + return true; 1.515 + 1.516 + // Force a bailout. Objects may be effectful; strings are currently unhandled. 1.517 + if (in->type() == MIRType_Object || in->type() == MIRType_String) { 1.518 + MToDouble *toDouble = MToDouble::New(alloc, in); 1.519 + def->block()->insertBefore(def, toDouble); 1.520 + 1.521 + MBox *box = MBox::New(alloc, toDouble); 1.522 + def->block()->insertBefore(def, box); 1.523 + 1.524 + MUnbox *unbox = MUnbox::New(alloc, box, MIRType_Double, MUnbox::Fallible); 1.525 + def->block()->insertBefore(def, unbox); 1.526 + 1.527 + MToFloat32 *toFloat32 = MToFloat32::New(alloc, unbox); 1.528 + def->block()->insertBefore(def, toFloat32); 1.529 + 1.530 + def->replaceOperand(Op, unbox); 1.531 + 1.532 + return true; 1.533 + } 1.534 + 1.535 + MToFloat32 *replace = MToFloat32::New(alloc, in); 1.536 + def->block()->insertBefore(def, replace); 1.537 + def->replaceOperand(Op, replace); 1.538 + return true; 1.539 +} 1.540 + 1.541 +template bool Float32Policy<0>::staticAdjustInputs(TempAllocator &alloc, MInstruction *def); 1.542 +template bool Float32Policy<1>::staticAdjustInputs(TempAllocator &alloc, MInstruction *def); 1.543 +template bool Float32Policy<2>::staticAdjustInputs(TempAllocator &alloc, MInstruction *def); 1.544 + 1.545 +template <unsigned Op> 1.546 +bool 1.547 +NoFloatPolicy<Op>::staticAdjustInputs(TempAllocator &alloc, MInstruction *def) 1.548 +{ 1.549 + EnsureOperandNotFloat32(alloc, def, Op); 1.550 + return true; 1.551 +} 1.552 + 1.553 +template bool NoFloatPolicy<0>::staticAdjustInputs(TempAllocator &alloc, MInstruction *def); 1.554 +template bool NoFloatPolicy<1>::staticAdjustInputs(TempAllocator &alloc, MInstruction *def); 1.555 +template bool NoFloatPolicy<2>::staticAdjustInputs(TempAllocator &alloc, MInstruction *def); 1.556 +template bool NoFloatPolicy<3>::staticAdjustInputs(TempAllocator &alloc, MInstruction *def); 1.557 + 1.558 +template <unsigned Op> 1.559 +bool 1.560 +BoxPolicy<Op>::staticAdjustInputs(TempAllocator &alloc, MInstruction *ins) 1.561 +{ 1.562 + MDefinition *in = ins->getOperand(Op); 1.563 + if (in->type() == MIRType_Value) 1.564 + return true; 1.565 + 1.566 + ins->replaceOperand(Op, boxAt(alloc, ins, in)); 1.567 + return true; 1.568 +} 1.569 + 1.570 +template bool BoxPolicy<0>::staticAdjustInputs(TempAllocator &alloc, MInstruction *ins); 1.571 +template bool BoxPolicy<1>::staticAdjustInputs(TempAllocator &alloc, MInstruction *ins); 1.572 +template bool BoxPolicy<2>::staticAdjustInputs(TempAllocator &alloc, MInstruction *ins); 1.573 + 1.574 +template <unsigned Op, MIRType Type> 1.575 +bool 1.576 +BoxExceptPolicy<Op, Type>::staticAdjustInputs(TempAllocator &alloc, MInstruction *ins) 1.577 +{ 1.578 + MDefinition *in = ins->getOperand(Op); 1.579 + if (in->type() == Type) 1.580 + return true; 1.581 + return BoxPolicy<Op>::staticAdjustInputs(alloc, ins); 1.582 +} 1.583 + 1.584 +template bool BoxExceptPolicy<0, MIRType_String>::staticAdjustInputs(TempAllocator &alloc, 1.585 + MInstruction *ins); 1.586 +template bool BoxExceptPolicy<1, MIRType_String>::staticAdjustInputs(TempAllocator &alloc, 1.587 + MInstruction *ins); 1.588 +template bool BoxExceptPolicy<2, MIRType_String>::staticAdjustInputs(TempAllocator &alloc, 1.589 + MInstruction *ins); 1.590 + 1.591 +bool 1.592 +ToDoublePolicy::staticAdjustInputs(TempAllocator &alloc, MInstruction *ins) 1.593 +{ 1.594 + MDefinition *in = ins->getOperand(0); 1.595 + if (in->type() != MIRType_Object && in->type() != MIRType_String) 1.596 + return true; 1.597 + 1.598 + in = boxAt(alloc, ins, in); 1.599 + ins->replaceOperand(0, in); 1.600 + return true; 1.601 +} 1.602 + 1.603 +bool 1.604 +ToInt32Policy::staticAdjustInputs(TempAllocator &alloc, MInstruction *ins) 1.605 +{ 1.606 + JS_ASSERT(ins->isToInt32()); 1.607 + 1.608 + MDefinition *in = ins->getOperand(0); 1.609 + switch (in->type()) { 1.610 + case MIRType_Object: 1.611 + case MIRType_String: 1.612 + case MIRType_Undefined: 1.613 + // Objects might be effectful. Undefined coerces to NaN, not int32. 1.614 + in = boxAt(alloc, ins, in); 1.615 + ins->replaceOperand(0, in); 1.616 + break; 1.617 + default: 1.618 + break; 1.619 + } 1.620 + 1.621 + return true; 1.622 +} 1.623 + 1.624 +template <unsigned Op> 1.625 +bool 1.626 +ObjectPolicy<Op>::staticAdjustInputs(TempAllocator &alloc, MInstruction *ins) 1.627 +{ 1.628 + MDefinition *in = ins->getOperand(Op); 1.629 + if (in->type() == MIRType_Object || in->type() == MIRType_Slots || 1.630 + in->type() == MIRType_Elements) 1.631 + { 1.632 + return true; 1.633 + } 1.634 + 1.635 + if (in->type() != MIRType_Value) 1.636 + in = boxAt(alloc, ins, in); 1.637 + 1.638 + MUnbox *replace = MUnbox::New(alloc, in, MIRType_Object, MUnbox::Fallible); 1.639 + ins->block()->insertBefore(ins, replace); 1.640 + ins->replaceOperand(Op, replace); 1.641 + return true; 1.642 +} 1.643 + 1.644 +template bool ObjectPolicy<0>::staticAdjustInputs(TempAllocator &alloc, MInstruction *ins); 1.645 +template bool ObjectPolicy<1>::staticAdjustInputs(TempAllocator &alloc, MInstruction *ins); 1.646 +template bool ObjectPolicy<2>::staticAdjustInputs(TempAllocator &alloc, MInstruction *ins); 1.647 +template bool ObjectPolicy<3>::staticAdjustInputs(TempAllocator &alloc, MInstruction *ins); 1.648 + 1.649 +bool 1.650 +CallPolicy::adjustInputs(TempAllocator &alloc, MInstruction *ins) 1.651 +{ 1.652 + MCall *call = ins->toCall(); 1.653 + 1.654 + MDefinition *func = call->getFunction(); 1.655 + if (func->type() != MIRType_Object) { 1.656 + // If the function is impossible to call, 1.657 + // bail out by causing a subsequent unbox to fail. 1.658 + if (func->type() != MIRType_Value) 1.659 + func = boxAt(alloc, call, func); 1.660 + 1.661 + MInstruction *unbox = MUnbox::New(alloc, func, MIRType_Object, MUnbox::Fallible); 1.662 + call->block()->insertBefore(call, unbox); 1.663 + call->replaceFunction(unbox); 1.664 + } 1.665 + 1.666 + for (uint32_t i = 0; i < call->numStackArgs(); i++) 1.667 + EnsureOperandNotFloat32(alloc, call, MCall::IndexOfStackArg(i)); 1.668 + 1.669 + return true; 1.670 +} 1.671 + 1.672 +bool 1.673 +CallSetElementPolicy::adjustInputs(TempAllocator &alloc, MInstruction *ins) 1.674 +{ 1.675 + // The first operand should be an object. 1.676 + SingleObjectPolicy::adjustInputs(alloc, ins); 1.677 + 1.678 + // Box the index and value operands. 1.679 + for (size_t i = 1, e = ins->numOperands(); i < e; i++) { 1.680 + MDefinition *in = ins->getOperand(i); 1.681 + if (in->type() == MIRType_Value) 1.682 + continue; 1.683 + ins->replaceOperand(i, boxAt(alloc, ins, in)); 1.684 + } 1.685 + return true; 1.686 +} 1.687 + 1.688 +bool 1.689 +InstanceOfPolicy::adjustInputs(TempAllocator &alloc, MInstruction *def) 1.690 +{ 1.691 + // Box first operand if it isn't object 1.692 + if (def->getOperand(0)->type() != MIRType_Object) 1.693 + BoxPolicy<0>::staticAdjustInputs(alloc, def); 1.694 + 1.695 + return true; 1.696 +} 1.697 + 1.698 +bool 1.699 +StoreTypedArrayPolicy::adjustValueInput(TempAllocator &alloc, MInstruction *ins, int arrayType, 1.700 + MDefinition *value, int valueOperand) 1.701 +{ 1.702 + MDefinition *curValue = value; 1.703 + // First, ensure the value is int32, boolean, double or Value. 1.704 + // The conversion is based on TypedArrayObjectTemplate::setElementTail. 1.705 + switch (value->type()) { 1.706 + case MIRType_Int32: 1.707 + case MIRType_Double: 1.708 + case MIRType_Float32: 1.709 + case MIRType_Boolean: 1.710 + case MIRType_Value: 1.711 + break; 1.712 + case MIRType_Null: 1.713 + value->setImplicitlyUsedUnchecked(); 1.714 + value = MConstant::New(alloc, Int32Value(0)); 1.715 + ins->block()->insertBefore(ins, value->toInstruction()); 1.716 + break; 1.717 + case MIRType_Undefined: 1.718 + value->setImplicitlyUsedUnchecked(); 1.719 + value = MConstant::New(alloc, DoubleNaNValue()); 1.720 + ins->block()->insertBefore(ins, value->toInstruction()); 1.721 + break; 1.722 + case MIRType_Object: 1.723 + case MIRType_String: 1.724 + value = boxAt(alloc, ins, value); 1.725 + break; 1.726 + default: 1.727 + MOZ_ASSUME_UNREACHABLE("Unexpected type"); 1.728 + } 1.729 + 1.730 + if (value != curValue) { 1.731 + ins->replaceOperand(valueOperand, value); 1.732 + curValue = value; 1.733 + } 1.734 + 1.735 + JS_ASSERT(value->type() == MIRType_Int32 || 1.736 + value->type() == MIRType_Boolean || 1.737 + value->type() == MIRType_Double || 1.738 + value->type() == MIRType_Float32 || 1.739 + value->type() == MIRType_Value); 1.740 + 1.741 + switch (arrayType) { 1.742 + case ScalarTypeDescr::TYPE_INT8: 1.743 + case ScalarTypeDescr::TYPE_UINT8: 1.744 + case ScalarTypeDescr::TYPE_INT16: 1.745 + case ScalarTypeDescr::TYPE_UINT16: 1.746 + case ScalarTypeDescr::TYPE_INT32: 1.747 + case ScalarTypeDescr::TYPE_UINT32: 1.748 + if (value->type() != MIRType_Int32) { 1.749 + value = MTruncateToInt32::New(alloc, value); 1.750 + ins->block()->insertBefore(ins, value->toInstruction()); 1.751 + } 1.752 + break; 1.753 + case ScalarTypeDescr::TYPE_UINT8_CLAMPED: 1.754 + // IonBuilder should have inserted ClampToUint8. 1.755 + JS_ASSERT(value->type() == MIRType_Int32); 1.756 + break; 1.757 + case ScalarTypeDescr::TYPE_FLOAT32: 1.758 + if (LIRGenerator::allowFloat32Optimizations()) { 1.759 + if (value->type() != MIRType_Float32) { 1.760 + value = MToFloat32::New(alloc, value); 1.761 + ins->block()->insertBefore(ins, value->toInstruction()); 1.762 + } 1.763 + break; 1.764 + } 1.765 + // Fallthrough: if the LIRGenerator cannot directly store Float32, it will expect the 1.766 + // stored value to be a double. 1.767 + case ScalarTypeDescr::TYPE_FLOAT64: 1.768 + if (value->type() != MIRType_Double) { 1.769 + value = MToDouble::New(alloc, value); 1.770 + ins->block()->insertBefore(ins, value->toInstruction()); 1.771 + } 1.772 + break; 1.773 + default: 1.774 + MOZ_ASSUME_UNREACHABLE("Invalid array type"); 1.775 + } 1.776 + 1.777 + if (value != curValue) { 1.778 + ins->replaceOperand(valueOperand, value); 1.779 + curValue = value; 1.780 + } 1.781 + return true; 1.782 +} 1.783 + 1.784 +bool 1.785 +StoreTypedArrayPolicy::adjustInputs(TempAllocator &alloc, MInstruction *ins) 1.786 +{ 1.787 + MStoreTypedArrayElement *store = ins->toStoreTypedArrayElement(); 1.788 + JS_ASSERT(store->elements()->type() == MIRType_Elements); 1.789 + JS_ASSERT(store->index()->type() == MIRType_Int32); 1.790 + 1.791 + return adjustValueInput(alloc, ins, store->arrayType(), store->value(), 2); 1.792 +} 1.793 + 1.794 +bool 1.795 +StoreTypedArrayHolePolicy::adjustInputs(TempAllocator &alloc, MInstruction *ins) 1.796 +{ 1.797 + MStoreTypedArrayElementHole *store = ins->toStoreTypedArrayElementHole(); 1.798 + JS_ASSERT(store->elements()->type() == MIRType_Elements); 1.799 + JS_ASSERT(store->index()->type() == MIRType_Int32); 1.800 + JS_ASSERT(store->length()->type() == MIRType_Int32); 1.801 + 1.802 + return adjustValueInput(alloc, ins, store->arrayType(), store->value(), 3); 1.803 +} 1.804 + 1.805 +bool 1.806 +StoreTypedArrayElementStaticPolicy::adjustInputs(TempAllocator &alloc, MInstruction *ins) 1.807 +{ 1.808 + MStoreTypedArrayElementStatic *store = ins->toStoreTypedArrayElementStatic(); 1.809 + 1.810 + return ConvertToInt32Policy<0>::staticAdjustInputs(alloc, ins) && 1.811 + adjustValueInput(alloc, ins, store->viewType(), store->value(), 1); 1.812 +} 1.813 + 1.814 +bool 1.815 +ClampPolicy::adjustInputs(TempAllocator &alloc, MInstruction *ins) 1.816 +{ 1.817 + MDefinition *in = ins->toClampToUint8()->input(); 1.818 + 1.819 + switch (in->type()) { 1.820 + case MIRType_Int32: 1.821 + case MIRType_Double: 1.822 + case MIRType_Value: 1.823 + break; 1.824 + default: 1.825 + ins->replaceOperand(0, boxAt(alloc, ins, in)); 1.826 + break; 1.827 + } 1.828 + 1.829 + return true; 1.830 +} 1.831 + 1.832 +bool 1.833 +FilterTypeSetPolicy::adjustInputs(TempAllocator &alloc, MInstruction *ins) 1.834 +{ 1.835 + MOZ_ASSERT(ins->numOperands() == 1); 1.836 + 1.837 + // Do nothing if already same type. 1.838 + if (ins->type() == ins->getOperand(0)->type()) 1.839 + return true; 1.840 + 1.841 + // Box input if ouput type is MIRType_Value 1.842 + if (ins->type() == MIRType_Value) { 1.843 + ins->replaceOperand(0, boxAt(alloc, ins, ins->getOperand(0))); 1.844 + return true; 1.845 + } 1.846 + 1.847 + // For simplicity just mark output type as MIRType_Value if input type 1.848 + // is MIRType_Value. It should be possible to unbox, but we need to 1.849 + // add extra code for Undefined/Null. 1.850 + if (ins->getOperand(0)->type() == MIRType_Value) { 1.851 + ins->setResultType(MIRType_Value); 1.852 + return true; 1.853 + } 1.854 + 1.855 + // In all other cases we will definitely bail, since types don't 1.856 + // correspond. Just box and mark output as MIRType_Value. 1.857 + ins->replaceOperand(0, boxAt(alloc, ins, ins->getOperand(0))); 1.858 + ins->setResultType(MIRType_Value); 1.859 + 1.860 + return true; 1.861 +}