js/src/jit/TypePolicy.cpp

Sat, 03 Jan 2015 20:18:00 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Sat, 03 Jan 2015 20:18:00 +0100
branch
TOR_BUG_3246
changeset 7
129ffea94266
permissions
-rw-r--r--

Conditionally enable double key logic according to:
private browsing mode or privacy.thirdparty.isolate preference and
implement in GetCookieStringCommon and FindCookie where it counts...
With some reservations of how to convince FindCookie users to test
condition and pass a nullptr when disabling double key logic.

     1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
     2  * vim: set ts=8 sts=4 et sw=4 tw=99:
     3  * This Source Code Form is subject to the terms of the Mozilla Public
     4  * License, v. 2.0. If a copy of the MPL was not distributed with this
     5  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
     7 #include "jit/TypePolicy.h"
     9 #include "jit/Lowering.h"
    10 #include "jit/MIR.h"
    11 #include "jit/MIRGraph.h"
    13 using namespace js;
    14 using namespace js::jit;
    16 using JS::DoubleNaNValue;
    18 static void
    19 EnsureOperandNotFloat32(TempAllocator &alloc, MInstruction *def, unsigned op)
    20 {
    21     MDefinition *in = def->getOperand(op);
    22     if (in->type() == MIRType_Float32) {
    23         MToDouble *replace = MToDouble::New(alloc, in);
    24         def->block()->insertBefore(def, replace);
    25         def->replaceOperand(op, replace);
    26     }
    27 }
    29 MDefinition *
    30 BoxInputsPolicy::boxAt(TempAllocator &alloc, MInstruction *at, MDefinition *operand)
    31 {
    32     if (operand->isUnbox())
    33         return operand->toUnbox()->input();
    34     return alwaysBoxAt(alloc, at, operand);
    35 }
    37 MDefinition *
    38 BoxInputsPolicy::alwaysBoxAt(TempAllocator &alloc, MInstruction *at, MDefinition *operand)
    39 {
    40     MDefinition *boxedOperand = operand;
    41     // Replace Float32 by double
    42     if (operand->type() == MIRType_Float32) {
    43         MInstruction *replace = MToDouble::New(alloc, operand);
    44         at->block()->insertBefore(at, replace);
    45         boxedOperand = replace;
    46     }
    47     MBox *box = MBox::New(alloc, boxedOperand);
    48     at->block()->insertBefore(at, box);
    49     return box;
    50 }
    52 bool
    53 BoxInputsPolicy::adjustInputs(TempAllocator &alloc, MInstruction *ins)
    54 {
    55     for (size_t i = 0, e = ins->numOperands(); i < e; i++) {
    56         MDefinition *in = ins->getOperand(i);
    57         if (in->type() == MIRType_Value)
    58             continue;
    59         ins->replaceOperand(i, boxAt(alloc, ins, in));
    60     }
    61     return true;
    62 }
    64 bool
    65 ArithPolicy::adjustInputs(TempAllocator &alloc, MInstruction *ins)
    66 {
    67     if (specialization_ == MIRType_None)
    68         return BoxInputsPolicy::adjustInputs(alloc, ins);
    70     JS_ASSERT(ins->type() == MIRType_Double || ins->type() == MIRType_Int32 || ins->type() == MIRType_Float32);
    72     for (size_t i = 0, e = ins->numOperands(); i < e; i++) {
    73         MDefinition *in = ins->getOperand(i);
    74         if (in->type() == ins->type())
    75             continue;
    77         MInstruction *replace;
    79         // If the input is a string or an object, the conversion is not
    80         // possible, at least, we can't specialize. So box the input.
    81         if (in->type() == MIRType_Object || in->type() == MIRType_String ||
    82             (in->type() == MIRType_Undefined && specialization_ == MIRType_Int32))
    83         {
    84             in = boxAt(alloc, ins, in);
    85         }
    87         if (ins->type() == MIRType_Double)
    88             replace = MToDouble::New(alloc, in);
    89         else if (ins->type() == MIRType_Float32)
    90             replace = MToFloat32::New(alloc, in);
    91         else
    92             replace = MToInt32::New(alloc, in);
    94         ins->block()->insertBefore(ins, replace);
    95         ins->replaceOperand(i, replace);
    96     }
    98     return true;
    99 }
   101 bool
   102 ComparePolicy::adjustInputs(TempAllocator &alloc, MInstruction *def)
   103 {
   104     JS_ASSERT(def->isCompare());
   105     MCompare *compare = def->toCompare();
   107     // Convert Float32 operands to doubles
   108     for (size_t i = 0; i < 2; i++) {
   109         MDefinition *in = def->getOperand(i);
   110         if (in->type() == MIRType_Float32) {
   111             MInstruction *replace = MToDouble::New(alloc, in);
   112             def->block()->insertBefore(def, replace);
   113             def->replaceOperand(i, replace);
   114         }
   115     }
   117     // Box inputs to get value
   118     if (compare->compareType() == MCompare::Compare_Unknown ||
   119         compare->compareType() == MCompare::Compare_Value)
   120     {
   121         return BoxInputsPolicy::adjustInputs(alloc, def);
   122     }
   124     // Compare_Boolean specialization is done for "Anything === Bool"
   125     // If the LHS is boolean, we set the specialization to Compare_Int32.
   126     // This matches other comparisons of the form bool === bool and
   127     // generated code of Compare_Int32 is more efficient.
   128     if (compare->compareType() == MCompare::Compare_Boolean &&
   129         def->getOperand(0)->type() == MIRType_Boolean)
   130     {
   131        compare->setCompareType(MCompare::Compare_Int32MaybeCoerceBoth);
   132     }
   134     // Compare_Boolean specialization is done for "Anything === Bool"
   135     // As of previous line Anything can't be Boolean
   136     if (compare->compareType() == MCompare::Compare_Boolean) {
   137         // Unbox rhs that is definitely Boolean
   138         MDefinition *rhs = def->getOperand(1);
   139         if (rhs->type() != MIRType_Boolean) {
   140             if (rhs->type() != MIRType_Value)
   141                 rhs = boxAt(alloc, def, rhs);
   142             MInstruction *unbox = MUnbox::New(alloc, rhs, MIRType_Boolean, MUnbox::Infallible);
   143             def->block()->insertBefore(def, unbox);
   144             def->replaceOperand(1, unbox);
   145         }
   147         JS_ASSERT(def->getOperand(0)->type() != MIRType_Boolean);
   148         JS_ASSERT(def->getOperand(1)->type() == MIRType_Boolean);
   149         return true;
   150     }
   152     // Compare_StrictString specialization is done for "Anything === String"
   153     // If the LHS is string, we set the specialization to Compare_String.
   154     if (compare->compareType() == MCompare::Compare_StrictString &&
   155         def->getOperand(0)->type() == MIRType_String)
   156     {
   157        compare->setCompareType(MCompare::Compare_String);
   158     }
   160     // Compare_StrictString specialization is done for "Anything === String"
   161     // As of previous line Anything can't be String
   162     if (compare->compareType() == MCompare::Compare_StrictString) {
   163         // Unbox rhs that is definitely String
   164         MDefinition *rhs = def->getOperand(1);
   165         if (rhs->type() != MIRType_String) {
   166             if (rhs->type() != MIRType_Value)
   167                 rhs = boxAt(alloc, def, rhs);
   168             MInstruction *unbox = MUnbox::New(alloc, rhs, MIRType_String, MUnbox::Infallible);
   169             def->block()->insertBefore(def, unbox);
   170             def->replaceOperand(1, unbox);
   171         }
   173         JS_ASSERT(def->getOperand(0)->type() != MIRType_String);
   174         JS_ASSERT(def->getOperand(1)->type() == MIRType_String);
   175         return true;
   176     }
   178     if (compare->compareType() == MCompare::Compare_Undefined ||
   179         compare->compareType() == MCompare::Compare_Null)
   180     {
   181         // Nothing to do for undefined and null, lowering handles all types.
   182         return true;
   183     }
   185     // Convert all inputs to the right input type
   186     MIRType type = compare->inputType();
   187     JS_ASSERT(type == MIRType_Int32 || type == MIRType_Double ||
   188               type == MIRType_Object || type == MIRType_String || type == MIRType_Float32);
   189     for (size_t i = 0; i < 2; i++) {
   190         MDefinition *in = def->getOperand(i);
   191         if (in->type() == type)
   192             continue;
   194         MInstruction *replace;
   196         // See BinaryArithPolicy::adjustInputs for an explanation of the following
   197         if (in->type() == MIRType_Object || in->type() == MIRType_String ||
   198             in->type() == MIRType_Undefined)
   199         {
   200             in = boxAt(alloc, def, in);
   201         }
   203         switch (type) {
   204           case MIRType_Double: {
   205             MToDouble::ConversionKind convert = MToDouble::NumbersOnly;
   206             if (compare->compareType() == MCompare::Compare_DoubleMaybeCoerceLHS && i == 0)
   207                 convert = MToDouble::NonNullNonStringPrimitives;
   208             else if (compare->compareType() == MCompare::Compare_DoubleMaybeCoerceRHS && i == 1)
   209                 convert = MToDouble::NonNullNonStringPrimitives;
   210             if (in->type() == MIRType_Null ||
   211                 (in->type() == MIRType_Boolean && convert == MToDouble::NumbersOnly))
   212             {
   213                 in = boxAt(alloc, def, in);
   214             }
   215             replace = MToDouble::New(alloc, in, convert);
   216             break;
   217           }
   218           case MIRType_Float32: {
   219             MToFloat32::ConversionKind convert = MToFloat32::NumbersOnly;
   220             if (compare->compareType() == MCompare::Compare_DoubleMaybeCoerceLHS && i == 0)
   221                 convert = MToFloat32::NonNullNonStringPrimitives;
   222             else if (compare->compareType() == MCompare::Compare_DoubleMaybeCoerceRHS && i == 1)
   223                 convert = MToFloat32::NonNullNonStringPrimitives;
   224             if (in->type() == MIRType_Null ||
   225                 (in->type() == MIRType_Boolean && convert == MToFloat32::NumbersOnly))
   226             {
   227                 in = boxAt(alloc, def, in);
   228             }
   229             replace = MToFloat32::New(alloc, in, convert);
   230             break;
   231           }
   232           case MIRType_Int32: {
   233             MacroAssembler::IntConversionInputKind convert = MacroAssembler::IntConversion_NumbersOnly;
   234             if (compare->compareType() == MCompare::Compare_Int32MaybeCoerceBoth ||
   235                 (compare->compareType() == MCompare::Compare_Int32MaybeCoerceLHS && i == 0) ||
   236                 (compare->compareType() == MCompare::Compare_Int32MaybeCoerceRHS && i == 1))
   237             {
   238                 convert = MacroAssembler::IntConversion_NumbersOrBoolsOnly;
   239             }
   240             if (convert == MacroAssembler::IntConversion_NumbersOnly) {
   241                 if (in->type() != MIRType_Int32 && in->type() != MIRType_Value)
   242                     in = boxAt(alloc, def, in);
   243             } else {
   244                 MOZ_ASSERT(convert == MacroAssembler::IntConversion_NumbersOrBoolsOnly);
   245                 if (in->type() != MIRType_Int32 &&
   246                     in->type() != MIRType_Boolean &&
   247                     in->type() != MIRType_Value)
   248                 {
   249                     in = boxAt(alloc, def, in);
   250                 }
   251             }
   252             replace = MToInt32::New(alloc, in, convert);
   253             break;
   254           }
   255           case MIRType_Object:
   256             replace = MUnbox::New(alloc, in, MIRType_Object, MUnbox::Infallible);
   257             break;
   258           case MIRType_String:
   259             replace = MUnbox::New(alloc, in, MIRType_String, MUnbox::Infallible);
   260             break;
   261           default:
   262             MOZ_ASSUME_UNREACHABLE("Unknown compare specialization");
   263         }
   265         def->block()->insertBefore(def, replace);
   266         def->replaceOperand(i, replace);
   267     }
   269     return true;
   270 }
   272 bool
   273 TypeBarrierPolicy::adjustInputs(TempAllocator &alloc, MInstruction *def)
   274 {
   275     MTypeBarrier *ins = def->toTypeBarrier();
   276     MIRType inputType = ins->getOperand(0)->type();
   277     MIRType outputType = ins->type();
   279     // Input and output type are already in accordance.
   280     if (inputType == outputType)
   281         return true;
   283     // Output is a value, currently box the input.
   284     if (outputType == MIRType_Value) {
   285         // XXX: Possible optimization: decrease resultTypeSet to only include
   286         // the inputType. This will remove the need for boxing.
   287         JS_ASSERT(inputType != MIRType_Value);
   288         ins->replaceOperand(0, boxAt(alloc, ins, ins->getOperand(0)));
   289         return true;
   290     }
   292     // Input is a value. Unbox the input to the requested type.
   293     if (inputType == MIRType_Value) {
   294         JS_ASSERT(outputType != MIRType_Value);
   296         // We can't unbox a value to null/undefined/lazyargs. So keep output
   297         // also a value.
   298         if (IsNullOrUndefined(outputType) || outputType == MIRType_MagicOptimizedArguments) {
   299             JS_ASSERT(ins->defUseCount() == 0);
   300             ins->setResultType(MIRType_Value);
   301             return true;
   302         }
   304         MUnbox *unbox = MUnbox::New(alloc, ins->getOperand(0), outputType, MUnbox::TypeBarrier);
   305         ins->block()->insertBefore(ins, unbox);
   306         ins->replaceOperand(0, unbox);
   307         return true;
   308     }
   310     // In the remaining cases we will alway bail. OutputType doesn't matter.
   311     // Take inputType so we can use redefine during lowering.
   312     JS_ASSERT(ins->alwaysBails());
   313     ins->setResultType(inputType);
   315     return true;
   316 }
   318 bool
   319 TestPolicy::adjustInputs(TempAllocator &alloc, MInstruction *ins)
   320 {
   321     MDefinition *op = ins->getOperand(0);
   322     switch (op->type()) {
   323       case MIRType_Value:
   324       case MIRType_Null:
   325       case MIRType_Undefined:
   326       case MIRType_Boolean:
   327       case MIRType_Int32:
   328       case MIRType_Double:
   329       case MIRType_Float32:
   330       case MIRType_Object:
   331         break;
   333       case MIRType_String:
   334       {
   335         MStringLength *length = MStringLength::New(alloc, op);
   336         ins->block()->insertBefore(ins, length);
   337         ins->replaceOperand(0, length);
   338         break;
   339       }
   341       default:
   342         ins->replaceOperand(0, boxAt(alloc, ins, op));
   343         break;
   344     }
   345     return true;
   346 }
   348 bool
   349 BitwisePolicy::adjustInputs(TempAllocator &alloc, MInstruction *ins)
   350 {
   351     if (specialization_ == MIRType_None)
   352         return BoxInputsPolicy::adjustInputs(alloc, ins);
   354     JS_ASSERT(ins->type() == specialization_);
   355     JS_ASSERT(specialization_ == MIRType_Int32 || specialization_ == MIRType_Double);
   357     // This policy works for both unary and binary bitwise operations.
   358     for (size_t i = 0, e = ins->numOperands(); i < e; i++) {
   359         MDefinition *in = ins->getOperand(i);
   360         if (in->type() == MIRType_Int32)
   361             continue;
   363         // See BinaryArithPolicy::adjustInputs for an explanation of the following
   364         if (in->type() == MIRType_Object || in->type() == MIRType_String)
   365             in = boxAt(alloc, ins, in);
   367         MInstruction *replace = MTruncateToInt32::New(alloc, in);
   368         ins->block()->insertBefore(ins, replace);
   369         ins->replaceOperand(i, replace);
   370     }
   372     return true;
   373 }
   375 bool
   376 PowPolicy::adjustInputs(TempAllocator &alloc, MInstruction *ins)
   377 {
   378     JS_ASSERT(specialization_ == MIRType_Int32 || specialization_ == MIRType_Double);
   380     // Input must be a double.
   381     if (!DoublePolicy<0>::staticAdjustInputs(alloc, ins))
   382         return false;
   384     // Power may be an int32 or a double. Integers receive a faster path.
   385     if (specialization_ == MIRType_Double)
   386         return DoublePolicy<1>::staticAdjustInputs(alloc, ins);
   387     return IntPolicy<1>::staticAdjustInputs(alloc, ins);
   388 }
   390 template <unsigned Op>
   391 bool
   392 StringPolicy<Op>::staticAdjustInputs(TempAllocator &alloc, MInstruction *ins)
   393 {
   394     MDefinition *in = ins->getOperand(Op);
   395     if (in->type() == MIRType_String)
   396         return true;
   398     if (in->type() != MIRType_Value)
   399         in = boxAt(alloc, ins, in);
   401     MUnbox *replace = MUnbox::New(alloc, in, MIRType_String, MUnbox::Fallible);
   402     ins->block()->insertBefore(ins, replace);
   403     ins->replaceOperand(Op, replace);
   404     return true;
   405 }
   407 template bool StringPolicy<0>::staticAdjustInputs(TempAllocator &alloc, MInstruction *ins);
   408 template bool StringPolicy<1>::staticAdjustInputs(TempAllocator &alloc, MInstruction *ins);
   409 template bool StringPolicy<2>::staticAdjustInputs(TempAllocator &alloc, MInstruction *ins);
   411 template <unsigned Op>
   412 bool
   413 ConvertToStringPolicy<Op>::staticAdjustInputs(TempAllocator &alloc, MInstruction *ins)
   414 {
   415     MDefinition *in = ins->getOperand(Op);
   416     if (in->type() == MIRType_String)
   417         return true;
   419     MInstruction *replace;
   420     if (in->mightBeType(MIRType_Object)) {
   421         if (in->type() != MIRType_Value)
   422             in = boxAt(alloc, ins, in);
   424         replace = MUnbox::New(alloc, in, MIRType_String, MUnbox::Fallible);
   425     } else {
   426         // TODO remove these two lines once 966957 has landed
   427         EnsureOperandNotFloat32(alloc, ins, Op);
   428         in = ins->getOperand(Op);
   429         replace = MToString::New(alloc, in);
   430     }
   432     ins->block()->insertBefore(ins, replace);
   433     ins->replaceOperand(Op, replace);
   434     return true;
   435 }
   437 template bool ConvertToStringPolicy<0>::staticAdjustInputs(TempAllocator &alloc, MInstruction *ins);
   438 template bool ConvertToStringPolicy<1>::staticAdjustInputs(TempAllocator &alloc, MInstruction *ins);
   440 template <unsigned Op>
   441 bool
   442 IntPolicy<Op>::staticAdjustInputs(TempAllocator &alloc, MInstruction *def)
   443 {
   444     MDefinition *in = def->getOperand(Op);
   445     if (in->type() == MIRType_Int32)
   446         return true;
   448     if (in->type() != MIRType_Value)
   449         in = boxAt(alloc, def, in);
   451     MUnbox *replace = MUnbox::New(alloc, in, MIRType_Int32, MUnbox::Fallible);
   452     def->block()->insertBefore(def, replace);
   453     def->replaceOperand(Op, replace);
   454     return true;
   455 }
   457 template bool IntPolicy<0>::staticAdjustInputs(TempAllocator &alloc, MInstruction *def);
   458 template bool IntPolicy<1>::staticAdjustInputs(TempAllocator &alloc, MInstruction *def);
   459 template bool IntPolicy<2>::staticAdjustInputs(TempAllocator &alloc, MInstruction *def);
   461 template <unsigned Op>
   462 bool
   463 ConvertToInt32Policy<Op>::staticAdjustInputs(TempAllocator &alloc, MInstruction *def)
   464 {
   465     MDefinition *in = def->getOperand(Op);
   466     if (in->type() == MIRType_Int32)
   467         return true;
   469     MToInt32 *replace = MToInt32::New(alloc, in);
   470     def->block()->insertBefore(def, replace);
   471     def->replaceOperand(Op, replace);
   472     return true;
   473 }
   475 template bool ConvertToInt32Policy<0>::staticAdjustInputs(TempAllocator &alloc, MInstruction *def);
   477 template <unsigned Op>
   478 bool
   479 DoublePolicy<Op>::staticAdjustInputs(TempAllocator &alloc, MInstruction *def)
   480 {
   481     MDefinition *in = def->getOperand(Op);
   482     if (in->type() == MIRType_Double)
   483         return true;
   485     // Force a bailout. Objects may be effectful; strings are currently unhandled.
   486     if (in->type() == MIRType_Object || in->type() == MIRType_String) {
   487         MBox *box = MBox::New(alloc, in);
   488         def->block()->insertBefore(def, box);
   490         MUnbox *unbox = MUnbox::New(alloc, box, MIRType_Double, MUnbox::Fallible);
   491         def->block()->insertBefore(def, unbox);
   492         def->replaceOperand(Op, unbox);
   493         return true;
   494     }
   496     MToDouble *replace = MToDouble::New(alloc, in);
   497     def->block()->insertBefore(def, replace);
   498     def->replaceOperand(Op, replace);
   499     return true;
   500 }
   502 template bool DoublePolicy<0>::staticAdjustInputs(TempAllocator &alloc, MInstruction *def);
   503 template bool DoublePolicy<1>::staticAdjustInputs(TempAllocator &alloc, MInstruction *def);
   505 template <unsigned Op>
   506 bool
   507 Float32Policy<Op>::staticAdjustInputs(TempAllocator &alloc, MInstruction *def)
   508 {
   509     MDefinition *in = def->getOperand(Op);
   510     if (in->type() == MIRType_Float32)
   511         return true;
   513     // Force a bailout. Objects may be effectful; strings are currently unhandled.
   514     if (in->type() == MIRType_Object || in->type() == MIRType_String) {
   515         MToDouble *toDouble = MToDouble::New(alloc, in);
   516         def->block()->insertBefore(def, toDouble);
   518         MBox *box = MBox::New(alloc, toDouble);
   519         def->block()->insertBefore(def, box);
   521         MUnbox *unbox = MUnbox::New(alloc, box, MIRType_Double, MUnbox::Fallible);
   522         def->block()->insertBefore(def, unbox);
   524         MToFloat32 *toFloat32 = MToFloat32::New(alloc, unbox);
   525         def->block()->insertBefore(def, toFloat32);
   527         def->replaceOperand(Op, unbox);
   529         return true;
   530     }
   532     MToFloat32 *replace = MToFloat32::New(alloc, in);
   533     def->block()->insertBefore(def, replace);
   534     def->replaceOperand(Op, replace);
   535     return true;
   536 }
   538 template bool Float32Policy<0>::staticAdjustInputs(TempAllocator &alloc, MInstruction *def);
   539 template bool Float32Policy<1>::staticAdjustInputs(TempAllocator &alloc, MInstruction *def);
   540 template bool Float32Policy<2>::staticAdjustInputs(TempAllocator &alloc, MInstruction *def);
   542 template <unsigned Op>
   543 bool
   544 NoFloatPolicy<Op>::staticAdjustInputs(TempAllocator &alloc, MInstruction *def)
   545 {
   546     EnsureOperandNotFloat32(alloc, def, Op);
   547     return true;
   548 }
   550 template bool NoFloatPolicy<0>::staticAdjustInputs(TempAllocator &alloc, MInstruction *def);
   551 template bool NoFloatPolicy<1>::staticAdjustInputs(TempAllocator &alloc, MInstruction *def);
   552 template bool NoFloatPolicy<2>::staticAdjustInputs(TempAllocator &alloc, MInstruction *def);
   553 template bool NoFloatPolicy<3>::staticAdjustInputs(TempAllocator &alloc, MInstruction *def);
   555 template <unsigned Op>
   556 bool
   557 BoxPolicy<Op>::staticAdjustInputs(TempAllocator &alloc, MInstruction *ins)
   558 {
   559     MDefinition *in = ins->getOperand(Op);
   560     if (in->type() == MIRType_Value)
   561         return true;
   563     ins->replaceOperand(Op, boxAt(alloc, ins, in));
   564     return true;
   565 }
   567 template bool BoxPolicy<0>::staticAdjustInputs(TempAllocator &alloc, MInstruction *ins);
   568 template bool BoxPolicy<1>::staticAdjustInputs(TempAllocator &alloc, MInstruction *ins);
   569 template bool BoxPolicy<2>::staticAdjustInputs(TempAllocator &alloc, MInstruction *ins);
   571 template <unsigned Op, MIRType Type>
   572 bool
   573 BoxExceptPolicy<Op, Type>::staticAdjustInputs(TempAllocator &alloc, MInstruction *ins)
   574 {
   575     MDefinition *in = ins->getOperand(Op);
   576     if (in->type() == Type)
   577         return true;
   578     return BoxPolicy<Op>::staticAdjustInputs(alloc, ins);
   579 }
   581 template bool BoxExceptPolicy<0, MIRType_String>::staticAdjustInputs(TempAllocator &alloc,
   582                                                                      MInstruction *ins);
   583 template bool BoxExceptPolicy<1, MIRType_String>::staticAdjustInputs(TempAllocator &alloc,
   584                                                                      MInstruction *ins);
   585 template bool BoxExceptPolicy<2, MIRType_String>::staticAdjustInputs(TempAllocator &alloc,
   586                                                                      MInstruction *ins);
   588 bool
   589 ToDoublePolicy::staticAdjustInputs(TempAllocator &alloc, MInstruction *ins)
   590 {
   591     MDefinition *in = ins->getOperand(0);
   592     if (in->type() != MIRType_Object && in->type() != MIRType_String)
   593         return true;
   595     in = boxAt(alloc, ins, in);
   596     ins->replaceOperand(0, in);
   597     return true;
   598 }
   600 bool
   601 ToInt32Policy::staticAdjustInputs(TempAllocator &alloc, MInstruction *ins)
   602 {
   603     JS_ASSERT(ins->isToInt32());
   605     MDefinition *in = ins->getOperand(0);
   606     switch (in->type()) {
   607       case MIRType_Object:
   608       case MIRType_String:
   609       case MIRType_Undefined:
   610         // Objects might be effectful. Undefined coerces to NaN, not int32.
   611         in = boxAt(alloc, ins, in);
   612         ins->replaceOperand(0, in);
   613         break;
   614       default:
   615         break;
   616     }
   618     return true;
   619 }
   621 template <unsigned Op>
   622 bool
   623 ObjectPolicy<Op>::staticAdjustInputs(TempAllocator &alloc, MInstruction *ins)
   624 {
   625     MDefinition *in = ins->getOperand(Op);
   626     if (in->type() == MIRType_Object || in->type() == MIRType_Slots ||
   627         in->type() == MIRType_Elements)
   628     {
   629         return true;
   630     }
   632     if (in->type() != MIRType_Value)
   633         in = boxAt(alloc, ins, in);
   635     MUnbox *replace = MUnbox::New(alloc, in, MIRType_Object, MUnbox::Fallible);
   636     ins->block()->insertBefore(ins, replace);
   637     ins->replaceOperand(Op, replace);
   638     return true;
   639 }
   641 template bool ObjectPolicy<0>::staticAdjustInputs(TempAllocator &alloc, MInstruction *ins);
   642 template bool ObjectPolicy<1>::staticAdjustInputs(TempAllocator &alloc, MInstruction *ins);
   643 template bool ObjectPolicy<2>::staticAdjustInputs(TempAllocator &alloc, MInstruction *ins);
   644 template bool ObjectPolicy<3>::staticAdjustInputs(TempAllocator &alloc, MInstruction *ins);
   646 bool
   647 CallPolicy::adjustInputs(TempAllocator &alloc, MInstruction *ins)
   648 {
   649     MCall *call = ins->toCall();
   651     MDefinition *func = call->getFunction();
   652     if (func->type() != MIRType_Object) {
   653         // If the function is impossible to call,
   654         // bail out by causing a subsequent unbox to fail.
   655         if (func->type() != MIRType_Value)
   656             func = boxAt(alloc, call, func);
   658         MInstruction *unbox = MUnbox::New(alloc, func, MIRType_Object, MUnbox::Fallible);
   659         call->block()->insertBefore(call, unbox);
   660         call->replaceFunction(unbox);
   661     }
   663     for (uint32_t i = 0; i < call->numStackArgs(); i++)
   664         EnsureOperandNotFloat32(alloc, call, MCall::IndexOfStackArg(i));
   666     return true;
   667 }
   669 bool
   670 CallSetElementPolicy::adjustInputs(TempAllocator &alloc, MInstruction *ins)
   671 {
   672     // The first operand should be an object.
   673     SingleObjectPolicy::adjustInputs(alloc, ins);
   675     // Box the index and value operands.
   676     for (size_t i = 1, e = ins->numOperands(); i < e; i++) {
   677         MDefinition *in = ins->getOperand(i);
   678         if (in->type() == MIRType_Value)
   679             continue;
   680         ins->replaceOperand(i, boxAt(alloc, ins, in));
   681     }
   682     return true;
   683 }
   685 bool
   686 InstanceOfPolicy::adjustInputs(TempAllocator &alloc, MInstruction *def)
   687 {
   688     // Box first operand if it isn't object
   689     if (def->getOperand(0)->type() != MIRType_Object)
   690         BoxPolicy<0>::staticAdjustInputs(alloc, def);
   692     return true;
   693 }
   695 bool
   696 StoreTypedArrayPolicy::adjustValueInput(TempAllocator &alloc, MInstruction *ins, int arrayType,
   697                                         MDefinition *value, int valueOperand)
   698 {
   699     MDefinition *curValue = value;
   700     // First, ensure the value is int32, boolean, double or Value.
   701     // The conversion is based on TypedArrayObjectTemplate::setElementTail.
   702     switch (value->type()) {
   703       case MIRType_Int32:
   704       case MIRType_Double:
   705       case MIRType_Float32:
   706       case MIRType_Boolean:
   707       case MIRType_Value:
   708         break;
   709       case MIRType_Null:
   710         value->setImplicitlyUsedUnchecked();
   711         value = MConstant::New(alloc, Int32Value(0));
   712         ins->block()->insertBefore(ins, value->toInstruction());
   713         break;
   714       case MIRType_Undefined:
   715         value->setImplicitlyUsedUnchecked();
   716         value = MConstant::New(alloc, DoubleNaNValue());
   717         ins->block()->insertBefore(ins, value->toInstruction());
   718         break;
   719       case MIRType_Object:
   720       case MIRType_String:
   721         value = boxAt(alloc, ins, value);
   722         break;
   723       default:
   724         MOZ_ASSUME_UNREACHABLE("Unexpected type");
   725     }
   727     if (value != curValue) {
   728         ins->replaceOperand(valueOperand, value);
   729         curValue = value;
   730     }
   732     JS_ASSERT(value->type() == MIRType_Int32 ||
   733               value->type() == MIRType_Boolean ||
   734               value->type() == MIRType_Double ||
   735               value->type() == MIRType_Float32 ||
   736               value->type() == MIRType_Value);
   738     switch (arrayType) {
   739       case ScalarTypeDescr::TYPE_INT8:
   740       case ScalarTypeDescr::TYPE_UINT8:
   741       case ScalarTypeDescr::TYPE_INT16:
   742       case ScalarTypeDescr::TYPE_UINT16:
   743       case ScalarTypeDescr::TYPE_INT32:
   744       case ScalarTypeDescr::TYPE_UINT32:
   745         if (value->type() != MIRType_Int32) {
   746             value = MTruncateToInt32::New(alloc, value);
   747             ins->block()->insertBefore(ins, value->toInstruction());
   748         }
   749         break;
   750       case ScalarTypeDescr::TYPE_UINT8_CLAMPED:
   751         // IonBuilder should have inserted ClampToUint8.
   752         JS_ASSERT(value->type() == MIRType_Int32);
   753         break;
   754       case ScalarTypeDescr::TYPE_FLOAT32:
   755         if (LIRGenerator::allowFloat32Optimizations()) {
   756             if (value->type() != MIRType_Float32) {
   757                 value = MToFloat32::New(alloc, value);
   758                 ins->block()->insertBefore(ins, value->toInstruction());
   759             }
   760             break;
   761         }
   762         // Fallthrough: if the LIRGenerator cannot directly store Float32, it will expect the
   763         // stored value to be a double.
   764       case ScalarTypeDescr::TYPE_FLOAT64:
   765         if (value->type() != MIRType_Double) {
   766             value = MToDouble::New(alloc, value);
   767             ins->block()->insertBefore(ins, value->toInstruction());
   768         }
   769         break;
   770       default:
   771         MOZ_ASSUME_UNREACHABLE("Invalid array type");
   772     }
   774     if (value != curValue) {
   775         ins->replaceOperand(valueOperand, value);
   776         curValue = value;
   777     }
   778     return true;
   779 }
   781 bool
   782 StoreTypedArrayPolicy::adjustInputs(TempAllocator &alloc, MInstruction *ins)
   783 {
   784     MStoreTypedArrayElement *store = ins->toStoreTypedArrayElement();
   785     JS_ASSERT(store->elements()->type() == MIRType_Elements);
   786     JS_ASSERT(store->index()->type() == MIRType_Int32);
   788     return adjustValueInput(alloc, ins, store->arrayType(), store->value(), 2);
   789 }
   791 bool
   792 StoreTypedArrayHolePolicy::adjustInputs(TempAllocator &alloc, MInstruction *ins)
   793 {
   794     MStoreTypedArrayElementHole *store = ins->toStoreTypedArrayElementHole();
   795     JS_ASSERT(store->elements()->type() == MIRType_Elements);
   796     JS_ASSERT(store->index()->type() == MIRType_Int32);
   797     JS_ASSERT(store->length()->type() == MIRType_Int32);
   799     return adjustValueInput(alloc, ins, store->arrayType(), store->value(), 3);
   800 }
   802 bool
   803 StoreTypedArrayElementStaticPolicy::adjustInputs(TempAllocator &alloc, MInstruction *ins)
   804 {
   805     MStoreTypedArrayElementStatic *store = ins->toStoreTypedArrayElementStatic();
   807     return ConvertToInt32Policy<0>::staticAdjustInputs(alloc, ins) &&
   808         adjustValueInput(alloc, ins, store->viewType(), store->value(), 1);
   809 }
   811 bool
   812 ClampPolicy::adjustInputs(TempAllocator &alloc, MInstruction *ins)
   813 {
   814     MDefinition *in = ins->toClampToUint8()->input();
   816     switch (in->type()) {
   817       case MIRType_Int32:
   818       case MIRType_Double:
   819       case MIRType_Value:
   820         break;
   821       default:
   822           ins->replaceOperand(0, boxAt(alloc, ins, in));
   823         break;
   824     }
   826     return true;
   827 }
   829 bool
   830 FilterTypeSetPolicy::adjustInputs(TempAllocator &alloc, MInstruction *ins)
   831 {
   832     MOZ_ASSERT(ins->numOperands() == 1);
   834     // Do nothing if already same type.
   835     if (ins->type() == ins->getOperand(0)->type())
   836         return true;
   838     // Box input if ouput type is MIRType_Value
   839     if (ins->type() == MIRType_Value) {
   840         ins->replaceOperand(0, boxAt(alloc, ins, ins->getOperand(0)));
   841         return true;
   842     }
   844     // For simplicity just mark output type as MIRType_Value if input type
   845     // is MIRType_Value. It should be possible to unbox, but we need to
   846     // add extra code for Undefined/Null.
   847     if (ins->getOperand(0)->type() == MIRType_Value) {
   848         ins->setResultType(MIRType_Value);
   849         return true;
   850     }
   852     // In all other cases we will definitely bail, since types don't
   853     // correspond. Just box and mark output as MIRType_Value.
   854     ins->replaceOperand(0, boxAt(alloc, ins, ins->getOperand(0)));
   855     ins->setResultType(MIRType_Value);
   857     return true;
   858 }

mercurial