js/src/jit/TypePolicy.cpp

changeset 0
6474c204b198
     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 +}

mercurial