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.

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

mercurial