js/src/jit/CodeGenerator.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/CodeGenerator.h"
     9 #include "mozilla/Assertions.h"
    10 #include "mozilla/Attributes.h"
    11 #include "mozilla/DebugOnly.h"
    13 #include "jslibmath.h"
    14 #include "jsmath.h"
    15 #include "jsnum.h"
    16 #include "jsprf.h"
    18 #include "builtin/Eval.h"
    19 #include "builtin/TypedObject.h"
    20 #ifdef JSGC_GENERATIONAL
    21 # include "gc/Nursery.h"
    22 #endif
    23 #include "jit/IonCaches.h"
    24 #include "jit/IonLinker.h"
    25 #include "jit/IonOptimizationLevels.h"
    26 #include "jit/IonSpewer.h"
    27 #include "jit/MIRGenerator.h"
    28 #include "jit/MoveEmitter.h"
    29 #include "jit/ParallelFunctions.h"
    30 #include "jit/ParallelSafetyAnalysis.h"
    31 #include "jit/RangeAnalysis.h"
    32 #include "vm/ForkJoin.h"
    33 #include "vm/TraceLogging.h"
    35 #include "jsboolinlines.h"
    37 #include "jit/ExecutionMode-inl.h"
    38 #include "jit/shared/CodeGenerator-shared-inl.h"
    39 #include "vm/Interpreter-inl.h"
    41 using namespace js;
    42 using namespace js::jit;
    44 using mozilla::DebugOnly;
    45 using mozilla::FloatingPoint;
    46 using mozilla::Maybe;
    47 using mozilla::NegativeInfinity;
    48 using mozilla::PositiveInfinity;
    49 using JS::GenericNaN;
    51 namespace js {
    52 namespace jit {
    54 // This out-of-line cache is used to do a double dispatch including it-self and
    55 // the wrapped IonCache.
    56 class OutOfLineUpdateCache :
    57   public OutOfLineCodeBase<CodeGenerator>,
    58   public IonCacheVisitor
    59 {
    60   private:
    61     LInstruction *lir_;
    62     size_t cacheIndex_;
    63     AddCacheState state_;
    65   public:
    66     OutOfLineUpdateCache(LInstruction *lir, size_t cacheIndex)
    67       : lir_(lir),
    68         cacheIndex_(cacheIndex)
    69     { }
    71     void bind(MacroAssembler *masm) {
    72         // The binding of the initial jump is done in
    73         // CodeGenerator::visitOutOfLineCache.
    74     }
    76     size_t getCacheIndex() const {
    77         return cacheIndex_;
    78     }
    79     LInstruction *lir() const {
    80         return lir_;
    81     }
    82     AddCacheState &state() {
    83         return state_;
    84     }
    86     bool accept(CodeGenerator *codegen) {
    87         return codegen->visitOutOfLineCache(this);
    88     }
    90     // ICs' visit functions delegating the work to the CodeGen visit funtions.
    91 #define VISIT_CACHE_FUNCTION(op)                                        \
    92     bool visit##op##IC(CodeGenerator *codegen) {                        \
    93         CodeGenerator::DataPtr<op##IC> ic(codegen, getCacheIndex());    \
    94         return codegen->visit##op##IC(this, ic);                        \
    95     }
    97     IONCACHE_KIND_LIST(VISIT_CACHE_FUNCTION)
    98 #undef VISIT_CACHE_FUNCTION
    99 };
   101 // This function is declared here because it needs to instantiate an
   102 // OutOfLineUpdateCache, but we want to keep it visible inside the
   103 // CodeGeneratorShared such as we can specialize inline caches in function of
   104 // the architecture.
   105 bool
   106 CodeGeneratorShared::addCache(LInstruction *lir, size_t cacheIndex)
   107 {
   108     if (cacheIndex == SIZE_MAX)
   109         return false;
   111     DataPtr<IonCache> cache(this, cacheIndex);
   112     MInstruction *mir = lir->mirRaw()->toInstruction();
   113     if (mir->resumePoint())
   114         cache->setScriptedLocation(mir->block()->info().script(),
   115                                    mir->resumePoint()->pc());
   116     else
   117         cache->setIdempotent();
   119     OutOfLineUpdateCache *ool = new(alloc()) OutOfLineUpdateCache(lir, cacheIndex);
   120     if (!addOutOfLineCode(ool))
   121         return false;
   123     // OOL-specific state depends on the type of cache.
   124     cache->initializeAddCacheState(lir, &ool->state());
   126     cache->emitInitialJump(masm, ool->state());
   127     masm.bind(ool->rejoin());
   129     return true;
   130 }
   132 bool
   133 CodeGenerator::visitOutOfLineCache(OutOfLineUpdateCache *ool)
   134 {
   135     DataPtr<IonCache> cache(this, ool->getCacheIndex());
   137     // Register the location of the OOL path in the IC.
   138     cache->setFallbackLabel(masm.labelForPatch());
   139     cache->bindInitialJump(masm, ool->state());
   141     // Dispatch to ICs' accept functions.
   142     return cache->accept(this, ool);
   143 }
   145 StringObject *
   146 MNewStringObject::templateObj() const {
   147     return &templateObj_->as<StringObject>();
   148 }
   150 CodeGenerator::CodeGenerator(MIRGenerator *gen, LIRGraph *graph, MacroAssembler *masm)
   151   : CodeGeneratorSpecific(gen, graph, masm)
   152   , ionScriptLabels_(gen->alloc())
   153 {
   154 }
   156 CodeGenerator::~CodeGenerator()
   157 {
   158     JS_ASSERT_IF(!gen->compilingAsmJS(), masm.numAsmJSAbsoluteLinks() == 0);
   159 }
   161 typedef bool (*StringToNumberFn)(ThreadSafeContext *, JSString *, double *);
   162 typedef bool (*StringToNumberParFn)(ForkJoinContext *, JSString *, double *);
   163 static const VMFunctionsModal StringToNumberInfo = VMFunctionsModal(
   164     FunctionInfo<StringToNumberFn>(StringToNumber),
   165     FunctionInfo<StringToNumberParFn>(StringToNumberPar));
   167 bool
   168 CodeGenerator::visitValueToInt32(LValueToInt32 *lir)
   169 {
   170     ValueOperand operand = ToValue(lir, LValueToInt32::Input);
   171     Register output = ToRegister(lir->output());
   172     FloatRegister temp = ToFloatRegister(lir->tempFloat());
   174     MDefinition *input;
   175     if (lir->mode() == LValueToInt32::NORMAL)
   176         input = lir->mirNormal()->input();
   177     else
   178         input = lir->mirTruncate()->input();
   180     Label fails;
   181     if (lir->mode() == LValueToInt32::TRUNCATE) {
   182         OutOfLineCode *oolDouble = oolTruncateDouble(temp, output);
   183         if (!oolDouble)
   184             return false;
   186         // We can only handle strings in truncation contexts, like bitwise
   187         // operations.
   188         Label *stringEntry, *stringRejoin;
   189         Register stringReg;
   190         if (input->mightBeType(MIRType_String)) {
   191             stringReg = ToRegister(lir->temp());
   192             OutOfLineCode *oolString = oolCallVM(StringToNumberInfo, lir, (ArgList(), stringReg),
   193                                                  StoreFloatRegisterTo(temp));
   194             if (!oolString)
   195                 return false;
   196             stringEntry = oolString->entry();
   197             stringRejoin = oolString->rejoin();
   198         } else {
   199             stringReg = InvalidReg;
   200             stringEntry = nullptr;
   201             stringRejoin = nullptr;
   202         }
   204         masm.truncateValueToInt32(operand, input, stringEntry, stringRejoin, oolDouble->entry(),
   205                                   stringReg, temp, output, &fails);
   206         masm.bind(oolDouble->rejoin());
   207     } else {
   208         masm.convertValueToInt32(operand, input, temp, output, &fails,
   209                                  lir->mirNormal()->canBeNegativeZero(),
   210                                  lir->mirNormal()->conversion());
   211     }
   213     return bailoutFrom(&fails, lir->snapshot());
   214 }
   216 bool
   217 CodeGenerator::visitValueToDouble(LValueToDouble *lir)
   218 {
   219     MToDouble *mir = lir->mir();
   220     ValueOperand operand = ToValue(lir, LValueToDouble::Input);
   221     FloatRegister output = ToFloatRegister(lir->output());
   223     Register tag = masm.splitTagForTest(operand);
   225     Label isDouble, isInt32, isBool, isNull, isUndefined, done;
   226     bool hasBoolean = false, hasNull = false, hasUndefined = false;
   228     masm.branchTestDouble(Assembler::Equal, tag, &isDouble);
   229     masm.branchTestInt32(Assembler::Equal, tag, &isInt32);
   231     if (mir->conversion() != MToDouble::NumbersOnly) {
   232         masm.branchTestBoolean(Assembler::Equal, tag, &isBool);
   233         masm.branchTestUndefined(Assembler::Equal, tag, &isUndefined);
   234         hasBoolean = true;
   235         hasUndefined = true;
   236         if (mir->conversion() != MToDouble::NonNullNonStringPrimitives) {
   237             masm.branchTestNull(Assembler::Equal, tag, &isNull);
   238             hasNull = true;
   239         }
   240     }
   242     if (!bailout(lir->snapshot()))
   243         return false;
   245     if (hasNull) {
   246         masm.bind(&isNull);
   247         masm.loadConstantDouble(0.0, output);
   248         masm.jump(&done);
   249     }
   251     if (hasUndefined) {
   252         masm.bind(&isUndefined);
   253         masm.loadConstantDouble(GenericNaN(), output);
   254         masm.jump(&done);
   255     }
   257     if (hasBoolean) {
   258         masm.bind(&isBool);
   259         masm.boolValueToDouble(operand, output);
   260         masm.jump(&done);
   261     }
   263     masm.bind(&isInt32);
   264     masm.int32ValueToDouble(operand, output);
   265     masm.jump(&done);
   267     masm.bind(&isDouble);
   268     masm.unboxDouble(operand, output);
   269     masm.bind(&done);
   271     return true;
   272 }
   274 bool
   275 CodeGenerator::visitValueToFloat32(LValueToFloat32 *lir)
   276 {
   277     MToFloat32 *mir = lir->mir();
   278     ValueOperand operand = ToValue(lir, LValueToFloat32::Input);
   279     FloatRegister output = ToFloatRegister(lir->output());
   281     Register tag = masm.splitTagForTest(operand);
   283     Label isDouble, isInt32, isBool, isNull, isUndefined, done;
   284     bool hasBoolean = false, hasNull = false, hasUndefined = false;
   286     masm.branchTestDouble(Assembler::Equal, tag, &isDouble);
   287     masm.branchTestInt32(Assembler::Equal, tag, &isInt32);
   289     if (mir->conversion() != MToFloat32::NumbersOnly) {
   290         masm.branchTestBoolean(Assembler::Equal, tag, &isBool);
   291         masm.branchTestUndefined(Assembler::Equal, tag, &isUndefined);
   292         hasBoolean = true;
   293         hasUndefined = true;
   294         if (mir->conversion() != MToFloat32::NonNullNonStringPrimitives) {
   295             masm.branchTestNull(Assembler::Equal, tag, &isNull);
   296             hasNull = true;
   297         }
   298     }
   300     if (!bailout(lir->snapshot()))
   301         return false;
   303     if (hasNull) {
   304         masm.bind(&isNull);
   305         masm.loadConstantFloat32(0.0f, output);
   306         masm.jump(&done);
   307     }
   309     if (hasUndefined) {
   310         masm.bind(&isUndefined);
   311         masm.loadConstantFloat32(float(GenericNaN()), output);
   312         masm.jump(&done);
   313     }
   315     if (hasBoolean) {
   316         masm.bind(&isBool);
   317         masm.boolValueToFloat32(operand, output);
   318         masm.jump(&done);
   319     }
   321     masm.bind(&isInt32);
   322     masm.int32ValueToFloat32(operand, output);
   323     masm.jump(&done);
   325     masm.bind(&isDouble);
   326     masm.unboxDouble(operand, output);
   327     masm.convertDoubleToFloat32(output, output);
   328     masm.bind(&done);
   330     return true;
   331 }
   333 bool
   334 CodeGenerator::visitInt32ToDouble(LInt32ToDouble *lir)
   335 {
   336     masm.convertInt32ToDouble(ToRegister(lir->input()), ToFloatRegister(lir->output()));
   337     return true;
   338 }
   340 bool
   341 CodeGenerator::visitFloat32ToDouble(LFloat32ToDouble *lir)
   342 {
   343     masm.convertFloat32ToDouble(ToFloatRegister(lir->input()), ToFloatRegister(lir->output()));
   344     return true;
   345 }
   347 bool
   348 CodeGenerator::visitDoubleToFloat32(LDoubleToFloat32 *lir)
   349 {
   350     masm.convertDoubleToFloat32(ToFloatRegister(lir->input()), ToFloatRegister(lir->output()));
   351     return true;
   352 }
   354 bool
   355 CodeGenerator::visitInt32ToFloat32(LInt32ToFloat32 *lir)
   356 {
   357     masm.convertInt32ToFloat32(ToRegister(lir->input()), ToFloatRegister(lir->output()));
   358     return true;
   359 }
   361 bool
   362 CodeGenerator::visitDoubleToInt32(LDoubleToInt32 *lir)
   363 {
   364     Label fail;
   365     FloatRegister input = ToFloatRegister(lir->input());
   366     Register output = ToRegister(lir->output());
   367     masm.convertDoubleToInt32(input, output, &fail, lir->mir()->canBeNegativeZero());
   368     if (!bailoutFrom(&fail, lir->snapshot()))
   369         return false;
   370     return true;
   371 }
   373 bool
   374 CodeGenerator::visitFloat32ToInt32(LFloat32ToInt32 *lir)
   375 {
   376     Label fail;
   377     FloatRegister input = ToFloatRegister(lir->input());
   378     Register output = ToRegister(lir->output());
   379     masm.convertFloat32ToInt32(input, output, &fail, lir->mir()->canBeNegativeZero());
   380     if (!bailoutFrom(&fail, lir->snapshot()))
   381         return false;
   382     return true;
   383 }
   385 void
   386 CodeGenerator::emitOOLTestObject(Register objreg,
   387                                  Label *ifEmulatesUndefined,
   388                                  Label *ifDoesntEmulateUndefined,
   389                                  Register scratch)
   390 {
   391     saveVolatile(scratch);
   392     masm.setupUnalignedABICall(1, scratch);
   393     masm.passABIArg(objreg);
   394     masm.callWithABI(JS_FUNC_TO_DATA_PTR(void *, js::EmulatesUndefined));
   395     masm.storeCallResult(scratch);
   396     restoreVolatile(scratch);
   398     masm.branchIfTrueBool(scratch, ifEmulatesUndefined);
   399     masm.jump(ifDoesntEmulateUndefined);
   400 }
   402 // Base out-of-line code generator for all tests of the truthiness of an
   403 // object, where the object might not be truthy.  (Recall that per spec all
   404 // objects are truthy, but we implement the JSCLASS_EMULATES_UNDEFINED class
   405 // flag to permit objects to look like |undefined| in certain contexts,
   406 // including in object truthiness testing.)  We check truthiness inline except
   407 // when we're testing it on a proxy (or if TI guarantees us that the specified
   408 // object will never emulate |undefined|), in which case out-of-line code will
   409 // call EmulatesUndefined for a conclusive answer.
   410 class OutOfLineTestObject : public OutOfLineCodeBase<CodeGenerator>
   411 {
   412     Register objreg_;
   413     Register scratch_;
   415     Label *ifEmulatesUndefined_;
   416     Label *ifDoesntEmulateUndefined_;
   418 #ifdef DEBUG
   419     bool initialized() { return ifEmulatesUndefined_ != nullptr; }
   420 #endif
   422   public:
   423     OutOfLineTestObject()
   424 #ifdef DEBUG
   425       : ifEmulatesUndefined_(nullptr), ifDoesntEmulateUndefined_(nullptr)
   426 #endif
   427     { }
   429     bool accept(CodeGenerator *codegen) MOZ_FINAL MOZ_OVERRIDE {
   430         MOZ_ASSERT(initialized());
   431         codegen->emitOOLTestObject(objreg_, ifEmulatesUndefined_, ifDoesntEmulateUndefined_,
   432                                    scratch_);
   433         return true;
   434     }
   436     // Specify the register where the object to be tested is found, labels to
   437     // jump to if the object is truthy or falsy, and a scratch register for
   438     // use in the out-of-line path.
   439     void setInputAndTargets(Register objreg, Label *ifEmulatesUndefined, Label *ifDoesntEmulateUndefined,
   440                             Register scratch)
   441     {
   442         MOZ_ASSERT(!initialized());
   443         MOZ_ASSERT(ifEmulatesUndefined);
   444         objreg_ = objreg;
   445         scratch_ = scratch;
   446         ifEmulatesUndefined_ = ifEmulatesUndefined;
   447         ifDoesntEmulateUndefined_ = ifDoesntEmulateUndefined;
   448     }
   449 };
   451 // A subclass of OutOfLineTestObject containing two extra labels, for use when
   452 // the ifTruthy/ifFalsy labels are needed in inline code as well as out-of-line
   453 // code.  The user should bind these labels in inline code, and specify them as
   454 // targets via setInputAndTargets, as appropriate.
   455 class OutOfLineTestObjectWithLabels : public OutOfLineTestObject
   456 {
   457     Label label1_;
   458     Label label2_;
   460   public:
   461     OutOfLineTestObjectWithLabels() { }
   463     Label *label1() { return &label1_; }
   464     Label *label2() { return &label2_; }
   465 };
   467 void
   468 CodeGenerator::testObjectEmulatesUndefinedKernel(Register objreg,
   469                                                  Label *ifEmulatesUndefined,
   470                                                  Label *ifDoesntEmulateUndefined,
   471                                                  Register scratch, OutOfLineTestObject *ool)
   472 {
   473     ool->setInputAndTargets(objreg, ifEmulatesUndefined, ifDoesntEmulateUndefined, scratch);
   475     // Perform a fast-path check of the object's class flags if the object's
   476     // not a proxy.  Let out-of-line code handle the slow cases that require
   477     // saving registers, making a function call, and restoring registers.
   478     masm.branchTestObjectTruthy(false, objreg, scratch, ool->entry(), ifEmulatesUndefined);
   479 }
   481 void
   482 CodeGenerator::branchTestObjectEmulatesUndefined(Register objreg,
   483                                                  Label *ifEmulatesUndefined,
   484                                                  Label *ifDoesntEmulateUndefined,
   485                                                  Register scratch, OutOfLineTestObject *ool)
   486 {
   487     MOZ_ASSERT(!ifDoesntEmulateUndefined->bound(),
   488                "ifDoesntEmulateUndefined will be bound to the fallthrough path");
   490     testObjectEmulatesUndefinedKernel(objreg, ifEmulatesUndefined, ifDoesntEmulateUndefined,
   491                                       scratch, ool);
   492     masm.bind(ifDoesntEmulateUndefined);
   493 }
   495 void
   496 CodeGenerator::testObjectEmulatesUndefined(Register objreg,
   497                                            Label *ifEmulatesUndefined,
   498                                            Label *ifDoesntEmulateUndefined,
   499                                            Register scratch, OutOfLineTestObject *ool)
   500 {
   501     testObjectEmulatesUndefinedKernel(objreg, ifEmulatesUndefined, ifDoesntEmulateUndefined,
   502                                       scratch, ool);
   503     masm.jump(ifDoesntEmulateUndefined);
   504 }
   506 void
   507 CodeGenerator::testValueTruthyKernel(const ValueOperand &value,
   508                                      const LDefinition *scratch1, const LDefinition *scratch2,
   509                                      FloatRegister fr,
   510                                      Label *ifTruthy, Label *ifFalsy,
   511                                      OutOfLineTestObject *ool)
   512 {
   513     Register tag = masm.splitTagForTest(value);
   515     // Eventually we will want some sort of type filter here. For now, just
   516     // emit all easy cases. For speed we use the cached tag for all comparison,
   517     // except for doubles, which we test last (as the operation can clobber the
   518     // tag, which may be in ScratchReg).
   519     masm.branchTestUndefined(Assembler::Equal, tag, ifFalsy);
   520     masm.branchTestNull(Assembler::Equal, tag, ifFalsy);
   522     Label notBoolean;
   523     masm.branchTestBoolean(Assembler::NotEqual, tag, &notBoolean);
   524     masm.branchTestBooleanTruthy(false, value, ifFalsy);
   525     masm.jump(ifTruthy);
   526     masm.bind(&notBoolean);
   528     Label notInt32;
   529     masm.branchTestInt32(Assembler::NotEqual, tag, &notInt32);
   530     masm.branchTestInt32Truthy(false, value, ifFalsy);
   531     masm.jump(ifTruthy);
   532     masm.bind(&notInt32);
   534     if (ool) {
   535         Label notObject;
   537         masm.branchTestObject(Assembler::NotEqual, tag, &notObject);
   539         Register objreg = masm.extractObject(value, ToRegister(scratch1));
   540         testObjectEmulatesUndefined(objreg, ifFalsy, ifTruthy, ToRegister(scratch2), ool);
   542         masm.bind(&notObject);
   543     } else {
   544         masm.branchTestObject(Assembler::Equal, tag, ifTruthy);
   545     }
   547     // Test if a string is non-empty.
   548     Label notString;
   549     masm.branchTestString(Assembler::NotEqual, tag, &notString);
   550     masm.branchTestStringTruthy(false, value, ifFalsy);
   551     masm.jump(ifTruthy);
   552     masm.bind(&notString);
   554     // If we reach here the value is a double.
   555     masm.unboxDouble(value, fr);
   556     masm.branchTestDoubleTruthy(false, fr, ifFalsy);
   558     // Fall through for truthy.
   559 }
   561 void
   562 CodeGenerator::testValueTruthy(const ValueOperand &value,
   563                                const LDefinition *scratch1, const LDefinition *scratch2,
   564                                FloatRegister fr,
   565                                Label *ifTruthy, Label *ifFalsy,
   566                                OutOfLineTestObject *ool)
   567 {
   568     testValueTruthyKernel(value, scratch1, scratch2, fr, ifTruthy, ifFalsy, ool);
   569     masm.jump(ifTruthy);
   570 }
   572 Label *
   573 CodeGenerator::getJumpLabelForBranch(MBasicBlock *block)
   574 {
   575     if (!labelForBackedgeWithImplicitCheck(block))
   576         return block->lir()->label();
   578     // We need to use a patchable jump for this backedge, but want to treat
   579     // this as a normal label target to simplify codegen. Efficiency isn't so
   580     // important here as these tests are extremely unlikely to be used in loop
   581     // backedges, so emit inline code for the patchable jump. Heap allocating
   582     // the label allows it to be used by out of line blocks.
   583     Label *res = GetIonContext()->temp->lifoAlloc()->new_<Label>();
   584     Label after;
   585     masm.jump(&after);
   586     masm.bind(res);
   587     jumpToBlock(block);
   588     masm.bind(&after);
   589     return res;
   590 }
   592 bool
   593 CodeGenerator::visitTestOAndBranch(LTestOAndBranch *lir)
   594 {
   595     MOZ_ASSERT(lir->mir()->operandMightEmulateUndefined(),
   596                "Objects which can't emulate undefined should have been constant-folded");
   598     OutOfLineTestObject *ool = new(alloc()) OutOfLineTestObject();
   599     if (!addOutOfLineCode(ool))
   600         return false;
   602     Label *truthy = getJumpLabelForBranch(lir->ifTruthy());
   603     Label *falsy = getJumpLabelForBranch(lir->ifFalsy());
   605     testObjectEmulatesUndefined(ToRegister(lir->input()), falsy, truthy,
   606                                 ToRegister(lir->temp()), ool);
   607     return true;
   609 }
   611 bool
   612 CodeGenerator::visitTestVAndBranch(LTestVAndBranch *lir)
   613 {
   614     OutOfLineTestObject *ool = nullptr;
   615     if (lir->mir()->operandMightEmulateUndefined()) {
   616         ool = new(alloc()) OutOfLineTestObject();
   617         if (!addOutOfLineCode(ool))
   618             return false;
   619     }
   621     Label *truthy = getJumpLabelForBranch(lir->ifTruthy());
   622     Label *falsy = getJumpLabelForBranch(lir->ifFalsy());
   624     testValueTruthy(ToValue(lir, LTestVAndBranch::Input),
   625                     lir->temp1(), lir->temp2(),
   626                     ToFloatRegister(lir->tempFloat()),
   627                     truthy, falsy, ool);
   628     return true;
   629 }
   631 bool
   632 CodeGenerator::visitFunctionDispatch(LFunctionDispatch *lir)
   633 {
   634     MFunctionDispatch *mir = lir->mir();
   635     Register input = ToRegister(lir->input());
   636     Label *lastLabel;
   637     size_t casesWithFallback;
   639     // Determine if the last case is fallback or an ordinary case.
   640     if (!mir->hasFallback()) {
   641         JS_ASSERT(mir->numCases() > 0);
   642         casesWithFallback = mir->numCases();
   643         lastLabel = mir->getCaseBlock(mir->numCases() - 1)->lir()->label();
   644     } else {
   645         casesWithFallback = mir->numCases() + 1;
   646         lastLabel = mir->getFallback()->lir()->label();
   647     }
   649     // Compare function pointers, except for the last case.
   650     for (size_t i = 0; i < casesWithFallback - 1; i++) {
   651         JS_ASSERT(i < mir->numCases());
   652         JSFunction *func = mir->getCase(i);
   653         LBlock *target = mir->getCaseBlock(i)->lir();
   654         masm.branchPtr(Assembler::Equal, input, ImmGCPtr(func), target->label());
   655     }
   657     // Jump to the last case.
   658     masm.jump(lastLabel);
   660     return true;
   661 }
   663 bool
   664 CodeGenerator::visitTypeObjectDispatch(LTypeObjectDispatch *lir)
   665 {
   666     MTypeObjectDispatch *mir = lir->mir();
   667     Register input = ToRegister(lir->input());
   668     Register temp = ToRegister(lir->temp());
   670     // Hold the incoming TypeObject.
   671     masm.loadPtr(Address(input, JSObject::offsetOfType()), temp);
   673     // Compare TypeObjects.
   674     InlinePropertyTable *propTable = mir->propTable();
   675     for (size_t i = 0; i < mir->numCases(); i++) {
   676         JSFunction *func = mir->getCase(i);
   677         LBlock *target = mir->getCaseBlock(i)->lir();
   679         DebugOnly<bool> found = false;
   680         for (size_t j = 0; j < propTable->numEntries(); j++) {
   681             if (propTable->getFunction(j) != func)
   682                 continue;
   683             types::TypeObject *typeObj = propTable->getTypeObject(j);
   684             masm.branchPtr(Assembler::Equal, temp, ImmGCPtr(typeObj), target->label());
   685             found = true;
   686         }
   687         JS_ASSERT(found);
   688     }
   690     // Unknown function: jump to fallback block.
   691     LBlock *fallback = mir->getFallback()->lir();
   692     masm.jump(fallback->label());
   693     return true;
   694 }
   696 bool
   697 CodeGenerator::visitBooleanToString(LBooleanToString *lir)
   698 {
   699     Register input = ToRegister(lir->input());
   700     Register output = ToRegister(lir->output());
   701     const JSAtomState &names = GetIonContext()->runtime->names();
   702     Label true_, done;
   704     masm.branchTest32(Assembler::NonZero, input, input, &true_);
   705     masm.movePtr(ImmGCPtr(names.false_), output);
   706     masm.jump(&done);
   708     masm.bind(&true_);
   709     masm.movePtr(ImmGCPtr(names.true_), output);
   711     masm.bind(&done);
   713     return true;
   714 }
   716 void
   717 CodeGenerator::emitIntToString(Register input, Register output, Label *ool)
   718 {
   719     masm.branch32(Assembler::AboveOrEqual, input, Imm32(StaticStrings::INT_STATIC_LIMIT), ool);
   721     // Fast path for small integers.
   722     masm.movePtr(ImmPtr(&GetIonContext()->runtime->staticStrings().intStaticTable), output);
   723     masm.loadPtr(BaseIndex(output, input, ScalePointer), output);
   724 }
   726 typedef JSFlatString *(*IntToStringFn)(ThreadSafeContext *, int);
   727 typedef JSFlatString *(*IntToStringParFn)(ForkJoinContext *, int);
   728 static const VMFunctionsModal IntToStringInfo = VMFunctionsModal(
   729     FunctionInfo<IntToStringFn>(Int32ToString<CanGC>),
   730     FunctionInfo<IntToStringParFn>(IntToStringPar));
   732 bool
   733 CodeGenerator::visitIntToString(LIntToString *lir)
   734 {
   735     Register input = ToRegister(lir->input());
   736     Register output = ToRegister(lir->output());
   738     OutOfLineCode *ool = oolCallVM(IntToStringInfo, lir, (ArgList(), input),
   739                                    StoreRegisterTo(output));
   740     if (!ool)
   741         return false;
   743     emitIntToString(input, output, ool->entry());
   745     masm.bind(ool->rejoin());
   746     return true;
   747 }
   749 typedef JSString *(*DoubleToStringFn)(ThreadSafeContext *, double);
   750 typedef JSString *(*DoubleToStringParFn)(ForkJoinContext *, double);
   751 static const VMFunctionsModal DoubleToStringInfo = VMFunctionsModal(
   752     FunctionInfo<DoubleToStringFn>(NumberToString<CanGC>),
   753     FunctionInfo<DoubleToStringParFn>(DoubleToStringPar));
   755 bool
   756 CodeGenerator::visitDoubleToString(LDoubleToString *lir)
   757 {
   758     FloatRegister input = ToFloatRegister(lir->input());
   759     Register temp = ToRegister(lir->tempInt());
   760     Register output = ToRegister(lir->output());
   762     OutOfLineCode *ool = oolCallVM(DoubleToStringInfo, lir, (ArgList(), input),
   763                                    StoreRegisterTo(output));
   764     if (!ool)
   765         return false;
   767     // Try double to integer conversion and run integer to string code.
   768     masm.convertDoubleToInt32(input, temp, ool->entry(), true);
   769     emitIntToString(temp, output, ool->entry());
   771     masm.bind(ool->rejoin());
   772     return true;
   773 }
   775 typedef JSString *(*PrimitiveToStringFn)(JSContext *, HandleValue);
   776 typedef JSString *(*PrimitiveToStringParFn)(ForkJoinContext *, HandleValue);
   777 static const VMFunctionsModal PrimitiveToStringInfo = VMFunctionsModal(
   778     FunctionInfo<PrimitiveToStringFn>(ToStringSlow),
   779     FunctionInfo<PrimitiveToStringParFn>(PrimitiveToStringPar));
   781 bool
   782 CodeGenerator::visitPrimitiveToString(LPrimitiveToString *lir)
   783 {
   784     ValueOperand input = ToValue(lir, LPrimitiveToString::Input);
   785     Register output = ToRegister(lir->output());
   787     OutOfLineCode *ool = oolCallVM(PrimitiveToStringInfo, lir, (ArgList(), input),
   788                                    StoreRegisterTo(output));
   789     if (!ool)
   790         return false;
   792     Label done;
   793     Register tag = masm.splitTagForTest(input);
   794     const JSAtomState &names = GetIonContext()->runtime->names();
   796     // String
   797     if (lir->mir()->input()->mightBeType(MIRType_String)) {
   798         Label notString;
   799         masm.branchTestString(Assembler::NotEqual, tag, &notString);
   800         masm.unboxString(input, output);
   801         masm.jump(&done);
   802         masm.bind(&notString);
   803     }
   805     // Integer
   806     if (lir->mir()->input()->mightBeType(MIRType_Int32)) {
   807         Label notInteger;
   808         masm.branchTestInt32(Assembler::NotEqual, tag, &notInteger);
   809         Register unboxed = ToTempUnboxRegister(lir->tempToUnbox());
   810         unboxed = masm.extractInt32(input, unboxed);
   811         emitIntToString(unboxed, output, ool->entry());
   812         masm.jump(&done);
   813         masm.bind(&notInteger);
   814     }
   816     // Double
   817     if (lir->mir()->input()->mightBeType(MIRType_Double)) {
   818         // Note: no fastpath. Need two extra registers and can only convert doubles
   819         // that fit integers and are smaller than StaticStrings::INT_STATIC_LIMIT.
   820         masm.branchTestDouble(Assembler::Equal, tag, ool->entry());
   821     }
   823     // Undefined
   824     if (lir->mir()->input()->mightBeType(MIRType_Undefined)) {
   825         Label notUndefined;
   826         masm.branchTestUndefined(Assembler::NotEqual, tag, &notUndefined);
   827         masm.movePtr(ImmGCPtr(names.undefined), output);
   828         masm.jump(&done);
   829         masm.bind(&notUndefined);
   830     }
   832     // Null
   833     if (lir->mir()->input()->mightBeType(MIRType_Null)) {
   834         Label notNull;
   835         masm.branchTestNull(Assembler::NotEqual, tag, &notNull);
   836         masm.movePtr(ImmGCPtr(names.null), output);
   837         masm.jump(&done);
   838         masm.bind(&notNull);
   839     }
   841     // Boolean
   842     if (lir->mir()->input()->mightBeType(MIRType_Boolean)) {
   843         Label notBoolean, true_;
   844         masm.branchTestBoolean(Assembler::NotEqual, tag, &notBoolean);
   845         masm.branchTestBooleanTruthy(true, input, &true_);
   846         masm.movePtr(ImmGCPtr(names.false_), output);
   847         masm.jump(&done);
   848         masm.bind(&true_);
   849         masm.movePtr(ImmGCPtr(names.true_), output);
   850         masm.jump(&done);
   851         masm.bind(&notBoolean);
   852     }
   854 #ifdef DEBUG
   855     // Objects are not supported or we see a type that wasn't accounted for.
   856     masm.assumeUnreachable("Unexpected type for MPrimitiveToString.");
   857 #endif
   859     masm.bind(&done);
   860     masm.bind(ool->rejoin());
   861     return true;
   862 }
   864 typedef JSObject *(*CloneRegExpObjectFn)(JSContext *, JSObject *);
   865 static const VMFunction CloneRegExpObjectInfo =
   866     FunctionInfo<CloneRegExpObjectFn>(CloneRegExpObject);
   868 bool
   869 CodeGenerator::visitRegExp(LRegExp *lir)
   870 {
   871     pushArg(ImmGCPtr(lir->mir()->source()));
   872     return callVM(CloneRegExpObjectInfo, lir);
   873 }
   875 typedef bool (*RegExpExecRawFn)(JSContext *cx, HandleObject regexp,
   876                                 HandleString input, MutableHandleValue output);
   877 static const VMFunction RegExpExecRawInfo = FunctionInfo<RegExpExecRawFn>(regexp_exec_raw);
   879 bool
   880 CodeGenerator::visitRegExpExec(LRegExpExec *lir)
   881 {
   882     pushArg(ToRegister(lir->string()));
   883     pushArg(ToRegister(lir->regexp()));
   884     return callVM(RegExpExecRawInfo, lir);
   885 }
   887 typedef bool (*RegExpTestRawFn)(JSContext *cx, HandleObject regexp,
   888                                 HandleString input, bool *result);
   889 static const VMFunction RegExpTestRawInfo = FunctionInfo<RegExpTestRawFn>(regexp_test_raw);
   891 bool
   892 CodeGenerator::visitRegExpTest(LRegExpTest *lir)
   893 {
   894     pushArg(ToRegister(lir->string()));
   895     pushArg(ToRegister(lir->regexp()));
   896     return callVM(RegExpTestRawInfo, lir);
   897 }
   899 typedef JSString *(*RegExpReplaceFn)(JSContext *, HandleString, HandleObject, HandleString);
   900 static const VMFunction RegExpReplaceInfo = FunctionInfo<RegExpReplaceFn>(RegExpReplace);
   902 bool
   903 CodeGenerator::visitRegExpReplace(LRegExpReplace *lir)
   904 {
   905     if (lir->replacement()->isConstant())
   906         pushArg(ImmGCPtr(lir->replacement()->toConstant()->toString()));
   907     else
   908         pushArg(ToRegister(lir->replacement()));
   910     pushArg(ToRegister(lir->pattern()));
   912     if (lir->string()->isConstant())
   913         pushArg(ImmGCPtr(lir->string()->toConstant()->toString()));
   914     else
   915         pushArg(ToRegister(lir->string()));
   917     return callVM(RegExpReplaceInfo, lir);
   918 }
   920 typedef JSString *(*StringReplaceFn)(JSContext *, HandleString, HandleString, HandleString);
   921 static const VMFunction StringReplaceInfo = FunctionInfo<StringReplaceFn>(StringReplace);
   923 bool
   924 CodeGenerator::visitStringReplace(LStringReplace *lir)
   925 {
   926     if (lir->replacement()->isConstant())
   927         pushArg(ImmGCPtr(lir->replacement()->toConstant()->toString()));
   928     else
   929         pushArg(ToRegister(lir->replacement()));
   931     if (lir->pattern()->isConstant())
   932         pushArg(ImmGCPtr(lir->pattern()->toConstant()->toString()));
   933     else
   934         pushArg(ToRegister(lir->pattern()));
   936     if (lir->string()->isConstant())
   937         pushArg(ImmGCPtr(lir->string()->toConstant()->toString()));
   938     else
   939         pushArg(ToRegister(lir->string()));
   941     return callVM(StringReplaceInfo, lir);
   942 }
   945 typedef JSObject *(*LambdaFn)(JSContext *, HandleFunction, HandleObject);
   946 static const VMFunction LambdaInfo = FunctionInfo<LambdaFn>(js::Lambda);
   948 bool
   949 CodeGenerator::visitLambdaForSingleton(LLambdaForSingleton *lir)
   950 {
   951     pushArg(ToRegister(lir->scopeChain()));
   952     pushArg(ImmGCPtr(lir->mir()->info().fun));
   953     return callVM(LambdaInfo, lir);
   954 }
   956 bool
   957 CodeGenerator::visitLambda(LLambda *lir)
   958 {
   959     Register scopeChain = ToRegister(lir->scopeChain());
   960     Register output = ToRegister(lir->output());
   961     Register tempReg = ToRegister(lir->temp());
   962     const LambdaFunctionInfo &info = lir->mir()->info();
   964     OutOfLineCode *ool = oolCallVM(LambdaInfo, lir, (ArgList(), ImmGCPtr(info.fun), scopeChain),
   965                                    StoreRegisterTo(output));
   966     if (!ool)
   967         return false;
   969     JS_ASSERT(!info.singletonType);
   971     masm.newGCThing(output, tempReg, info.fun, ool->entry(), gc::DefaultHeap);
   972     masm.initGCThing(output, tempReg, info.fun);
   974     emitLambdaInit(output, scopeChain, info);
   976     masm.bind(ool->rejoin());
   977     return true;
   978 }
   980 typedef JSObject *(*LambdaArrowFn)(JSContext *, HandleFunction, HandleObject, HandleValue);
   981 static const VMFunction LambdaArrowInfo = FunctionInfo<LambdaArrowFn>(js::LambdaArrow);
   983 bool
   984 CodeGenerator::visitLambdaArrow(LLambdaArrow *lir)
   985 {
   986     Register scopeChain = ToRegister(lir->scopeChain());
   987     ValueOperand thisv = ToValue(lir, LLambdaArrow::ThisValue);
   988     Register output = ToRegister(lir->output());
   989     Register tempReg = ToRegister(lir->temp());
   990     const LambdaFunctionInfo &info = lir->mir()->info();
   992     OutOfLineCode *ool = oolCallVM(LambdaArrowInfo, lir,
   993                                    (ArgList(), ImmGCPtr(info.fun), scopeChain, thisv),
   994                                    StoreRegisterTo(output));
   995     if (!ool)
   996         return false;
   998     MOZ_ASSERT(!info.useNewTypeForClone);
  1000     if (info.singletonType) {
  1001         // If the function has a singleton type, this instruction will only be
  1002         // executed once so we don't bother inlining it.
  1003         masm.jump(ool->entry());
  1004         masm.bind(ool->rejoin());
  1005         return true;
  1008     masm.newGCThing(output, tempReg, info.fun, ool->entry(), gc::DefaultHeap);
  1009     masm.initGCThing(output, tempReg, info.fun);
  1011     emitLambdaInit(output, scopeChain, info);
  1013     // Initialize extended slots. Lexical |this| is stored in the first one.
  1014     MOZ_ASSERT(info.flags & JSFunction::EXTENDED);
  1015     static_assert(FunctionExtended::NUM_EXTENDED_SLOTS == 2, "All slots must be initialized");
  1016     static_assert(FunctionExtended::ARROW_THIS_SLOT == 0, "|this| must be stored in first slot");
  1017     masm.storeValue(thisv, Address(output, FunctionExtended::offsetOfExtendedSlot(0)));
  1018     masm.storeValue(UndefinedValue(), Address(output, FunctionExtended::offsetOfExtendedSlot(1)));
  1020     masm.bind(ool->rejoin());
  1021     return true;
  1024 void
  1025 CodeGenerator::emitLambdaInit(Register output, Register scopeChain,
  1026                               const LambdaFunctionInfo &info)
  1028     MOZ_ASSERT(!!(info.flags & JSFunction::ARROW) == !!(info.flags & JSFunction::EXTENDED));
  1030     // Initialize nargs and flags. We do this with a single uint32 to avoid
  1031     // 16-bit writes.
  1032     union {
  1033         struct S {
  1034             uint16_t nargs;
  1035             uint16_t flags;
  1036         } s;
  1037         uint32_t word;
  1038     } u;
  1039     u.s.nargs = info.fun->nargs();
  1040     u.s.flags = info.flags;
  1042     JS_ASSERT(JSFunction::offsetOfFlags() == JSFunction::offsetOfNargs() + 2);
  1043     masm.store32(Imm32(u.word), Address(output, JSFunction::offsetOfNargs()));
  1044     masm.storePtr(ImmGCPtr(info.scriptOrLazyScript),
  1045                   Address(output, JSFunction::offsetOfNativeOrScript()));
  1046     masm.storePtr(scopeChain, Address(output, JSFunction::offsetOfEnvironment()));
  1047     masm.storePtr(ImmGCPtr(info.fun->displayAtom()), Address(output, JSFunction::offsetOfAtom()));
  1050 bool
  1051 CodeGenerator::visitLambdaPar(LLambdaPar *lir)
  1053     Register resultReg = ToRegister(lir->output());
  1054     Register cxReg = ToRegister(lir->forkJoinContext());
  1055     Register scopeChainReg = ToRegister(lir->scopeChain());
  1056     Register tempReg1 = ToRegister(lir->getTemp0());
  1057     Register tempReg2 = ToRegister(lir->getTemp1());
  1058     const LambdaFunctionInfo &info = lir->mir()->info();
  1060     JS_ASSERT(scopeChainReg != resultReg);
  1062     emitAllocateGCThingPar(lir, resultReg, cxReg, tempReg1, tempReg2, info.fun);
  1063     emitLambdaInit(resultReg, scopeChainReg, info);
  1064     return true;
  1067 bool
  1068 CodeGenerator::visitLabel(LLabel *lir)
  1070     return true;
  1073 bool
  1074 CodeGenerator::visitNop(LNop *lir)
  1076     return true;
  1079 bool
  1080 CodeGenerator::visitOsiPoint(LOsiPoint *lir)
  1082     // Note: markOsiPoint ensures enough space exists between the last
  1083     // LOsiPoint and this one to patch adjacent call instructions.
  1085     JS_ASSERT(masm.framePushed() == frameSize());
  1087     uint32_t osiCallPointOffset;
  1088     if (!markOsiPoint(lir, &osiCallPointOffset))
  1089         return false;
  1091     LSafepoint *safepoint = lir->associatedSafepoint();
  1092     JS_ASSERT(!safepoint->osiCallPointOffset());
  1093     safepoint->setOsiCallPointOffset(osiCallPointOffset);
  1095 #ifdef DEBUG
  1096     // There should be no movegroups or other instructions between
  1097     // an instruction and its OsiPoint. This is necessary because
  1098     // we use the OsiPoint's snapshot from within VM calls.
  1099     for (LInstructionReverseIterator iter(current->rbegin(lir)); iter != current->rend(); iter++) {
  1100         if (*iter == lir || iter->isNop())
  1101             continue;
  1102         JS_ASSERT(!iter->isMoveGroup());
  1103         JS_ASSERT(iter->safepoint() == safepoint);
  1104         break;
  1106 #endif
  1108 #ifdef CHECK_OSIPOINT_REGISTERS
  1109     if (shouldVerifyOsiPointRegs(safepoint))
  1110         verifyOsiPointRegs(safepoint);
  1111 #endif
  1113     return true;
  1116 bool
  1117 CodeGenerator::visitGoto(LGoto *lir)
  1119     jumpToBlock(lir->target());
  1120     return true;
  1123 // Out-of-line path to execute any move groups between the start of a loop
  1124 // header and its interrupt check, then invoke the interrupt handler.
  1125 class OutOfLineInterruptCheckImplicit : public OutOfLineCodeBase<CodeGenerator>
  1127   public:
  1128     LBlock *block;
  1129     LInterruptCheckImplicit *lir;
  1131     OutOfLineInterruptCheckImplicit(LBlock *block, LInterruptCheckImplicit *lir)
  1132       : block(block), lir(lir)
  1133     { }
  1135     bool accept(CodeGenerator *codegen) {
  1136         return codegen->visitOutOfLineInterruptCheckImplicit(this);
  1138 };
  1140 bool
  1141 CodeGenerator::visitOutOfLineInterruptCheckImplicit(OutOfLineInterruptCheckImplicit *ool)
  1143 #ifdef CHECK_OSIPOINT_REGISTERS
  1144     // This is path is entered from the patched back-edge of the loop. This
  1145     // means that the JitAtivation flags used for checking the validity of the
  1146     // OSI points are not reseted by the path generated by generateBody, so we
  1147     // have to reset it here.
  1148     resetOsiPointRegs(ool->lir->safepoint());
  1149 #endif
  1151     LInstructionIterator iter = ool->block->begin();
  1152     for (; iter != ool->block->end(); iter++) {
  1153         if (iter->isLabel()) {
  1154             // Nothing to do.
  1155         } else if (iter->isMoveGroup()) {
  1156             // Replay this move group that preceds the interrupt check at the
  1157             // start of the loop header. Any incoming jumps here will be from
  1158             // the backedge and will skip over the move group emitted inline.
  1159             visitMoveGroup(iter->toMoveGroup());
  1160         } else {
  1161             break;
  1164     JS_ASSERT(*iter == ool->lir);
  1166     saveLive(ool->lir);
  1167     if (!callVM(InterruptCheckInfo, ool->lir))
  1168         return false;
  1169     restoreLive(ool->lir);
  1170     masm.jump(ool->rejoin());
  1172     return true;
  1175 bool
  1176 CodeGenerator::visitInterruptCheckImplicit(LInterruptCheckImplicit *lir)
  1178     OutOfLineInterruptCheckImplicit *ool = new(alloc()) OutOfLineInterruptCheckImplicit(current, lir);
  1179     if (!addOutOfLineCode(ool))
  1180         return false;
  1182     lir->setOolEntry(ool->entry());
  1183     masm.bind(ool->rejoin());
  1184     return true;
  1187 bool
  1188 CodeGenerator::visitTableSwitch(LTableSwitch *ins)
  1190     MTableSwitch *mir = ins->mir();
  1191     Label *defaultcase = mir->getDefault()->lir()->label();
  1192     const LAllocation *temp;
  1194     if (mir->getOperand(0)->type() != MIRType_Int32) {
  1195         temp = ins->tempInt()->output();
  1197         // The input is a double, so try and convert it to an integer.
  1198         // If it does not fit in an integer, take the default case.
  1199         masm.convertDoubleToInt32(ToFloatRegister(ins->index()), ToRegister(temp), defaultcase, false);
  1200     } else {
  1201         temp = ins->index();
  1204     return emitTableSwitchDispatch(mir, ToRegister(temp), ToRegisterOrInvalid(ins->tempPointer()));
  1207 bool
  1208 CodeGenerator::visitTableSwitchV(LTableSwitchV *ins)
  1210     MTableSwitch *mir = ins->mir();
  1211     Label *defaultcase = mir->getDefault()->lir()->label();
  1213     Register index = ToRegister(ins->tempInt());
  1214     ValueOperand value = ToValue(ins, LTableSwitchV::InputValue);
  1215     Register tag = masm.extractTag(value, index);
  1216     masm.branchTestNumber(Assembler::NotEqual, tag, defaultcase);
  1218     Label unboxInt, isInt;
  1219     masm.branchTestInt32(Assembler::Equal, tag, &unboxInt);
  1221         FloatRegister floatIndex = ToFloatRegister(ins->tempFloat());
  1222         masm.unboxDouble(value, floatIndex);
  1223         masm.convertDoubleToInt32(floatIndex, index, defaultcase, false);
  1224         masm.jump(&isInt);
  1227     masm.bind(&unboxInt);
  1228     masm.unboxInt32(value, index);
  1230     masm.bind(&isInt);
  1232     return emitTableSwitchDispatch(mir, index, ToRegisterOrInvalid(ins->tempPointer()));
  1235 typedef JSObject *(*DeepCloneObjectLiteralFn)(JSContext *, HandleObject, NewObjectKind);
  1236 static const VMFunction DeepCloneObjectLiteralInfo =
  1237     FunctionInfo<DeepCloneObjectLiteralFn>(DeepCloneObjectLiteral);
  1239 bool
  1240 CodeGenerator::visitCloneLiteral(LCloneLiteral *lir)
  1242     pushArg(ImmWord(js::MaybeSingletonObject));
  1243     pushArg(ToRegister(lir->output()));
  1244     return callVM(DeepCloneObjectLiteralInfo, lir);
  1247 bool
  1248 CodeGenerator::visitParameter(LParameter *lir)
  1250     return true;
  1253 bool
  1254 CodeGenerator::visitCallee(LCallee *lir)
  1256     // read number of actual arguments from the JS frame.
  1257     Register callee = ToRegister(lir->output());
  1258     Address ptr(StackPointer, frameSize() + IonJSFrameLayout::offsetOfCalleeToken());
  1260     masm.loadPtr(ptr, callee);
  1261     return true;
  1264 bool
  1265 CodeGenerator::visitStart(LStart *lir)
  1267     return true;
  1270 bool
  1271 CodeGenerator::visitReturn(LReturn *lir)
  1273 #if defined(JS_NUNBOX32)
  1274     DebugOnly<LAllocation *> type    = lir->getOperand(TYPE_INDEX);
  1275     DebugOnly<LAllocation *> payload = lir->getOperand(PAYLOAD_INDEX);
  1276     JS_ASSERT(ToRegister(type)    == JSReturnReg_Type);
  1277     JS_ASSERT(ToRegister(payload) == JSReturnReg_Data);
  1278 #elif defined(JS_PUNBOX64)
  1279     DebugOnly<LAllocation *> result = lir->getOperand(0);
  1280     JS_ASSERT(ToRegister(result) == JSReturnReg);
  1281 #endif
  1282     // Don't emit a jump to the return label if this is the last block.
  1283     if (current->mir() != *gen->graph().poBegin())
  1284         masm.jump(&returnLabel_);
  1285     return true;
  1288 bool
  1289 CodeGenerator::visitOsrEntry(LOsrEntry *lir)
  1291     // Remember the OSR entry offset into the code buffer.
  1292     masm.flushBuffer();
  1293     setOsrEntryOffset(masm.size());
  1295 #ifdef JS_TRACE_LOGGING
  1296     if (gen->info().executionMode() == SequentialExecution) {
  1297         if (!emitTracelogStopEvent(TraceLogger::Baseline))
  1298             return false;
  1299         if (!emitTracelogStartEvent(TraceLogger::IonMonkey))
  1300             return false;
  1302 #endif
  1304     // Allocate the full frame for this function.
  1305     uint32_t size = frameSize();
  1306     if (size != 0)
  1307         masm.subPtr(Imm32(size), StackPointer);
  1308     return true;
  1311 bool
  1312 CodeGenerator::visitOsrScopeChain(LOsrScopeChain *lir)
  1314     const LAllocation *frame   = lir->getOperand(0);
  1315     const LDefinition *object  = lir->getDef(0);
  1317     const ptrdiff_t frameOffset = BaselineFrame::reverseOffsetOfScopeChain();
  1319     masm.loadPtr(Address(ToRegister(frame), frameOffset), ToRegister(object));
  1320     return true;
  1323 bool
  1324 CodeGenerator::visitOsrArgumentsObject(LOsrArgumentsObject *lir)
  1326     const LAllocation *frame   = lir->getOperand(0);
  1327     const LDefinition *object  = lir->getDef(0);
  1329     const ptrdiff_t frameOffset = BaselineFrame::reverseOffsetOfArgsObj();
  1331     masm.loadPtr(Address(ToRegister(frame), frameOffset), ToRegister(object));
  1332     return true;
  1335 bool
  1336 CodeGenerator::visitOsrValue(LOsrValue *value)
  1338     const LAllocation *frame   = value->getOperand(0);
  1339     const ValueOperand out     = ToOutValue(value);
  1341     const ptrdiff_t frameOffset = value->mir()->frameOffset();
  1343     masm.loadValue(Address(ToRegister(frame), frameOffset), out);
  1344     return true;
  1347 bool
  1348 CodeGenerator::visitOsrReturnValue(LOsrReturnValue *lir)
  1350     const LAllocation *frame   = lir->getOperand(0);
  1351     const ValueOperand out     = ToOutValue(lir);
  1353     Address flags = Address(ToRegister(frame), BaselineFrame::reverseOffsetOfFlags());
  1354     Address retval = Address(ToRegister(frame), BaselineFrame::reverseOffsetOfReturnValue());
  1356     masm.moveValue(UndefinedValue(), out);
  1358     Label done;
  1359     masm.branchTest32(Assembler::Zero, flags, Imm32(BaselineFrame::HAS_RVAL), &done);
  1360     masm.loadValue(retval, out);
  1361     masm.bind(&done);
  1363     return true;
  1366 bool
  1367 CodeGenerator::visitStackArgT(LStackArgT *lir)
  1369     const LAllocation *arg = lir->getArgument();
  1370     MIRType argType = lir->type();
  1371     uint32_t argslot = lir->argslot();
  1372     JS_ASSERT(argslot - 1u < graph.argumentSlotCount());
  1374     int32_t stack_offset = StackOffsetOfPassedArg(argslot);
  1375     Address dest(StackPointer, stack_offset);
  1377     if (arg->isFloatReg())
  1378         masm.storeDouble(ToFloatRegister(arg), dest);
  1379     else if (arg->isRegister())
  1380         masm.storeValue(ValueTypeFromMIRType(argType), ToRegister(arg), dest);
  1381     else
  1382         masm.storeValue(*(arg->toConstant()), dest);
  1384     uint32_t slot = StackOffsetToSlot(stack_offset);
  1385     JS_ASSERT(slot - 1u < graph.totalSlotCount());
  1386     return pushedArgumentSlots_.append(slot);
  1389 bool
  1390 CodeGenerator::visitStackArgV(LStackArgV *lir)
  1392     ValueOperand val = ToValue(lir, 0);
  1393     uint32_t argslot = lir->argslot();
  1394     JS_ASSERT(argslot - 1u < graph.argumentSlotCount());
  1396     int32_t stack_offset = StackOffsetOfPassedArg(argslot);
  1398     masm.storeValue(val, Address(StackPointer, stack_offset));
  1400     uint32_t slot = StackOffsetToSlot(stack_offset);
  1401     JS_ASSERT(slot - 1u < graph.totalSlotCount());
  1402     return pushedArgumentSlots_.append(slot);
  1405 bool
  1406 CodeGenerator::visitMoveGroup(LMoveGroup *group)
  1408     if (!group->numMoves())
  1409         return true;
  1411     MoveResolver &resolver = masm.moveResolver();
  1413     for (size_t i = 0; i < group->numMoves(); i++) {
  1414         const LMove &move = group->getMove(i);
  1416         const LAllocation *from = move.from();
  1417         const LAllocation *to = move.to();
  1418         LDefinition::Type type = move.type();
  1420         // No bogus moves.
  1421         JS_ASSERT(*from != *to);
  1422         JS_ASSERT(!from->isConstant());
  1424         MoveOp::Type moveType;
  1425         switch (type) {
  1426           case LDefinition::OBJECT:
  1427           case LDefinition::SLOTS:
  1428 #ifdef JS_NUNBOX32
  1429           case LDefinition::TYPE:
  1430           case LDefinition::PAYLOAD:
  1431 #else
  1432           case LDefinition::BOX:
  1433 #endif
  1434           case LDefinition::GENERAL: moveType = MoveOp::GENERAL; break;
  1435           case LDefinition::INT32:   moveType = MoveOp::INT32;   break;
  1436           case LDefinition::FLOAT32: moveType = MoveOp::FLOAT32; break;
  1437           case LDefinition::DOUBLE:  moveType = MoveOp::DOUBLE;  break;
  1438           default: MOZ_ASSUME_UNREACHABLE("Unexpected move type");
  1441         if (!resolver.addMove(toMoveOperand(from), toMoveOperand(to), moveType))
  1442             return false;
  1445     if (!resolver.resolve())
  1446         return false;
  1448     MoveEmitter emitter(masm);
  1449     emitter.emit(resolver);
  1450     emitter.finish();
  1452     return true;
  1455 bool
  1456 CodeGenerator::visitInteger(LInteger *lir)
  1458     masm.move32(Imm32(lir->getValue()), ToRegister(lir->output()));
  1459     return true;
  1462 bool
  1463 CodeGenerator::visitPointer(LPointer *lir)
  1465     if (lir->kind() == LPointer::GC_THING)
  1466         masm.movePtr(ImmGCPtr(lir->gcptr()), ToRegister(lir->output()));
  1467     else
  1468         masm.movePtr(ImmPtr(lir->ptr()), ToRegister(lir->output()));
  1469     return true;
  1472 bool
  1473 CodeGenerator::visitSlots(LSlots *lir)
  1475     Address slots(ToRegister(lir->object()), JSObject::offsetOfSlots());
  1476     masm.loadPtr(slots, ToRegister(lir->output()));
  1477     return true;
  1480 bool
  1481 CodeGenerator::visitStoreSlotV(LStoreSlotV *store)
  1483     Register base = ToRegister(store->slots());
  1484     int32_t offset = store->mir()->slot() * sizeof(Value);
  1486     const ValueOperand value = ToValue(store, LStoreSlotV::Value);
  1488     if (store->mir()->needsBarrier())
  1489        emitPreBarrier(Address(base, offset), MIRType_Value);
  1491     masm.storeValue(value, Address(base, offset));
  1492     return true;
  1495 bool
  1496 CodeGenerator::emitGetPropertyPolymorphic(LInstruction *ins, Register obj, Register scratch,
  1497                                           const TypedOrValueRegister &output)
  1499     MGetPropertyPolymorphic *mir = ins->mirRaw()->toGetPropertyPolymorphic();
  1500     JS_ASSERT(mir->numShapes() > 1);
  1502     masm.loadObjShape(obj, scratch);
  1504     Label done;
  1505     for (size_t i = 0; i < mir->numShapes(); i++) {
  1506         Label next;
  1507         masm.branchPtr(Assembler::NotEqual, scratch, ImmGCPtr(mir->objShape(i)), &next);
  1509         Shape *shape = mir->shape(i);
  1510         if (shape->slot() < shape->numFixedSlots()) {
  1511             // Fixed slot.
  1512             masm.loadTypedOrValue(Address(obj, JSObject::getFixedSlotOffset(shape->slot())),
  1513                                   output);
  1514         } else {
  1515             // Dynamic slot.
  1516             uint32_t offset = (shape->slot() - shape->numFixedSlots()) * sizeof(js::Value);
  1517             masm.loadPtr(Address(obj, JSObject::offsetOfSlots()), scratch);
  1518             masm.loadTypedOrValue(Address(scratch, offset), output);
  1521         masm.jump(&done);
  1522         masm.bind(&next);
  1525     // Bailout if no shape matches.
  1526     if (!bailout(ins->snapshot()))
  1527         return false;
  1529     masm.bind(&done);
  1530     return true;
  1533 bool
  1534 CodeGenerator::visitGetPropertyPolymorphicV(LGetPropertyPolymorphicV *ins)
  1536     Register obj = ToRegister(ins->obj());
  1537     ValueOperand output = GetValueOutput(ins);
  1538     return emitGetPropertyPolymorphic(ins, obj, output.scratchReg(), output);
  1541 bool
  1542 CodeGenerator::visitGetPropertyPolymorphicT(LGetPropertyPolymorphicT *ins)
  1544     Register obj = ToRegister(ins->obj());
  1545     TypedOrValueRegister output(ins->mir()->type(), ToAnyRegister(ins->output()));
  1546     Register temp = (output.type() == MIRType_Double)
  1547                     ? ToRegister(ins->temp())
  1548                     : output.typedReg().gpr();
  1549     return emitGetPropertyPolymorphic(ins, obj, temp, output);
  1552 bool
  1553 CodeGenerator::emitSetPropertyPolymorphic(LInstruction *ins, Register obj, Register scratch,
  1554                                           const ConstantOrRegister &value)
  1556     MSetPropertyPolymorphic *mir = ins->mirRaw()->toSetPropertyPolymorphic();
  1557     JS_ASSERT(mir->numShapes() > 1);
  1559     masm.loadObjShape(obj, scratch);
  1561     Label done;
  1562     for (size_t i = 0; i < mir->numShapes(); i++) {
  1563         Label next;
  1564         masm.branchPtr(Assembler::NotEqual, scratch, ImmGCPtr(mir->objShape(i)), &next);
  1566         Shape *shape = mir->shape(i);
  1567         if (shape->slot() < shape->numFixedSlots()) {
  1568             // Fixed slot.
  1569             Address addr(obj, JSObject::getFixedSlotOffset(shape->slot()));
  1570             if (mir->needsBarrier())
  1571                 emitPreBarrier(addr, MIRType_Value);
  1572             masm.storeConstantOrRegister(value, addr);
  1573         } else {
  1574             // Dynamic slot.
  1575             masm.loadPtr(Address(obj, JSObject::offsetOfSlots()), scratch);
  1576             Address addr(scratch, (shape->slot() - shape->numFixedSlots()) * sizeof(js::Value));
  1577             if (mir->needsBarrier())
  1578                 emitPreBarrier(addr, MIRType_Value);
  1579             masm.storeConstantOrRegister(value, addr);
  1582         masm.jump(&done);
  1583         masm.bind(&next);
  1586     // Bailout if no shape matches.
  1587     if (!bailout(ins->snapshot()))
  1588         return false;
  1590     masm.bind(&done);
  1591     return true;
  1594 bool
  1595 CodeGenerator::visitSetPropertyPolymorphicV(LSetPropertyPolymorphicV *ins)
  1597     Register obj = ToRegister(ins->obj());
  1598     Register temp = ToRegister(ins->temp());
  1599     ValueOperand value = ToValue(ins, LSetPropertyPolymorphicV::Value);
  1600     return emitSetPropertyPolymorphic(ins, obj, temp, TypedOrValueRegister(value));
  1603 bool
  1604 CodeGenerator::visitSetPropertyPolymorphicT(LSetPropertyPolymorphicT *ins)
  1606     Register obj = ToRegister(ins->obj());
  1607     Register temp = ToRegister(ins->temp());
  1609     ConstantOrRegister value;
  1610     if (ins->mir()->value()->isConstant())
  1611         value = ConstantOrRegister(ins->mir()->value()->toConstant()->value());
  1612     else
  1613         value = TypedOrValueRegister(ins->mir()->value()->type(), ToAnyRegister(ins->value()));
  1615     return emitSetPropertyPolymorphic(ins, obj, temp, value);
  1618 bool
  1619 CodeGenerator::visitElements(LElements *lir)
  1621     Address elements(ToRegister(lir->object()), JSObject::offsetOfElements());
  1622     masm.loadPtr(elements, ToRegister(lir->output()));
  1623     return true;
  1626 typedef bool (*ConvertElementsToDoublesFn)(JSContext *, uintptr_t);
  1627 static const VMFunction ConvertElementsToDoublesInfo =
  1628     FunctionInfo<ConvertElementsToDoublesFn>(ObjectElements::ConvertElementsToDoubles);
  1630 bool
  1631 CodeGenerator::visitConvertElementsToDoubles(LConvertElementsToDoubles *lir)
  1633     Register elements = ToRegister(lir->elements());
  1635     OutOfLineCode *ool = oolCallVM(ConvertElementsToDoublesInfo, lir,
  1636                                    (ArgList(), elements), StoreNothing());
  1637     if (!ool)
  1638         return false;
  1640     Address convertedAddress(elements, ObjectElements::offsetOfFlags());
  1641     Imm32 bit(ObjectElements::CONVERT_DOUBLE_ELEMENTS);
  1642     masm.branchTest32(Assembler::Zero, convertedAddress, bit, ool->entry());
  1643     masm.bind(ool->rejoin());
  1644     return true;
  1647 bool
  1648 CodeGenerator::visitMaybeToDoubleElement(LMaybeToDoubleElement *lir)
  1650     Register elements = ToRegister(lir->elements());
  1651     Register value = ToRegister(lir->value());
  1652     ValueOperand out = ToOutValue(lir);
  1654     FloatRegister temp = ToFloatRegister(lir->tempFloat());
  1655     Label convert, done;
  1657     // If the CONVERT_DOUBLE_ELEMENTS flag is set, convert the int32
  1658     // value to double. Else, just box it.
  1659     masm.branchTest32(Assembler::NonZero,
  1660                       Address(elements, ObjectElements::offsetOfFlags()),
  1661                       Imm32(ObjectElements::CONVERT_DOUBLE_ELEMENTS),
  1662                       &convert);
  1664     masm.tagValue(JSVAL_TYPE_INT32, value, out);
  1665     masm.jump(&done);
  1667     masm.bind(&convert);
  1668     masm.convertInt32ToDouble(value, temp);
  1669     masm.boxDouble(temp, out);
  1671     masm.bind(&done);
  1672     return true;
  1675 bool
  1676 CodeGenerator::visitFunctionEnvironment(LFunctionEnvironment *lir)
  1678     Address environment(ToRegister(lir->function()), JSFunction::offsetOfEnvironment());
  1679     masm.loadPtr(environment, ToRegister(lir->output()));
  1680     return true;
  1683 bool
  1684 CodeGenerator::visitForkJoinContext(LForkJoinContext *lir)
  1686     const Register tempReg = ToRegister(lir->getTempReg());
  1688     masm.setupUnalignedABICall(0, tempReg);
  1689     masm.callWithABI(JS_FUNC_TO_DATA_PTR(void *, ForkJoinContextPar));
  1690     JS_ASSERT(ToRegister(lir->output()) == ReturnReg);
  1691     return true;
  1694 bool
  1695 CodeGenerator::visitGuardThreadExclusive(LGuardThreadExclusive *lir)
  1697     JS_ASSERT(gen->info().executionMode() == ParallelExecution);
  1699     const Register tempReg = ToRegister(lir->getTempReg());
  1700     masm.setupUnalignedABICall(2, tempReg);
  1701     masm.passABIArg(ToRegister(lir->forkJoinContext()));
  1702     masm.passABIArg(ToRegister(lir->object()));
  1703     masm.callWithABI(JS_FUNC_TO_DATA_PTR(void *, ParallelWriteGuard));
  1705     OutOfLineAbortPar *bail = oolAbortPar(ParallelBailoutIllegalWrite, lir);
  1706     if (!bail)
  1707         return false;
  1709     // branch to the OOL failure code if false is returned
  1710     masm.branchIfFalseBool(ReturnReg, bail->entry());
  1711     return true;
  1714 bool
  1715 CodeGenerator::visitGuardObjectIdentity(LGuardObjectIdentity *guard)
  1717     Register obj = ToRegister(guard->input());
  1719     Assembler::Condition cond =
  1720         guard->mir()->bailOnEquality() ? Assembler::Equal : Assembler::NotEqual;
  1721     return bailoutCmpPtr(cond, obj, ImmGCPtr(guard->mir()->singleObject()), guard->snapshot());
  1724 bool
  1725 CodeGenerator::visitTypeBarrierV(LTypeBarrierV *lir)
  1727     ValueOperand operand = ToValue(lir, LTypeBarrierV::Input);
  1728     Register scratch = ToTempRegisterOrInvalid(lir->temp());
  1730     Label miss;
  1731     masm.guardTypeSet(operand, lir->mir()->resultTypeSet(), scratch, &miss);
  1732     if (!bailoutFrom(&miss, lir->snapshot()))
  1733         return false;
  1734     return true;
  1737 bool
  1738 CodeGenerator::visitTypeBarrierO(LTypeBarrierO *lir)
  1740     Register obj = ToRegister(lir->object());
  1741     Register scratch = ToTempRegisterOrInvalid(lir->temp());
  1743     Label miss;
  1744     masm.guardObjectType(obj, lir->mir()->resultTypeSet(), scratch, &miss);
  1745     if (!bailoutFrom(&miss, lir->snapshot()))
  1746         return false;
  1747     return true;
  1750 bool
  1751 CodeGenerator::visitMonitorTypes(LMonitorTypes *lir)
  1753     ValueOperand operand = ToValue(lir, LMonitorTypes::Input);
  1754     Register scratch = ToTempUnboxRegister(lir->temp());
  1756     Label matched, miss;
  1757     masm.guardTypeSet(operand, lir->mir()->typeSet(), scratch, &miss);
  1758     if (!bailoutFrom(&miss, lir->snapshot()))
  1759         return false;
  1760     return true;
  1763 #ifdef JSGC_GENERATIONAL
  1764 // Out-of-line path to update the store buffer.
  1765 class OutOfLineCallPostWriteBarrier : public OutOfLineCodeBase<CodeGenerator>
  1767     LInstruction *lir_;
  1768     const LAllocation *object_;
  1770   public:
  1771     OutOfLineCallPostWriteBarrier(LInstruction *lir, const LAllocation *object)
  1772       : lir_(lir), object_(object)
  1773     { }
  1775     bool accept(CodeGenerator *codegen) {
  1776         return codegen->visitOutOfLineCallPostWriteBarrier(this);
  1779     LInstruction *lir() const {
  1780         return lir_;
  1782     const LAllocation *object() const {
  1783         return object_;
  1785 };
  1787 bool
  1788 CodeGenerator::visitOutOfLineCallPostWriteBarrier(OutOfLineCallPostWriteBarrier *ool)
  1790     saveLiveVolatile(ool->lir());
  1792     const LAllocation *obj = ool->object();
  1794     GeneralRegisterSet regs = GeneralRegisterSet::Volatile();
  1796     Register objreg;
  1797     bool isGlobal = false;
  1798     if (obj->isConstant()) {
  1799         JSObject *object = &obj->toConstant()->toObject();
  1800         isGlobal = object->is<GlobalObject>();
  1801         objreg = regs.takeAny();
  1802         masm.movePtr(ImmGCPtr(object), objreg);
  1803     } else {
  1804         objreg = ToRegister(obj);
  1805         regs.takeUnchecked(objreg);
  1808     Register runtimereg = regs.takeAny();
  1809     masm.mov(ImmPtr(GetIonContext()->runtime), runtimereg);
  1811     void (*fun)(JSRuntime*, JSObject*) = isGlobal ? PostGlobalWriteBarrier : PostWriteBarrier;
  1812     masm.setupUnalignedABICall(2, regs.takeAny());
  1813     masm.passABIArg(runtimereg);
  1814     masm.passABIArg(objreg);
  1815     masm.callWithABI(JS_FUNC_TO_DATA_PTR(void *, fun));
  1817     restoreLiveVolatile(ool->lir());
  1819     masm.jump(ool->rejoin());
  1820     return true;
  1822 #endif
  1824 bool
  1825 CodeGenerator::visitPostWriteBarrierO(LPostWriteBarrierO *lir)
  1827 #ifdef JSGC_GENERATIONAL
  1828     OutOfLineCallPostWriteBarrier *ool = new(alloc()) OutOfLineCallPostWriteBarrier(lir, lir->object());
  1829     if (!addOutOfLineCode(ool))
  1830         return false;
  1832     Register temp = ToTempRegisterOrInvalid(lir->temp());
  1834     if (lir->object()->isConstant()) {
  1835 #ifdef DEBUG
  1836         const Nursery &nursery = GetIonContext()->runtime->gcNursery();
  1837         JS_ASSERT(!nursery.isInside(&lir->object()->toConstant()->toObject()));
  1838 #endif
  1839     } else {
  1840         masm.branchPtrInNurseryRange(ToRegister(lir->object()), temp, ool->rejoin());
  1843     masm.branchPtrInNurseryRange(ToRegister(lir->value()), temp, ool->entry());
  1845     masm.bind(ool->rejoin());
  1846 #endif
  1847     return true;
  1850 bool
  1851 CodeGenerator::visitPostWriteBarrierV(LPostWriteBarrierV *lir)
  1853 #ifdef JSGC_GENERATIONAL
  1854     OutOfLineCallPostWriteBarrier *ool = new(alloc()) OutOfLineCallPostWriteBarrier(lir, lir->object());
  1855     if (!addOutOfLineCode(ool))
  1856         return false;
  1858     Register temp = ToTempRegisterOrInvalid(lir->temp());
  1860     if (lir->object()->isConstant()) {
  1861 #ifdef DEBUG
  1862         const Nursery &nursery = GetIonContext()->runtime->gcNursery();
  1863         JS_ASSERT(!nursery.isInside(&lir->object()->toConstant()->toObject()));
  1864 #endif
  1865     } else {
  1866         masm.branchPtrInNurseryRange(ToRegister(lir->object()), temp, ool->rejoin());
  1869     ValueOperand value = ToValue(lir, LPostWriteBarrierV::Input);
  1870     masm.branchValueIsNurseryObject(value, temp, ool->entry());
  1872     masm.bind(ool->rejoin());
  1873 #endif
  1874     return true;
  1877 bool
  1878 CodeGenerator::visitCallNative(LCallNative *call)
  1880     JSFunction *target = call->getSingleTarget();
  1881     JS_ASSERT(target);
  1882     JS_ASSERT(target->isNative());
  1884     int callargslot = call->argslot();
  1885     int unusedStack = StackOffsetOfPassedArg(callargslot);
  1887     // Registers used for callWithABI() argument-passing.
  1888     const Register argContextReg   = ToRegister(call->getArgContextReg());
  1889     const Register argUintNReg     = ToRegister(call->getArgUintNReg());
  1890     const Register argVpReg        = ToRegister(call->getArgVpReg());
  1892     // Misc. temporary registers.
  1893     const Register tempReg = ToRegister(call->getTempReg());
  1895     DebugOnly<uint32_t> initialStack = masm.framePushed();
  1897     masm.checkStackAlignment();
  1899     // Sequential native functions have the signature:
  1900     //  bool (*)(JSContext *, unsigned, Value *vp)
  1901     // and parallel native functions have the signature:
  1902     //  ParallelResult (*)(ForkJoinContext *, unsigned, Value *vp)
  1903     // Where vp[0] is space for an outparam, vp[1] is |this|, and vp[2] onward
  1904     // are the function arguments.
  1906     // Allocate space for the outparam, moving the StackPointer to what will be &vp[1].
  1907     masm.adjustStack(unusedStack);
  1909     // Push a Value containing the callee object: natives are allowed to access their callee before
  1910     // setitng the return value. The StackPointer is moved to &vp[0].
  1911     masm.Push(ObjectValue(*target));
  1913     // Preload arguments into registers.
  1914     //
  1915     // Note that for parallel execution, loadContext does an ABI call, so we
  1916     // need to do this before we load the other argument registers, otherwise
  1917     // we'll hose them.
  1918     ExecutionMode executionMode = gen->info().executionMode();
  1919     masm.loadContext(argContextReg, tempReg, executionMode);
  1920     masm.move32(Imm32(call->numStackArgs()), argUintNReg);
  1921     masm.movePtr(StackPointer, argVpReg);
  1923     masm.Push(argUintNReg);
  1925     // Construct native exit frame.
  1926     uint32_t safepointOffset;
  1927     if (!masm.buildFakeExitFrame(tempReg, &safepointOffset))
  1928         return false;
  1929     masm.enterFakeExitFrame(argContextReg, tempReg, executionMode);
  1931     if (!markSafepointAt(safepointOffset, call))
  1932         return false;
  1934     // Construct and execute call.
  1935     masm.setupUnalignedABICall(3, tempReg);
  1936     masm.passABIArg(argContextReg);
  1937     masm.passABIArg(argUintNReg);
  1938     masm.passABIArg(argVpReg);
  1940     switch (executionMode) {
  1941       case SequentialExecution:
  1942         masm.callWithABI(JS_FUNC_TO_DATA_PTR(void *, target->native()));
  1943         break;
  1945       case ParallelExecution:
  1946         masm.callWithABI(JS_FUNC_TO_DATA_PTR(void *, target->parallelNative()));
  1947         break;
  1949       default:
  1950         MOZ_ASSUME_UNREACHABLE("No such execution mode");
  1953     // Test for failure.
  1954     masm.branchIfFalseBool(ReturnReg, masm.failureLabel(executionMode));
  1956     // Load the outparam vp[0] into output register(s).
  1957     masm.loadValue(Address(StackPointer, IonNativeExitFrameLayout::offsetOfResult()), JSReturnOperand);
  1959     // The next instruction is removing the footer of the exit frame, so there
  1960     // is no need for leaveFakeExitFrame.
  1962     // Move the StackPointer back to its original location, unwinding the native exit frame.
  1963     masm.adjustStack(IonNativeExitFrameLayout::Size() - unusedStack);
  1964     JS_ASSERT(masm.framePushed() == initialStack);
  1966     dropArguments(call->numStackArgs() + 1);
  1967     return true;
  1970 bool
  1971 CodeGenerator::visitCallDOMNative(LCallDOMNative *call)
  1973     JSFunction *target = call->getSingleTarget();
  1974     JS_ASSERT(target);
  1975     JS_ASSERT(target->isNative());
  1976     JS_ASSERT(target->jitInfo());
  1977     JS_ASSERT(call->mir()->isCallDOMNative());
  1979     int callargslot = call->argslot();
  1980     int unusedStack = StackOffsetOfPassedArg(callargslot);
  1982     // Registers used for callWithABI() argument-passing.
  1983     const Register argJSContext = ToRegister(call->getArgJSContext());
  1984     const Register argObj       = ToRegister(call->getArgObj());
  1985     const Register argPrivate   = ToRegister(call->getArgPrivate());
  1986     const Register argArgs      = ToRegister(call->getArgArgs());
  1988     DebugOnly<uint32_t> initialStack = masm.framePushed();
  1990     masm.checkStackAlignment();
  1992     // DOM methods have the signature:
  1993     //  bool (*)(JSContext *, HandleObject, void *private, const JSJitMethodCallArgs& args)
  1994     // Where args is initialized from an argc and a vp, vp[0] is space for an
  1995     // outparam and the callee, vp[1] is |this|, and vp[2] onward are the
  1996     // function arguments.  Note that args stores the argv, not the vp, and
  1997     // argv == vp + 2.
  1999     // Nestle the stack up against the pushed arguments, leaving StackPointer at
  2000     // &vp[1]
  2001     masm.adjustStack(unusedStack);
  2002     // argObj is filled with the extracted object, then returned.
  2003     Register obj = masm.extractObject(Address(StackPointer, 0), argObj);
  2004     JS_ASSERT(obj == argObj);
  2006     // Push a Value containing the callee object: natives are allowed to access their callee before
  2007     // setitng the return value. After this the StackPointer points to &vp[0].
  2008     masm.Push(ObjectValue(*target));
  2010     // Now compute the argv value.  Since StackPointer is pointing to &vp[0] and
  2011     // argv is &vp[2] we just need to add 2*sizeof(Value) to the current
  2012     // StackPointer.
  2013     JS_STATIC_ASSERT(JSJitMethodCallArgsTraits::offsetOfArgv == 0);
  2014     JS_STATIC_ASSERT(JSJitMethodCallArgsTraits::offsetOfArgc ==
  2015                      IonDOMMethodExitFrameLayoutTraits::offsetOfArgcFromArgv);
  2016     masm.computeEffectiveAddress(Address(StackPointer, 2 * sizeof(Value)), argArgs);
  2018     // GetReservedSlot(obj, DOM_OBJECT_SLOT).toPrivate()
  2019     masm.loadPrivate(Address(obj, JSObject::getFixedSlotOffset(0)), argPrivate);
  2021     // Push argc from the call instruction into what will become the IonExitFrame
  2022     masm.Push(Imm32(call->numStackArgs()));
  2024     // Push our argv onto the stack
  2025     masm.Push(argArgs);
  2026     // And store our JSJitMethodCallArgs* in argArgs.
  2027     masm.movePtr(StackPointer, argArgs);
  2029     // Push |this| object for passing HandleObject. We push after argc to
  2030     // maintain the same sp-relative location of the object pointer with other
  2031     // DOMExitFrames.
  2032     masm.Push(argObj);
  2033     masm.movePtr(StackPointer, argObj);
  2035     // Construct native exit frame.
  2036     uint32_t safepointOffset;
  2037     if (!masm.buildFakeExitFrame(argJSContext, &safepointOffset))
  2038         return false;
  2039     masm.enterFakeExitFrame(ION_FRAME_DOMMETHOD);
  2041     if (!markSafepointAt(safepointOffset, call))
  2042         return false;
  2044     // Construct and execute call.
  2045     masm.setupUnalignedABICall(4, argJSContext);
  2047     masm.loadJSContext(argJSContext);
  2049     masm.passABIArg(argJSContext);
  2050     masm.passABIArg(argObj);
  2051     masm.passABIArg(argPrivate);
  2052     masm.passABIArg(argArgs);
  2053     masm.callWithABI(JS_FUNC_TO_DATA_PTR(void *, target->jitInfo()->method));
  2055     if (target->jitInfo()->isInfallible) {
  2056         masm.loadValue(Address(StackPointer, IonDOMMethodExitFrameLayout::offsetOfResult()),
  2057                        JSReturnOperand);
  2058     } else {
  2059         // Test for failure.
  2060         masm.branchIfFalseBool(ReturnReg, masm.exceptionLabel());
  2062         // Load the outparam vp[0] into output register(s).
  2063         masm.loadValue(Address(StackPointer, IonDOMMethodExitFrameLayout::offsetOfResult()),
  2064                        JSReturnOperand);
  2067     // The next instruction is removing the footer of the exit frame, so there
  2068     // is no need for leaveFakeExitFrame.
  2070     // Move the StackPointer back to its original location, unwinding the native exit frame.
  2071     masm.adjustStack(IonDOMMethodExitFrameLayout::Size() - unusedStack);
  2072     JS_ASSERT(masm.framePushed() == initialStack);
  2074     dropArguments(call->numStackArgs() + 1);
  2075     return true;
  2078 typedef bool (*GetIntrinsicValueFn)(JSContext *cx, HandlePropertyName, MutableHandleValue);
  2079 static const VMFunction GetIntrinsicValueInfo =
  2080     FunctionInfo<GetIntrinsicValueFn>(GetIntrinsicValue);
  2082 bool
  2083 CodeGenerator::visitCallGetIntrinsicValue(LCallGetIntrinsicValue *lir)
  2085     pushArg(ImmGCPtr(lir->mir()->name()));
  2086     return callVM(GetIntrinsicValueInfo, lir);
  2089 typedef bool (*InvokeFunctionFn)(JSContext *, HandleObject, uint32_t, Value *, Value *);
  2090 static const VMFunction InvokeFunctionInfo = FunctionInfo<InvokeFunctionFn>(InvokeFunction);
  2092 bool
  2093 CodeGenerator::emitCallInvokeFunction(LInstruction *call, Register calleereg,
  2094                                       uint32_t argc, uint32_t unusedStack)
  2096     // Nestle %esp up to the argument vector.
  2097     // Each path must account for framePushed_ separately, for callVM to be valid.
  2098     masm.freeStack(unusedStack);
  2100     pushArg(StackPointer); // argv.
  2101     pushArg(Imm32(argc));  // argc.
  2102     pushArg(calleereg);    // JSFunction *.
  2104     if (!callVM(InvokeFunctionInfo, call))
  2105         return false;
  2107     // Un-nestle %esp from the argument vector. No prefix was pushed.
  2108     masm.reserveStack(unusedStack);
  2109     return true;
  2112 bool
  2113 CodeGenerator::visitCallGeneric(LCallGeneric *call)
  2115     Register calleereg = ToRegister(call->getFunction());
  2116     Register objreg    = ToRegister(call->getTempObject());
  2117     Register nargsreg  = ToRegister(call->getNargsReg());
  2118     uint32_t unusedStack = StackOffsetOfPassedArg(call->argslot());
  2119     ExecutionMode executionMode = gen->info().executionMode();
  2120     Label invoke, thunk, makeCall, end;
  2122     // Known-target case is handled by LCallKnown.
  2123     JS_ASSERT(!call->hasSingleTarget());
  2125     // Generate an ArgumentsRectifier.
  2126     JitCode *argumentsRectifier = gen->jitRuntime()->getArgumentsRectifier(executionMode);
  2128     masm.checkStackAlignment();
  2130     // Guard that calleereg is actually a function object.
  2131     masm.loadObjClass(calleereg, nargsreg);
  2132     masm.branchPtr(Assembler::NotEqual, nargsreg, ImmPtr(&JSFunction::class_), &invoke);
  2134     // Guard that calleereg is an interpreted function with a JSScript.
  2135     // If we are constructing, also ensure the callee is a constructor.
  2136     if (call->mir()->isConstructing())
  2137         masm.branchIfNotInterpretedConstructor(calleereg, nargsreg, &invoke);
  2138     else
  2139         masm.branchIfFunctionHasNoScript(calleereg, &invoke);
  2141     // Knowing that calleereg is a non-native function, load the JSScript.
  2142     masm.loadPtr(Address(calleereg, JSFunction::offsetOfNativeOrScript()), objreg);
  2144     // Load script jitcode.
  2145     masm.loadBaselineOrIonRaw(objreg, objreg, executionMode, &invoke);
  2147     // Nestle the StackPointer up to the argument vector.
  2148     masm.freeStack(unusedStack);
  2150     // Construct the IonFramePrefix.
  2151     uint32_t descriptor = MakeFrameDescriptor(masm.framePushed(), JitFrame_IonJS);
  2152     masm.Push(Imm32(call->numActualArgs()));
  2153     masm.Push(calleereg);
  2154     masm.Push(Imm32(descriptor));
  2156     // Check whether the provided arguments satisfy target argc.
  2157     masm.load16ZeroExtend(Address(calleereg, JSFunction::offsetOfNargs()), nargsreg);
  2158     masm.branch32(Assembler::Above, nargsreg, Imm32(call->numStackArgs()), &thunk);
  2159     masm.jump(&makeCall);
  2161     // Argument fixed needed. Load the ArgumentsRectifier.
  2162     masm.bind(&thunk);
  2164         JS_ASSERT(ArgumentsRectifierReg != objreg);
  2165         masm.movePtr(ImmGCPtr(argumentsRectifier), objreg); // Necessary for GC marking.
  2166         masm.loadPtr(Address(objreg, JitCode::offsetOfCode()), objreg);
  2167         masm.move32(Imm32(call->numStackArgs()), ArgumentsRectifierReg);
  2170     // Finally call the function in objreg.
  2171     masm.bind(&makeCall);
  2172     uint32_t callOffset = masm.callIon(objreg);
  2173     if (!markSafepointAt(callOffset, call))
  2174         return false;
  2176     // Increment to remove IonFramePrefix; decrement to fill FrameSizeClass.
  2177     // The return address has already been removed from the Ion frame.
  2178     int prefixGarbage = sizeof(IonJSFrameLayout) - sizeof(void *);
  2179     masm.adjustStack(prefixGarbage - unusedStack);
  2180     masm.jump(&end);
  2182     // Handle uncompiled or native functions.
  2183     masm.bind(&invoke);
  2184     switch (executionMode) {
  2185       case SequentialExecution:
  2186         if (!emitCallInvokeFunction(call, calleereg, call->numActualArgs(), unusedStack))
  2187             return false;
  2188         break;
  2190       case ParallelExecution:
  2191         if (!emitCallToUncompiledScriptPar(call, calleereg))
  2192             return false;
  2193         break;
  2195       default:
  2196         MOZ_ASSUME_UNREACHABLE("No such execution mode");
  2199     masm.bind(&end);
  2201     // If the return value of the constructing function is Primitive,
  2202     // replace the return value with the Object from CreateThis.
  2203     if (call->mir()->isConstructing()) {
  2204         Label notPrimitive;
  2205         masm.branchTestPrimitive(Assembler::NotEqual, JSReturnOperand, &notPrimitive);
  2206         masm.loadValue(Address(StackPointer, unusedStack), JSReturnOperand);
  2207         masm.bind(&notPrimitive);
  2210     if (!checkForAbortPar(call))
  2211         return false;
  2213     dropArguments(call->numStackArgs() + 1);
  2214     return true;
  2217 // Generates a call to CallToUncompiledScriptPar() and then bails out.
  2218 // |calleeReg| should contain the JSFunction*.
  2219 bool
  2220 CodeGenerator::emitCallToUncompiledScriptPar(LInstruction *lir, Register calleeReg)
  2222     OutOfLineCode *bail = oolAbortPar(ParallelBailoutCalledToUncompiledScript, lir);
  2223     if (!bail)
  2224         return false;
  2226     masm.movePtr(calleeReg, CallTempReg0);
  2227     masm.setupUnalignedABICall(1, CallTempReg1);
  2228     masm.passABIArg(CallTempReg0);
  2229     masm.callWithABI(JS_FUNC_TO_DATA_PTR(void *, CallToUncompiledScriptPar));
  2230     masm.jump(bail->entry());
  2231     return true;
  2234 bool
  2235 CodeGenerator::visitCallKnown(LCallKnown *call)
  2237     Register calleereg = ToRegister(call->getFunction());
  2238     Register objreg    = ToRegister(call->getTempObject());
  2239     uint32_t unusedStack = StackOffsetOfPassedArg(call->argslot());
  2240     DebugOnly<JSFunction *> target = call->getSingleTarget();
  2241     ExecutionMode executionMode = gen->info().executionMode();
  2242     Label end, uncompiled;
  2244     // Native single targets are handled by LCallNative.
  2245     JS_ASSERT(!target->isNative());
  2246     // Missing arguments must have been explicitly appended by the IonBuilder.
  2247     JS_ASSERT(target->nargs() <= call->numStackArgs());
  2249     JS_ASSERT_IF(call->mir()->isConstructing(), target->isInterpretedConstructor());
  2251     masm.checkStackAlignment();
  2253     // The calleereg is known to be a non-native function, but might point to
  2254     // a LazyScript instead of a JSScript.
  2255     masm.branchIfFunctionHasNoScript(calleereg, &uncompiled);
  2257     // Knowing that calleereg is a non-native function, load the JSScript.
  2258     masm.loadPtr(Address(calleereg, JSFunction::offsetOfNativeOrScript()), objreg);
  2260     // Load script jitcode.
  2261     if (call->mir()->needsArgCheck())
  2262         masm.loadBaselineOrIonRaw(objreg, objreg, executionMode, &uncompiled);
  2263     else
  2264         masm.loadBaselineOrIonNoArgCheck(objreg, objreg, executionMode, &uncompiled);
  2266     // Nestle the StackPointer up to the argument vector.
  2267     masm.freeStack(unusedStack);
  2269     // Construct the IonFramePrefix.
  2270     uint32_t descriptor = MakeFrameDescriptor(masm.framePushed(), JitFrame_IonJS);
  2271     masm.Push(Imm32(call->numActualArgs()));
  2272     masm.Push(calleereg);
  2273     masm.Push(Imm32(descriptor));
  2275     // Finally call the function in objreg.
  2276     uint32_t callOffset = masm.callIon(objreg);
  2277     if (!markSafepointAt(callOffset, call))
  2278         return false;
  2280     // Increment to remove IonFramePrefix; decrement to fill FrameSizeClass.
  2281     // The return address has already been removed from the Ion frame.
  2282     int prefixGarbage = sizeof(IonJSFrameLayout) - sizeof(void *);
  2283     masm.adjustStack(prefixGarbage - unusedStack);
  2284     masm.jump(&end);
  2286     // Handle uncompiled functions.
  2287     masm.bind(&uncompiled);
  2288     switch (executionMode) {
  2289       case SequentialExecution:
  2290         if (!emitCallInvokeFunction(call, calleereg, call->numActualArgs(), unusedStack))
  2291             return false;
  2292         break;
  2294       case ParallelExecution:
  2295         if (!emitCallToUncompiledScriptPar(call, calleereg))
  2296             return false;
  2297         break;
  2299       default:
  2300         MOZ_ASSUME_UNREACHABLE("No such execution mode");
  2303     masm.bind(&end);
  2305     if (!checkForAbortPar(call))
  2306         return false;
  2308     // If the return value of the constructing function is Primitive,
  2309     // replace the return value with the Object from CreateThis.
  2310     if (call->mir()->isConstructing()) {
  2311         Label notPrimitive;
  2312         masm.branchTestPrimitive(Assembler::NotEqual, JSReturnOperand, &notPrimitive);
  2313         masm.loadValue(Address(StackPointer, unusedStack), JSReturnOperand);
  2314         masm.bind(&notPrimitive);
  2317     dropArguments(call->numStackArgs() + 1);
  2318     return true;
  2321 bool
  2322 CodeGenerator::checkForAbortPar(LInstruction *lir)
  2324     // In parallel mode, if we call another ion-compiled function and
  2325     // it returns JS_ION_ERROR, that indicates a bailout that we have
  2326     // to propagate up the stack.
  2327     ExecutionMode executionMode = gen->info().executionMode();
  2328     if (executionMode == ParallelExecution) {
  2329         OutOfLinePropagateAbortPar *bail = oolPropagateAbortPar(lir);
  2330         if (!bail)
  2331             return false;
  2332         masm.branchTestMagic(Assembler::Equal, JSReturnOperand, bail->entry());
  2334     return true;
  2337 bool
  2338 CodeGenerator::emitCallInvokeFunction(LApplyArgsGeneric *apply, Register extraStackSize)
  2340     Register objreg = ToRegister(apply->getTempObject());
  2341     JS_ASSERT(objreg != extraStackSize);
  2343     // Push the space used by the arguments.
  2344     masm.movePtr(StackPointer, objreg);
  2345     masm.Push(extraStackSize);
  2347     pushArg(objreg);                           // argv.
  2348     pushArg(ToRegister(apply->getArgc()));     // argc.
  2349     pushArg(ToRegister(apply->getFunction())); // JSFunction *.
  2351     // This specialization og callVM restore the extraStackSize after the call.
  2352     if (!callVM(InvokeFunctionInfo, apply, &extraStackSize))
  2353         return false;
  2355     masm.Pop(extraStackSize);
  2356     return true;
  2359 // Do not bailout after the execution of this function since the stack no longer
  2360 // correspond to what is expected by the snapshots.
  2361 void
  2362 CodeGenerator::emitPushArguments(LApplyArgsGeneric *apply, Register extraStackSpace)
  2364     // Holds the function nargs. Initially undefined.
  2365     Register argcreg = ToRegister(apply->getArgc());
  2367     Register copyreg = ToRegister(apply->getTempObject());
  2368     size_t argvOffset = frameSize() + IonJSFrameLayout::offsetOfActualArgs();
  2369     Label end;
  2371     // Initialize the loop counter AND Compute the stack usage (if == 0)
  2372     masm.movePtr(argcreg, extraStackSpace);
  2373     masm.branchTestPtr(Assembler::Zero, argcreg, argcreg, &end);
  2375     // Copy arguments.
  2377         Register count = extraStackSpace; // <- argcreg
  2378         Label loop;
  2379         masm.bind(&loop);
  2381         // We remove sizeof(void*) from argvOffset because withtout it we target
  2382         // the address after the memory area that we want to copy.
  2383         BaseIndex disp(StackPointer, argcreg, ScaleFromElemWidth(sizeof(Value)), argvOffset - sizeof(void*));
  2385         // Do not use Push here because other this account to 1 in the framePushed
  2386         // instead of 0.  These push are only counted by argcreg.
  2387         masm.loadPtr(disp, copyreg);
  2388         masm.push(copyreg);
  2390         // Handle 32 bits architectures.
  2391         if (sizeof(Value) == 2 * sizeof(void*)) {
  2392             masm.loadPtr(disp, copyreg);
  2393             masm.push(copyreg);
  2396         masm.decBranchPtr(Assembler::NonZero, count, Imm32(1), &loop);
  2399     // Compute the stack usage.
  2400     masm.movePtr(argcreg, extraStackSpace);
  2401     masm.lshiftPtr(Imm32::ShiftOf(ScaleFromElemWidth(sizeof(Value))), extraStackSpace);
  2403     // Join with all arguments copied and the extra stack usage computed.
  2404     masm.bind(&end);
  2406     // Push |this|.
  2407     masm.addPtr(Imm32(sizeof(Value)), extraStackSpace);
  2408     masm.pushValue(ToValue(apply, LApplyArgsGeneric::ThisIndex));
  2411 void
  2412 CodeGenerator::emitPopArguments(LApplyArgsGeneric *apply, Register extraStackSpace)
  2414     // Pop |this| and Arguments.
  2415     masm.freeStack(extraStackSpace);
  2418 bool
  2419 CodeGenerator::visitApplyArgsGeneric(LApplyArgsGeneric *apply)
  2421     // Holds the function object.
  2422     Register calleereg = ToRegister(apply->getFunction());
  2424     // Temporary register for modifying the function object.
  2425     Register objreg = ToRegister(apply->getTempObject());
  2426     Register copyreg = ToRegister(apply->getTempCopy());
  2428     // Holds the function nargs. Initially undefined.
  2429     Register argcreg = ToRegister(apply->getArgc());
  2431     // Unless already known, guard that calleereg is actually a function object.
  2432     if (!apply->hasSingleTarget()) {
  2433         masm.loadObjClass(calleereg, objreg);
  2435         ImmPtr ptr = ImmPtr(&JSFunction::class_);
  2436         if (!bailoutCmpPtr(Assembler::NotEqual, objreg, ptr, apply->snapshot()))
  2437             return false;
  2440     // Copy the arguments of the current function.
  2441     emitPushArguments(apply, copyreg);
  2443     masm.checkStackAlignment();
  2445     // If the function is known to be uncompilable, only emit the call to InvokeFunction.
  2446     ExecutionMode executionMode = gen->info().executionMode();
  2447     if (apply->hasSingleTarget()) {
  2448         JSFunction *target = apply->getSingleTarget();
  2449         if (target->isNative()) {
  2450             if (!emitCallInvokeFunction(apply, copyreg))
  2451                 return false;
  2452             emitPopArguments(apply, copyreg);
  2453             return true;
  2457     Label end, invoke;
  2459     // Guard that calleereg is an interpreted function with a JSScript:
  2460     if (!apply->hasSingleTarget()) {
  2461         masm.branchIfFunctionHasNoScript(calleereg, &invoke);
  2462     } else {
  2463         // Native single targets are handled by LCallNative.
  2464         JS_ASSERT(!apply->getSingleTarget()->isNative());
  2467     // Knowing that calleereg is a non-native function, load the JSScript.
  2468     masm.loadPtr(Address(calleereg, JSFunction::offsetOfNativeOrScript()), objreg);
  2470     // Load script jitcode.
  2471     masm.loadBaselineOrIonRaw(objreg, objreg, executionMode, &invoke);
  2473     // Call with an Ion frame or a rectifier frame.
  2475         // Create the frame descriptor.
  2476         unsigned pushed = masm.framePushed();
  2477         masm.addPtr(Imm32(pushed), copyreg);
  2478         masm.makeFrameDescriptor(copyreg, JitFrame_IonJS);
  2480         masm.Push(argcreg);
  2481         masm.Push(calleereg);
  2482         masm.Push(copyreg); // descriptor
  2484         Label underflow, rejoin;
  2486         // Check whether the provided arguments satisfy target argc.
  2487         if (!apply->hasSingleTarget()) {
  2488             masm.load16ZeroExtend(Address(calleereg, JSFunction::offsetOfNargs()), copyreg);
  2489             masm.branch32(Assembler::Below, argcreg, copyreg, &underflow);
  2490         } else {
  2491             masm.branch32(Assembler::Below, argcreg, Imm32(apply->getSingleTarget()->nargs()),
  2492                           &underflow);
  2495         // Skip the construction of the rectifier frame because we have no
  2496         // underflow.
  2497         masm.jump(&rejoin);
  2499         // Argument fixup needed. Get ready to call the argumentsRectifier.
  2501             masm.bind(&underflow);
  2503             // Hardcode the address of the argumentsRectifier code.
  2504             JitCode *argumentsRectifier = gen->jitRuntime()->getArgumentsRectifier(executionMode);
  2506             JS_ASSERT(ArgumentsRectifierReg != objreg);
  2507             masm.movePtr(ImmGCPtr(argumentsRectifier), objreg); // Necessary for GC marking.
  2508             masm.loadPtr(Address(objreg, JitCode::offsetOfCode()), objreg);
  2509             masm.movePtr(argcreg, ArgumentsRectifierReg);
  2512         masm.bind(&rejoin);
  2514         // Finally call the function in objreg, as assigned by one of the paths above.
  2515         uint32_t callOffset = masm.callIon(objreg);
  2516         if (!markSafepointAt(callOffset, apply))
  2517             return false;
  2519         // Recover the number of arguments from the frame descriptor.
  2520         masm.loadPtr(Address(StackPointer, 0), copyreg);
  2521         masm.rshiftPtr(Imm32(FRAMESIZE_SHIFT), copyreg);
  2522         masm.subPtr(Imm32(pushed), copyreg);
  2524         // Increment to remove IonFramePrefix; decrement to fill FrameSizeClass.
  2525         // The return address has already been removed from the Ion frame.
  2526         int prefixGarbage = sizeof(IonJSFrameLayout) - sizeof(void *);
  2527         masm.adjustStack(prefixGarbage);
  2528         masm.jump(&end);
  2531     // Handle uncompiled or native functions.
  2533         masm.bind(&invoke);
  2534         if (!emitCallInvokeFunction(apply, copyreg))
  2535             return false;
  2538     // Pop arguments and continue.
  2539     masm.bind(&end);
  2540     emitPopArguments(apply, copyreg);
  2542     return true;
  2545 typedef bool (*ArraySpliceDenseFn)(JSContext *, HandleObject, uint32_t, uint32_t);
  2546 static const VMFunction ArraySpliceDenseInfo = FunctionInfo<ArraySpliceDenseFn>(ArraySpliceDense);
  2548 bool
  2549 CodeGenerator::visitArraySplice(LArraySplice *lir)
  2551     pushArg(ToRegister(lir->getDeleteCount()));
  2552     pushArg(ToRegister(lir->getStart()));
  2553     pushArg(ToRegister(lir->getObject()));
  2554     return callVM(ArraySpliceDenseInfo, lir);
  2558 bool
  2559 CodeGenerator::visitBail(LBail *lir)
  2561     return bailout(lir->snapshot());
  2564 bool
  2565 CodeGenerator::visitGetDynamicName(LGetDynamicName *lir)
  2567     Register scopeChain = ToRegister(lir->getScopeChain());
  2568     Register name = ToRegister(lir->getName());
  2569     Register temp1 = ToRegister(lir->temp1());
  2570     Register temp2 = ToRegister(lir->temp2());
  2571     Register temp3 = ToRegister(lir->temp3());
  2573     masm.loadJSContext(temp3);
  2575     /* Make space for the outparam. */
  2576     masm.adjustStack(-int32_t(sizeof(Value)));
  2577     masm.movePtr(StackPointer, temp2);
  2579     masm.setupUnalignedABICall(4, temp1);
  2580     masm.passABIArg(temp3);
  2581     masm.passABIArg(scopeChain);
  2582     masm.passABIArg(name);
  2583     masm.passABIArg(temp2);
  2584     masm.callWithABI(JS_FUNC_TO_DATA_PTR(void *, GetDynamicName));
  2586     const ValueOperand out = ToOutValue(lir);
  2588     masm.loadValue(Address(StackPointer, 0), out);
  2589     masm.adjustStack(sizeof(Value));
  2591     Label undefined;
  2592     masm.branchTestUndefined(Assembler::Equal, out, &undefined);
  2593     return bailoutFrom(&undefined, lir->snapshot());
  2596 bool
  2597 CodeGenerator::emitFilterArgumentsOrEval(LInstruction *lir, Register string,
  2598                                          Register temp1, Register temp2)
  2600     masm.loadJSContext(temp2);
  2602     masm.setupUnalignedABICall(2, temp1);
  2603     masm.passABIArg(temp2);
  2604     masm.passABIArg(string);
  2605     masm.callWithABI(JS_FUNC_TO_DATA_PTR(void *, FilterArgumentsOrEval));
  2607     Label bail;
  2608     masm.branchIfFalseBool(ReturnReg, &bail);
  2609     return bailoutFrom(&bail, lir->snapshot());
  2612 bool
  2613 CodeGenerator::visitFilterArgumentsOrEvalS(LFilterArgumentsOrEvalS *lir)
  2615     return emitFilterArgumentsOrEval(lir, ToRegister(lir->getString()),
  2616                                      ToRegister(lir->temp1()),
  2617                                      ToRegister(lir->temp2()));
  2620 bool
  2621 CodeGenerator::visitFilterArgumentsOrEvalV(LFilterArgumentsOrEvalV *lir)
  2623     ValueOperand input = ToValue(lir, LFilterArgumentsOrEvalV::Input);
  2625     // Act as nop on non-strings.
  2626     Label done;
  2627     masm.branchTestString(Assembler::NotEqual, input, &done);
  2629     if (!emitFilterArgumentsOrEval(lir, masm.extractString(input, ToRegister(lir->temp3())),
  2630                                    ToRegister(lir->temp1()), ToRegister(lir->temp2())))
  2632         return false;
  2635     masm.bind(&done);
  2636     return true;
  2639 typedef bool (*DirectEvalSFn)(JSContext *, HandleObject, HandleScript, HandleValue, HandleString,
  2640                               jsbytecode *, MutableHandleValue);
  2641 static const VMFunction DirectEvalStringInfo = FunctionInfo<DirectEvalSFn>(DirectEvalStringFromIon);
  2643 bool
  2644 CodeGenerator::visitCallDirectEvalS(LCallDirectEvalS *lir)
  2646     Register scopeChain = ToRegister(lir->getScopeChain());
  2647     Register string = ToRegister(lir->getString());
  2649     pushArg(ImmPtr(lir->mir()->pc()));
  2650     pushArg(string);
  2651     pushArg(ToValue(lir, LCallDirectEvalS::ThisValue));
  2652     pushArg(ImmGCPtr(gen->info().script()));
  2653     pushArg(scopeChain);
  2655     return callVM(DirectEvalStringInfo, lir);
  2658 typedef bool (*DirectEvalVFn)(JSContext *, HandleObject, HandleScript, HandleValue, HandleValue,
  2659                               jsbytecode *, MutableHandleValue);
  2660 static const VMFunction DirectEvalValueInfo = FunctionInfo<DirectEvalVFn>(DirectEvalValueFromIon);
  2662 bool
  2663 CodeGenerator::visitCallDirectEvalV(LCallDirectEvalV *lir)
  2665     Register scopeChain = ToRegister(lir->getScopeChain());
  2667     pushArg(ImmPtr(lir->mir()->pc()));
  2668     pushArg(ToValue(lir, LCallDirectEvalV::Argument));
  2669     pushArg(ToValue(lir, LCallDirectEvalV::ThisValue));
  2670     pushArg(ImmGCPtr(gen->info().script()));
  2671     pushArg(scopeChain);
  2673     return callVM(DirectEvalValueInfo, lir);
  2676 // Registers safe for use before generatePrologue().
  2677 static const uint32_t EntryTempMask = Registers::TempMask & ~(1 << OsrFrameReg.code());
  2679 bool
  2680 CodeGenerator::generateArgumentsChecks(bool bailout)
  2682     // This function can be used the normal way to check the argument types,
  2683     // before entering the function and bailout when arguments don't match.
  2684     // For debug purpose, this is can also be used to force/check that the
  2685     // arguments are correct. Upon fail it will hit a breakpoint.
  2687     MIRGraph &mir = gen->graph();
  2688     MResumePoint *rp = mir.entryResumePoint();
  2690     // Reserve the amount of stack the actual frame will use. We have to undo
  2691     // this before falling through to the method proper though, because the
  2692     // monomorphic call case will bypass this entire path.
  2693     masm.reserveStack(frameSize());
  2695     // No registers are allocated yet, so it's safe to grab anything.
  2696     Register temp = GeneralRegisterSet(EntryTempMask).getAny();
  2698     CompileInfo &info = gen->info();
  2700     Label miss;
  2701     for (uint32_t i = info.startArgSlot(); i < info.endArgSlot(); i++) {
  2702         // All initial parameters are guaranteed to be MParameters.
  2703         MParameter *param = rp->getOperand(i)->toParameter();
  2704         const types::TypeSet *types = param->resultTypeSet();
  2705         if (!types || types->unknown())
  2706             continue;
  2708         // Calculate the offset on the stack of the argument.
  2709         // (i - info.startArgSlot())    - Compute index of arg within arg vector.
  2710         // ... * sizeof(Value)          - Scale by value size.
  2711         // ArgToStackOffset(...)        - Compute displacement within arg vector.
  2712         int32_t offset = ArgToStackOffset((i - info.startArgSlot()) * sizeof(Value));
  2713         masm.guardTypeSet(Address(StackPointer, offset), types, temp, &miss);
  2716     if (miss.used()) {
  2717         if (bailout) {
  2718             if (!bailoutFrom(&miss, graph.entrySnapshot()))
  2719                 return false;
  2720         } else {
  2721             Label success;
  2722             masm.jump(&success);
  2723             masm.bind(&miss);
  2724             masm.assumeUnreachable("Argument check fail.");
  2725             masm.bind(&success);
  2729     masm.freeStack(frameSize());
  2731     return true;
  2734 // Out-of-line path to report over-recursed error and fail.
  2735 class CheckOverRecursedFailure : public OutOfLineCodeBase<CodeGenerator>
  2737     LCheckOverRecursed *lir_;
  2739   public:
  2740     CheckOverRecursedFailure(LCheckOverRecursed *lir)
  2741       : lir_(lir)
  2742     { }
  2744     bool accept(CodeGenerator *codegen) {
  2745         return codegen->visitCheckOverRecursedFailure(this);
  2748     LCheckOverRecursed *lir() const {
  2749         return lir_;
  2751 };
  2753 bool
  2754 CodeGenerator::visitCheckOverRecursed(LCheckOverRecursed *lir)
  2756     // If we don't push anything on the stack, skip the check.
  2757     if (omitOverRecursedCheck())
  2758         return true;
  2760     // Ensure that this frame will not cross the stack limit.
  2761     // This is a weak check, justified by Ion using the C stack: we must always
  2762     // be some distance away from the actual limit, since if the limit is
  2763     // crossed, an error must be thrown, which requires more frames.
  2764     //
  2765     // It must always be possible to trespass past the stack limit.
  2766     // Ion may legally place frames very close to the limit. Calling additional
  2767     // C functions may then violate the limit without any checking.
  2769     // Since Ion frames exist on the C stack, the stack limit may be
  2770     // dynamically set by JS_SetThreadStackLimit() and JS_SetNativeStackQuota().
  2771     const void *limitAddr = GetIonContext()->runtime->addressOfJitStackLimit();
  2773     CheckOverRecursedFailure *ool = new(alloc()) CheckOverRecursedFailure(lir);
  2774     if (!addOutOfLineCode(ool))
  2775         return false;
  2777     // Conditional forward (unlikely) branch to failure.
  2778     masm.branchPtr(Assembler::AboveOrEqual, AbsoluteAddress(limitAddr), StackPointer, ool->entry());
  2779     masm.bind(ool->rejoin());
  2781     return true;
  2784 typedef bool (*DefVarOrConstFn)(JSContext *, HandlePropertyName, unsigned, HandleObject);
  2785 static const VMFunction DefVarOrConstInfo =
  2786     FunctionInfo<DefVarOrConstFn>(DefVarOrConst);
  2788 bool
  2789 CodeGenerator::visitDefVar(LDefVar *lir)
  2791     Register scopeChain = ToRegister(lir->scopeChain());
  2793     pushArg(scopeChain); // JSObject *
  2794     pushArg(Imm32(lir->mir()->attrs())); // unsigned
  2795     pushArg(ImmGCPtr(lir->mir()->name())); // PropertyName *
  2797     if (!callVM(DefVarOrConstInfo, lir))
  2798         return false;
  2800     return true;
  2803 typedef bool (*DefFunOperationFn)(JSContext *, HandleScript, HandleObject, HandleFunction);
  2804 static const VMFunction DefFunOperationInfo = FunctionInfo<DefFunOperationFn>(DefFunOperation);
  2806 bool
  2807 CodeGenerator::visitDefFun(LDefFun *lir)
  2809     Register scopeChain = ToRegister(lir->scopeChain());
  2811     pushArg(ImmGCPtr(lir->mir()->fun()));
  2812     pushArg(scopeChain);
  2813     pushArg(ImmGCPtr(current->mir()->info().script()));
  2815     return callVM(DefFunOperationInfo, lir);
  2818 typedef bool (*ReportOverRecursedFn)(JSContext *);
  2819 static const VMFunction CheckOverRecursedInfo =
  2820     FunctionInfo<ReportOverRecursedFn>(CheckOverRecursed);
  2822 bool
  2823 CodeGenerator::visitCheckOverRecursedFailure(CheckOverRecursedFailure *ool)
  2825     // The OOL path is hit if the recursion depth has been exceeded.
  2826     // Throw an InternalError for over-recursion.
  2828     // LFunctionEnvironment can appear before LCheckOverRecursed, so we have
  2829     // to save all live registers to avoid crashes if CheckOverRecursed triggers
  2830     // a GC.
  2831     saveLive(ool->lir());
  2833     if (!callVM(CheckOverRecursedInfo, ool->lir()))
  2834         return false;
  2836     restoreLive(ool->lir());
  2837     masm.jump(ool->rejoin());
  2838     return true;
  2841 // Out-of-line path to report over-recursed error and fail.
  2842 class CheckOverRecursedFailurePar : public OutOfLineCodeBase<CodeGenerator>
  2844     LCheckOverRecursedPar *lir_;
  2846   public:
  2847     CheckOverRecursedFailurePar(LCheckOverRecursedPar *lir)
  2848       : lir_(lir)
  2849     { }
  2851     bool accept(CodeGenerator *codegen) {
  2852         return codegen->visitCheckOverRecursedFailurePar(this);
  2855     LCheckOverRecursedPar *lir() const {
  2856         return lir_;
  2858 };
  2860 bool
  2861 CodeGenerator::visitCheckOverRecursedPar(LCheckOverRecursedPar *lir)
  2863     // See above: unlike visitCheckOverRecursed(), this code runs in
  2864     // parallel mode and hence uses the jitStackLimit from the current
  2865     // thread state.  Also, we must check the interrupt flags because
  2866     // on interrupt or abort, only the stack limit for the main thread
  2867     // is reset, not the worker threads.  See comment in vm/ForkJoin.h
  2868     // for more details.
  2870     Register cxReg = ToRegister(lir->forkJoinContext());
  2871     Register tempReg = ToRegister(lir->getTempReg());
  2873     masm.loadPtr(Address(cxReg, offsetof(ForkJoinContext, perThreadData)), tempReg);
  2874     masm.loadPtr(Address(tempReg, offsetof(PerThreadData, jitStackLimit)), tempReg);
  2876     // Conditional forward (unlikely) branch to failure.
  2877     CheckOverRecursedFailurePar *ool = new(alloc()) CheckOverRecursedFailurePar(lir);
  2878     if (!addOutOfLineCode(ool))
  2879         return false;
  2880     masm.branchPtr(Assembler::BelowOrEqual, StackPointer, tempReg, ool->entry());
  2881     masm.checkInterruptFlagPar(tempReg, ool->entry());
  2882     masm.bind(ool->rejoin());
  2884     return true;
  2887 bool
  2888 CodeGenerator::visitCheckOverRecursedFailurePar(CheckOverRecursedFailurePar *ool)
  2890     OutOfLinePropagateAbortPar *bail = oolPropagateAbortPar(ool->lir());
  2891     if (!bail)
  2892         return false;
  2894     // Avoid saving/restoring the temp register since we will put the
  2895     // ReturnReg into it below and we don't want to clobber that
  2896     // during PopRegsInMask():
  2897     LCheckOverRecursedPar *lir = ool->lir();
  2898     Register tempReg = ToRegister(lir->getTempReg());
  2899     RegisterSet saveSet(lir->safepoint()->liveRegs());
  2900     saveSet.takeUnchecked(tempReg);
  2902     masm.PushRegsInMask(saveSet);
  2903     masm.movePtr(ToRegister(lir->forkJoinContext()), CallTempReg0);
  2904     masm.setupUnalignedABICall(1, CallTempReg1);
  2905     masm.passABIArg(CallTempReg0);
  2906     masm.callWithABI(JS_FUNC_TO_DATA_PTR(void *, CheckOverRecursedPar));
  2907     masm.movePtr(ReturnReg, tempReg);
  2908     masm.PopRegsInMask(saveSet);
  2909     masm.branchIfFalseBool(tempReg, bail->entry());
  2910     masm.jump(ool->rejoin());
  2912     return true;
  2915 // Out-of-line path to report over-recursed error and fail.
  2916 class OutOfLineInterruptCheckPar : public OutOfLineCodeBase<CodeGenerator>
  2918   public:
  2919     LInterruptCheckPar *const lir;
  2921     OutOfLineInterruptCheckPar(LInterruptCheckPar *lir)
  2922       : lir(lir)
  2923     { }
  2925     bool accept(CodeGenerator *codegen) {
  2926         return codegen->visitOutOfLineInterruptCheckPar(this);
  2928 };
  2930 bool
  2931 CodeGenerator::visitInterruptCheckPar(LInterruptCheckPar *lir)
  2933     // First check for cx->shared->interrupt_.
  2934     OutOfLineInterruptCheckPar *ool = new(alloc()) OutOfLineInterruptCheckPar(lir);
  2935     if (!addOutOfLineCode(ool))
  2936         return false;
  2938     Register tempReg = ToRegister(lir->getTempReg());
  2939     masm.checkInterruptFlagPar(tempReg, ool->entry());
  2940     masm.bind(ool->rejoin());
  2941     return true;
  2944 bool
  2945 CodeGenerator::visitOutOfLineInterruptCheckPar(OutOfLineInterruptCheckPar *ool)
  2947     OutOfLinePropagateAbortPar *bail = oolPropagateAbortPar(ool->lir);
  2948     if (!bail)
  2949         return false;
  2951     // Avoid saving/restoring the temp register since we will put the
  2952     // ReturnReg into it below and we don't want to clobber that
  2953     // during PopRegsInMask():
  2954     LInterruptCheckPar *lir = ool->lir;
  2955     Register tempReg = ToRegister(lir->getTempReg());
  2956     RegisterSet saveSet(lir->safepoint()->liveRegs());
  2957     saveSet.takeUnchecked(tempReg);
  2959     masm.PushRegsInMask(saveSet);
  2960     masm.movePtr(ToRegister(ool->lir->forkJoinContext()), CallTempReg0);
  2961     masm.setupUnalignedABICall(1, CallTempReg1);
  2962     masm.passABIArg(CallTempReg0);
  2963     masm.callWithABI(JS_FUNC_TO_DATA_PTR(void *, InterruptCheckPar));
  2964     masm.movePtr(ReturnReg, tempReg);
  2965     masm.PopRegsInMask(saveSet);
  2966     masm.branchIfFalseBool(tempReg, bail->entry());
  2967     masm.jump(ool->rejoin());
  2969     return true;
  2972 IonScriptCounts *
  2973 CodeGenerator::maybeCreateScriptCounts()
  2975     // If scripts are being profiled, create a new IonScriptCounts and attach
  2976     // it to the script. This must be done on the main thread.
  2977     JSContext *cx = GetIonContext()->cx;
  2978     if (!cx || !cx->runtime()->profilingScripts)
  2979         return nullptr;
  2981     CompileInfo *outerInfo = &gen->info();
  2982     JSScript *script = outerInfo->script();
  2983     if (!script)
  2984         return nullptr;
  2986     if (!script->hasScriptCounts() && !script->initScriptCounts(cx))
  2987         return nullptr;
  2989     IonScriptCounts *counts = js_new<IonScriptCounts>();
  2990     if (!counts || !counts->init(graph.numBlocks())) {
  2991         js_delete(counts);
  2992         return nullptr;
  2995     for (size_t i = 0; i < graph.numBlocks(); i++) {
  2996         MBasicBlock *block = graph.getBlock(i)->mir();
  2998         // Find a PC offset in the outermost script to use. If this block
  2999         // is from an inlined script, find a location in the outer script
  3000         // to associate information about the inlining with.
  3001         MResumePoint *resume = block->entryResumePoint();
  3002         while (resume->caller())
  3003             resume = resume->caller();
  3005         uint32_t offset = script->pcToOffset(resume->pc());
  3006         if (!counts->block(i).init(block->id(), offset, block->numSuccessors())) {
  3007             js_delete(counts);
  3008             return nullptr;
  3011         for (size_t j = 0; j < block->numSuccessors(); j++)
  3012             counts->block(i).setSuccessor(j, block->getSuccessor(j)->id());
  3015     script->addIonCounts(counts);
  3016     return counts;
  3019 // Structure for managing the state tracked for a block by script counters.
  3020 struct ScriptCountBlockState
  3022     IonBlockCounts &block;
  3023     MacroAssembler &masm;
  3025     Sprinter printer;
  3027   public:
  3028     ScriptCountBlockState(IonBlockCounts *block, MacroAssembler *masm)
  3029       : block(*block), masm(*masm), printer(GetIonContext()->cx)
  3033     bool init()
  3035         if (!printer.init())
  3036             return false;
  3038         // Bump the hit count for the block at the start. This code is not
  3039         // included in either the text for the block or the instruction byte
  3040         // counts.
  3041         masm.inc64(AbsoluteAddress(block.addressOfHitCount()));
  3043         // Collect human readable assembly for the code generated in the block.
  3044         masm.setPrinter(&printer);
  3046         return true;
  3049     void visitInstruction(LInstruction *ins)
  3051         // Prefix stream of assembly instructions with their LIR instruction
  3052         // name and any associated high level info.
  3053         if (const char *extra = ins->extraName())
  3054             printer.printf("[%s:%s]\n", ins->opName(), extra);
  3055         else
  3056             printer.printf("[%s]\n", ins->opName());
  3059     ~ScriptCountBlockState()
  3061         masm.setPrinter(nullptr);
  3063         block.setCode(printer.string());
  3065 };
  3067 #ifdef DEBUG
  3068 bool
  3069 CodeGenerator::branchIfInvalidated(Register temp, Label *invalidated)
  3071     CodeOffsetLabel label = masm.movWithPatch(ImmWord(uintptr_t(-1)), temp);
  3072     if (!ionScriptLabels_.append(label))
  3073         return false;
  3075     // If IonScript::refcount != 0, the script has been invalidated.
  3076     masm.branch32(Assembler::NotEqual,
  3077                   Address(temp, IonScript::offsetOfRefcount()),
  3078                   Imm32(0),
  3079                   invalidated);
  3080     return true;
  3083 bool
  3084 CodeGenerator::emitObjectOrStringResultChecks(LInstruction *lir, MDefinition *mir)
  3086     if (lir->numDefs() == 0)
  3087         return true;
  3089     JS_ASSERT(lir->numDefs() == 1);
  3090     Register output = ToRegister(lir->getDef(0));
  3092     GeneralRegisterSet regs(GeneralRegisterSet::All());
  3093     regs.take(output);
  3095     Register temp = regs.takeAny();
  3096     masm.push(temp);
  3098     // Don't check if the script has been invalidated. In that case invalid
  3099     // types are expected (until we reach the OsiPoint and bailout).
  3100     Label done;
  3101     if (!branchIfInvalidated(temp, &done))
  3102         return false;
  3104     if (mir->type() == MIRType_Object &&
  3105         mir->resultTypeSet() &&
  3106         !mir->resultTypeSet()->unknownObject())
  3108         // We have a result TypeSet, assert this object is in it.
  3109         Label miss, ok;
  3110         if (mir->resultTypeSet()->getObjectCount() > 0)
  3111             masm.guardObjectType(output, mir->resultTypeSet(), temp, &miss);
  3112         else
  3113             masm.jump(&miss);
  3114         masm.jump(&ok);
  3116         masm.bind(&miss);
  3117         masm.assumeUnreachable("MIR instruction returned object with unexpected type");
  3119         masm.bind(&ok);
  3122     // Check that we have a valid GC pointer.
  3123     if (gen->info().executionMode() != ParallelExecution) {
  3124         saveVolatile();
  3125         masm.setupUnalignedABICall(2, temp);
  3126         masm.loadJSContext(temp);
  3127         masm.passABIArg(temp);
  3128         masm.passABIArg(output);
  3129         masm.callWithABINoProfiling(mir->type() == MIRType_Object
  3130                                     ? JS_FUNC_TO_DATA_PTR(void *, AssertValidObjectPtr)
  3131                                     : JS_FUNC_TO_DATA_PTR(void *, AssertValidStringPtr));
  3132         restoreVolatile();
  3135     masm.bind(&done);
  3136     masm.pop(temp);
  3137     return true;
  3140 bool
  3141 CodeGenerator::emitValueResultChecks(LInstruction *lir, MDefinition *mir)
  3143     if (lir->numDefs() == 0)
  3144         return true;
  3146     JS_ASSERT(lir->numDefs() == BOX_PIECES);
  3147     if (!lir->getDef(0)->output()->isRegister())
  3148         return true;
  3150     ValueOperand output = ToOutValue(lir);
  3152     GeneralRegisterSet regs(GeneralRegisterSet::All());
  3153     regs.take(output);
  3155     Register temp1 = regs.takeAny();
  3156     Register temp2 = regs.takeAny();
  3157     masm.push(temp1);
  3158     masm.push(temp2);
  3160     // Don't check if the script has been invalidated. In that case invalid
  3161     // types are expected (until we reach the OsiPoint and bailout).
  3162     Label done;
  3163     if (!branchIfInvalidated(temp1, &done))
  3164         return false;
  3166     if (mir->resultTypeSet() && !mir->resultTypeSet()->unknown()) {
  3167         // We have a result TypeSet, assert this value is in it.
  3168         Label miss, ok;
  3169         masm.guardTypeSet(output, mir->resultTypeSet(), temp1, &miss);
  3170         masm.jump(&ok);
  3172         masm.bind(&miss);
  3173         masm.assumeUnreachable("MIR instruction returned value with unexpected type");
  3175         masm.bind(&ok);
  3178     // Check that we have a valid GC pointer.
  3179     if (gen->info().executionMode() != ParallelExecution) {
  3180         saveVolatile();
  3182         masm.pushValue(output);
  3183         masm.movePtr(StackPointer, temp1);
  3185         masm.setupUnalignedABICall(2, temp2);
  3186         masm.loadJSContext(temp2);
  3187         masm.passABIArg(temp2);
  3188         masm.passABIArg(temp1);
  3189         masm.callWithABINoProfiling(JS_FUNC_TO_DATA_PTR(void *, AssertValidValue));
  3190         masm.popValue(output);
  3191         restoreVolatile();
  3194     masm.bind(&done);
  3195     masm.pop(temp2);
  3196     masm.pop(temp1);
  3197     return true;
  3200 bool
  3201 CodeGenerator::emitDebugResultChecks(LInstruction *ins)
  3203     // In debug builds, check that LIR instructions return valid values.
  3205     MDefinition *mir = ins->mirRaw();
  3206     if (!mir)
  3207         return true;
  3209     switch (mir->type()) {
  3210       case MIRType_Object:
  3211       case MIRType_String:
  3212         return emitObjectOrStringResultChecks(ins, mir);
  3213       case MIRType_Value:
  3214         return emitValueResultChecks(ins, mir);
  3215       default:
  3216         return true;
  3219 #endif
  3221 bool
  3222 CodeGenerator::generateBody()
  3224     IonScriptCounts *counts = maybeCreateScriptCounts();
  3226 #if defined(JS_ION_PERF)
  3227     PerfSpewer *perfSpewer = &perfSpewer_;
  3228     if (gen->compilingAsmJS())
  3229         perfSpewer = &gen->perfSpewer();
  3230 #endif
  3232     for (size_t i = 0; i < graph.numBlocks(); i++) {
  3233         current = graph.getBlock(i);
  3234         masm.bind(current->label());
  3236         mozilla::Maybe<ScriptCountBlockState> blockCounts;
  3237         if (counts) {
  3238             blockCounts.construct(&counts->block(i), &masm);
  3239             if (!blockCounts.ref().init())
  3240                 return false;
  3243 #if defined(JS_ION_PERF)
  3244         perfSpewer->startBasicBlock(current->mir(), masm);
  3245 #endif
  3247         for (LInstructionIterator iter = current->begin(); iter != current->end(); iter++) {
  3248             IonSpewStart(IonSpew_Codegen, "instruction %s", iter->opName());
  3249 #ifdef DEBUG
  3250             if (const char *extra = iter->extraName())
  3251                 IonSpewCont(IonSpew_Codegen, ":%s", extra);
  3252 #endif
  3253             IonSpewFin(IonSpew_Codegen);
  3255             if (counts)
  3256                 blockCounts.ref().visitInstruction(*iter);
  3258             if (iter->safepoint() && pushedArgumentSlots_.length()) {
  3259                 if (!markArgumentSlots(iter->safepoint()))
  3260                     return false;
  3263 #ifdef CHECK_OSIPOINT_REGISTERS
  3264             if (iter->safepoint())
  3265                 resetOsiPointRegs(iter->safepoint());
  3266 #endif
  3268             if (!callTraceLIR(i, *iter))
  3269                 return false;
  3271             if (!iter->accept(this))
  3272                 return false;
  3274 #ifdef DEBUG
  3275             if (!emitDebugResultChecks(*iter))
  3276                 return false;
  3277 #endif
  3279         if (masm.oom())
  3280             return false;
  3282 #if defined(JS_ION_PERF)
  3283         perfSpewer->endBasicBlock(masm);
  3284 #endif
  3287     JS_ASSERT(pushedArgumentSlots_.empty());
  3288     return true;
  3291 // Out-of-line object allocation for LNewArray.
  3292 class OutOfLineNewArray : public OutOfLineCodeBase<CodeGenerator>
  3294     LNewArray *lir_;
  3296   public:
  3297     OutOfLineNewArray(LNewArray *lir)
  3298       : lir_(lir)
  3299     { }
  3301     bool accept(CodeGenerator *codegen) {
  3302         return codegen->visitOutOfLineNewArray(this);
  3305     LNewArray *lir() const {
  3306         return lir_;
  3308 };
  3310 typedef JSObject *(*NewInitArrayFn)(JSContext *, uint32_t, types::TypeObject *);
  3311 static const VMFunction NewInitArrayInfo =
  3312     FunctionInfo<NewInitArrayFn>(NewInitArray);
  3314 bool
  3315 CodeGenerator::visitNewArrayCallVM(LNewArray *lir)
  3317     JS_ASSERT(gen->info().executionMode() == SequentialExecution);
  3319     Register objReg = ToRegister(lir->output());
  3321     JS_ASSERT(!lir->isCall());
  3322     saveLive(lir);
  3324     JSObject *templateObject = lir->mir()->templateObject();
  3325     types::TypeObject *type =
  3326         templateObject->hasSingletonType() ? nullptr : templateObject->type();
  3328     pushArg(ImmGCPtr(type));
  3329     pushArg(Imm32(lir->mir()->count()));
  3331     if (!callVM(NewInitArrayInfo, lir))
  3332         return false;
  3334     if (ReturnReg != objReg)
  3335         masm.movePtr(ReturnReg, objReg);
  3337     restoreLive(lir);
  3339     return true;
  3342 typedef JSObject *(*NewDerivedTypedObjectFn)(JSContext *,
  3343                                              HandleObject type,
  3344                                              HandleObject owner,
  3345                                              int32_t offset);
  3346 static const VMFunction CreateDerivedTypedObjInfo =
  3347     FunctionInfo<NewDerivedTypedObjectFn>(CreateDerivedTypedObj);
  3349 bool
  3350 CodeGenerator::visitNewDerivedTypedObject(LNewDerivedTypedObject *lir)
  3352     // Not yet made safe for par exec:
  3353     JS_ASSERT(gen->info().executionMode() == SequentialExecution);
  3355     pushArg(ToRegister(lir->offset()));
  3356     pushArg(ToRegister(lir->owner()));
  3357     pushArg(ToRegister(lir->type()));
  3358     return callVM(CreateDerivedTypedObjInfo, lir);
  3361 bool
  3362 CodeGenerator::visitNewSlots(LNewSlots *lir)
  3364     Register temp1 = ToRegister(lir->temp1());
  3365     Register temp2 = ToRegister(lir->temp2());
  3366     Register temp3 = ToRegister(lir->temp3());
  3367     Register output = ToRegister(lir->output());
  3369     masm.mov(ImmPtr(GetIonContext()->runtime), temp1);
  3370     masm.mov(ImmWord(lir->mir()->nslots()), temp2);
  3372     masm.setupUnalignedABICall(2, temp3);
  3373     masm.passABIArg(temp1);
  3374     masm.passABIArg(temp2);
  3375     masm.callWithABI(JS_FUNC_TO_DATA_PTR(void *, NewSlots));
  3377     if (!bailoutTestPtr(Assembler::Zero, output, output, lir->snapshot()))
  3378         return false;
  3380     return true;
  3383 bool CodeGenerator::visitAtan2D(LAtan2D *lir)
  3385     Register temp = ToRegister(lir->temp());
  3386     FloatRegister y = ToFloatRegister(lir->y());
  3387     FloatRegister x = ToFloatRegister(lir->x());
  3389     masm.setupUnalignedABICall(2, temp);
  3390     masm.passABIArg(y, MoveOp::DOUBLE);
  3391     masm.passABIArg(x, MoveOp::DOUBLE);
  3392     masm.callWithABI(JS_FUNC_TO_DATA_PTR(void *, ecmaAtan2), MoveOp::DOUBLE);
  3394     JS_ASSERT(ToFloatRegister(lir->output()) == ReturnFloatReg);
  3395     return true;
  3398 bool CodeGenerator::visitHypot(LHypot *lir)
  3400     Register temp = ToRegister(lir->temp());
  3401     FloatRegister x = ToFloatRegister(lir->x());
  3402     FloatRegister y = ToFloatRegister(lir->y());
  3404     masm.setupUnalignedABICall(2, temp);
  3405     masm.passABIArg(x, MoveOp::DOUBLE);
  3406     masm.passABIArg(y, MoveOp::DOUBLE);
  3407     masm.callWithABI(JS_FUNC_TO_DATA_PTR(void *, ecmaHypot), MoveOp::DOUBLE);
  3409     JS_ASSERT(ToFloatRegister(lir->output()) == ReturnFloatReg);
  3410     return true;
  3413 bool
  3414 CodeGenerator::visitNewArray(LNewArray *lir)
  3416     JS_ASSERT(gen->info().executionMode() == SequentialExecution);
  3417     Register objReg = ToRegister(lir->output());
  3418     Register tempReg = ToRegister(lir->temp());
  3419     JSObject *templateObject = lir->mir()->templateObject();
  3420     DebugOnly<uint32_t> count = lir->mir()->count();
  3422     JS_ASSERT(count < JSObject::NELEMENTS_LIMIT);
  3424     if (lir->mir()->shouldUseVM())
  3425         return visitNewArrayCallVM(lir);
  3427     OutOfLineNewArray *ool = new(alloc()) OutOfLineNewArray(lir);
  3428     if (!addOutOfLineCode(ool))
  3429         return false;
  3431     masm.newGCThing(objReg, tempReg, templateObject, ool->entry(), lir->mir()->initialHeap());
  3432     masm.initGCThing(objReg, tempReg, templateObject);
  3434     masm.bind(ool->rejoin());
  3435     return true;
  3438 bool
  3439 CodeGenerator::visitOutOfLineNewArray(OutOfLineNewArray *ool)
  3441     if (!visitNewArrayCallVM(ool->lir()))
  3442         return false;
  3443     masm.jump(ool->rejoin());
  3444     return true;
  3447 // Out-of-line object allocation for JSOP_NEWOBJECT.
  3448 class OutOfLineNewObject : public OutOfLineCodeBase<CodeGenerator>
  3450     LNewObject *lir_;
  3452   public:
  3453     OutOfLineNewObject(LNewObject *lir)
  3454       : lir_(lir)
  3455     { }
  3457     bool accept(CodeGenerator *codegen) {
  3458         return codegen->visitOutOfLineNewObject(this);
  3461     LNewObject *lir() const {
  3462         return lir_;
  3464 };
  3466 typedef JSObject *(*NewInitObjectFn)(JSContext *, HandleObject);
  3467 static const VMFunction NewInitObjectInfo = FunctionInfo<NewInitObjectFn>(NewInitObject);
  3469 typedef JSObject *(*NewInitObjectWithClassPrototypeFn)(JSContext *, HandleObject);
  3470 static const VMFunction NewInitObjectWithClassPrototypeInfo =
  3471     FunctionInfo<NewInitObjectWithClassPrototypeFn>(NewInitObjectWithClassPrototype);
  3473 bool
  3474 CodeGenerator::visitNewObjectVMCall(LNewObject *lir)
  3476     JS_ASSERT(gen->info().executionMode() == SequentialExecution);
  3478     Register objReg = ToRegister(lir->output());
  3480     JS_ASSERT(!lir->isCall());
  3481     saveLive(lir);
  3483     pushArg(ImmGCPtr(lir->mir()->templateObject()));
  3485     // If we're making a new object with a class prototype (that is, an object
  3486     // that derives its class from its prototype instead of being
  3487     // JSObject::class_'d) from self-hosted code, we need a different init
  3488     // function.
  3489     if (lir->mir()->templateObjectIsClassPrototype()) {
  3490         if (!callVM(NewInitObjectWithClassPrototypeInfo, lir))
  3491             return false;
  3492     } else if (!callVM(NewInitObjectInfo, lir)) {
  3493         return false;
  3496     if (ReturnReg != objReg)
  3497         masm.movePtr(ReturnReg, objReg);
  3499     restoreLive(lir);
  3500     return true;
  3503 bool
  3504 CodeGenerator::visitNewObject(LNewObject *lir)
  3506     JS_ASSERT(gen->info().executionMode() == SequentialExecution);
  3507     Register objReg = ToRegister(lir->output());
  3508     Register tempReg = ToRegister(lir->temp());
  3509     JSObject *templateObject = lir->mir()->templateObject();
  3511     if (lir->mir()->shouldUseVM())
  3512         return visitNewObjectVMCall(lir);
  3514     OutOfLineNewObject *ool = new(alloc()) OutOfLineNewObject(lir);
  3515     if (!addOutOfLineCode(ool))
  3516         return false;
  3518     masm.newGCThing(objReg, tempReg, templateObject, ool->entry(), lir->mir()->initialHeap());
  3519     masm.initGCThing(objReg, tempReg, templateObject);
  3521     masm.bind(ool->rejoin());
  3522     return true;
  3525 bool
  3526 CodeGenerator::visitOutOfLineNewObject(OutOfLineNewObject *ool)
  3528     if (!visitNewObjectVMCall(ool->lir()))
  3529         return false;
  3530     masm.jump(ool->rejoin());
  3531     return true;
  3534 typedef js::DeclEnvObject *(*NewDeclEnvObjectFn)(JSContext *, HandleFunction, gc::InitialHeap);
  3535 static const VMFunction NewDeclEnvObjectInfo =
  3536     FunctionInfo<NewDeclEnvObjectFn>(DeclEnvObject::createTemplateObject);
  3538 bool
  3539 CodeGenerator::visitNewDeclEnvObject(LNewDeclEnvObject *lir)
  3541     Register objReg = ToRegister(lir->output());
  3542     Register tempReg = ToRegister(lir->temp());
  3543     JSObject *templateObj = lir->mir()->templateObj();
  3544     CompileInfo &info = lir->mir()->block()->info();
  3546     // If we have a template object, we can inline call object creation.
  3547     OutOfLineCode *ool = oolCallVM(NewDeclEnvObjectInfo, lir,
  3548                                    (ArgList(), ImmGCPtr(info.funMaybeLazy()),
  3549                                     Imm32(gc::DefaultHeap)),
  3550                                    StoreRegisterTo(objReg));
  3551     if (!ool)
  3552         return false;
  3554     masm.newGCThing(objReg, tempReg, templateObj, ool->entry(), gc::DefaultHeap);
  3555     masm.initGCThing(objReg, tempReg, templateObj);
  3556     masm.bind(ool->rejoin());
  3557     return true;
  3560 typedef JSObject *(*NewCallObjectFn)(JSContext *, HandleShape, HandleTypeObject, HeapSlot *);
  3561 static const VMFunction NewCallObjectInfo =
  3562     FunctionInfo<NewCallObjectFn>(NewCallObject);
  3564 bool
  3565 CodeGenerator::visitNewCallObject(LNewCallObject *lir)
  3567     Register objReg = ToRegister(lir->output());
  3568     Register tempReg = ToRegister(lir->temp());
  3570     JSObject *templateObj = lir->mir()->templateObject();
  3572     OutOfLineCode *ool;
  3573     if (lir->slots()->isRegister()) {
  3574         ool = oolCallVM(NewCallObjectInfo, lir,
  3575                         (ArgList(), ImmGCPtr(templateObj->lastProperty()),
  3576                                     ImmGCPtr(templateObj->type()),
  3577                                     ToRegister(lir->slots())),
  3578                         StoreRegisterTo(objReg));
  3579     } else {
  3580         ool = oolCallVM(NewCallObjectInfo, lir,
  3581                         (ArgList(), ImmGCPtr(templateObj->lastProperty()),
  3582                                     ImmGCPtr(templateObj->type()),
  3583                                     ImmPtr(nullptr)),
  3584                         StoreRegisterTo(objReg));
  3586     if (!ool)
  3587         return false;
  3589 #ifdef JSGC_GENERATIONAL
  3590     if (templateObj->hasDynamicSlots()) {
  3591         // Slot initialization is unbarriered in this case, so we must either
  3592         // allocate in the nursery or bail if that is not possible.
  3593         masm.jump(ool->entry());
  3594     } else
  3595 #endif
  3597         // Inline call object creation, using the OOL path only for tricky cases.
  3598         masm.newGCThing(objReg, tempReg, templateObj, ool->entry(), gc::DefaultHeap);
  3599         masm.initGCThing(objReg, tempReg, templateObj);
  3602     if (lir->slots()->isRegister())
  3603         masm.storePtr(ToRegister(lir->slots()), Address(objReg, JSObject::offsetOfSlots()));
  3605     masm.bind(ool->rejoin());
  3606     return true;
  3609 typedef JSObject *(*NewSingletonCallObjectFn)(JSContext *, HandleShape, HeapSlot *);
  3610 static const VMFunction NewSingletonCallObjectInfo =
  3611     FunctionInfo<NewSingletonCallObjectFn>(NewSingletonCallObject);
  3613 bool
  3614 CodeGenerator::visitNewSingletonCallObject(LNewSingletonCallObject *lir)
  3616     Register objReg = ToRegister(lir->output());
  3618     JSObject *templateObj = lir->mir()->templateObject();
  3620     OutOfLineCode *ool;
  3621     if (lir->slots()->isRegister()) {
  3622         ool = oolCallVM(NewSingletonCallObjectInfo, lir,
  3623                         (ArgList(), ImmGCPtr(templateObj->lastProperty()),
  3624                                     ToRegister(lir->slots())),
  3625                         StoreRegisterTo(objReg));
  3626     } else {
  3627         ool = oolCallVM(NewSingletonCallObjectInfo, lir,
  3628                         (ArgList(), ImmGCPtr(templateObj->lastProperty()),
  3629                                     ImmPtr(nullptr)),
  3630                         StoreRegisterTo(objReg));
  3632     if (!ool)
  3633         return false;
  3635     // Objects can only be given singleton types in VM calls.  We make the call
  3636     // out of line to not bloat inline code, even if (naively) this seems like
  3637     // extra work.
  3638     masm.jump(ool->entry());
  3639     masm.bind(ool->rejoin());
  3641     return true;
  3644 bool
  3645 CodeGenerator::visitNewCallObjectPar(LNewCallObjectPar *lir)
  3647     Register resultReg = ToRegister(lir->output());
  3648     Register cxReg = ToRegister(lir->forkJoinContext());
  3649     Register tempReg1 = ToRegister(lir->getTemp0());
  3650     Register tempReg2 = ToRegister(lir->getTemp1());
  3651     JSObject *templateObj = lir->mir()->templateObj();
  3653     emitAllocateGCThingPar(lir, resultReg, cxReg, tempReg1, tempReg2, templateObj);
  3655     // NB: !lir->slots()->isRegister() implies that there is no slots
  3656     // array at all, and the memory is already zeroed when copying
  3657     // from the template object
  3659     if (lir->slots()->isRegister()) {
  3660         Register slotsReg = ToRegister(lir->slots());
  3661         JS_ASSERT(slotsReg != resultReg);
  3662         masm.storePtr(slotsReg, Address(resultReg, JSObject::offsetOfSlots()));
  3665     return true;
  3668 bool
  3669 CodeGenerator::visitNewDenseArrayPar(LNewDenseArrayPar *lir)
  3671     Register cxReg = ToRegister(lir->forkJoinContext());
  3672     Register lengthReg = ToRegister(lir->length());
  3673     Register tempReg0 = ToRegister(lir->getTemp0());
  3674     Register tempReg1 = ToRegister(lir->getTemp1());
  3675     Register tempReg2 = ToRegister(lir->getTemp2());
  3676     JSObject *templateObj = lir->mir()->templateObject();
  3678     // Allocate the array into tempReg2.  Don't use resultReg because it
  3679     // may alias cxReg etc.
  3680     emitAllocateGCThingPar(lir, tempReg2, cxReg, tempReg0, tempReg1, templateObj);
  3682     // Invoke a C helper to allocate the elements.  For convenience,
  3683     // this helper also returns the array back to us, or nullptr, which
  3684     // obviates the need to preserve the register across the call.  In
  3685     // reality, we should probably just have the C helper also
  3686     // *allocate* the array, but that would require that it initialize
  3687     // the various fields of the object, and I didn't want to
  3688     // duplicate the code in initGCThing() that already does such an
  3689     // admirable job.
  3690     masm.setupUnalignedABICall(3, tempReg0);
  3691     masm.passABIArg(cxReg);
  3692     masm.passABIArg(tempReg2);
  3693     masm.passABIArg(lengthReg);
  3694     masm.callWithABI(JS_FUNC_TO_DATA_PTR(void *, ExtendArrayPar));
  3696     Register resultReg = ToRegister(lir->output());
  3697     JS_ASSERT(resultReg == ReturnReg);
  3698     OutOfLineAbortPar *bail = oolAbortPar(ParallelBailoutOutOfMemory, lir);
  3699     if (!bail)
  3700         return false;
  3701     masm.branchTestPtr(Assembler::Zero, resultReg, resultReg, bail->entry());
  3703     return true;
  3706 typedef JSObject *(*NewStringObjectFn)(JSContext *, HandleString);
  3707 static const VMFunction NewStringObjectInfo = FunctionInfo<NewStringObjectFn>(NewStringObject);
  3709 bool
  3710 CodeGenerator::visitNewStringObject(LNewStringObject *lir)
  3712     Register input = ToRegister(lir->input());
  3713     Register output = ToRegister(lir->output());
  3714     Register temp = ToRegister(lir->temp());
  3716     StringObject *templateObj = lir->mir()->templateObj();
  3718     OutOfLineCode *ool = oolCallVM(NewStringObjectInfo, lir, (ArgList(), input),
  3719                                    StoreRegisterTo(output));
  3720     if (!ool)
  3721         return false;
  3723     masm.newGCThing(output, temp, templateObj, ool->entry(), gc::DefaultHeap);
  3724     masm.initGCThing(output, temp, templateObj);
  3726     masm.loadStringLength(input, temp);
  3728     masm.storeValue(JSVAL_TYPE_STRING, input, Address(output, StringObject::offsetOfPrimitiveValue()));
  3729     masm.storeValue(JSVAL_TYPE_INT32, temp, Address(output, StringObject::offsetOfLength()));
  3731     masm.bind(ool->rejoin());
  3732     return true;
  3735 bool
  3736 CodeGenerator::visitNewPar(LNewPar *lir)
  3738     Register objReg = ToRegister(lir->output());
  3739     Register cxReg = ToRegister(lir->forkJoinContext());
  3740     Register tempReg1 = ToRegister(lir->getTemp0());
  3741     Register tempReg2 = ToRegister(lir->getTemp1());
  3742     JSObject *templateObject = lir->mir()->templateObject();
  3743     emitAllocateGCThingPar(lir, objReg, cxReg, tempReg1, tempReg2, templateObject);
  3744     return true;
  3747 class OutOfLineNewGCThingPar : public OutOfLineCodeBase<CodeGenerator>
  3749 public:
  3750     LInstruction *lir;
  3751     gc::AllocKind allocKind;
  3752     Register objReg;
  3753     Register cxReg;
  3755     OutOfLineNewGCThingPar(LInstruction *lir, gc::AllocKind allocKind, Register objReg,
  3756                            Register cxReg)
  3757       : lir(lir), allocKind(allocKind), objReg(objReg), cxReg(cxReg)
  3758     {}
  3760     bool accept(CodeGenerator *codegen) {
  3761         return codegen->visitOutOfLineNewGCThingPar(this);
  3763 };
  3765 bool
  3766 CodeGenerator::emitAllocateGCThingPar(LInstruction *lir, Register objReg, Register cxReg,
  3767                                       Register tempReg1, Register tempReg2, JSObject *templateObj)
  3769     gc::AllocKind allocKind = templateObj->tenuredGetAllocKind();
  3770     OutOfLineNewGCThingPar *ool = new(alloc()) OutOfLineNewGCThingPar(lir, allocKind, objReg, cxReg);
  3771     if (!ool || !addOutOfLineCode(ool))
  3772         return false;
  3774     masm.newGCThingPar(objReg, cxReg, tempReg1, tempReg2, templateObj, ool->entry());
  3775     masm.bind(ool->rejoin());
  3776     masm.initGCThing(objReg, tempReg1, templateObj);
  3777     return true;
  3780 bool
  3781 CodeGenerator::visitOutOfLineNewGCThingPar(OutOfLineNewGCThingPar *ool)
  3783     // As a fallback for allocation in par. exec. mode, we invoke the
  3784     // C helper NewGCThingPar(), which calls into the GC code.  If it
  3785     // returns nullptr, we bail.  If returns non-nullptr, we rejoin the
  3786     // original instruction.
  3787     Register out = ool->objReg;
  3789     saveVolatile(out);
  3790     masm.setupUnalignedABICall(2, out);
  3791     masm.passABIArg(ool->cxReg);
  3792     masm.move32(Imm32(ool->allocKind), out);
  3793     masm.passABIArg(out);
  3794     masm.callWithABI(JS_FUNC_TO_DATA_PTR(void *, NewGCThingPar));
  3795     masm.storeCallResult(out);
  3796     restoreVolatile(out);
  3798     OutOfLineAbortPar *bail = oolAbortPar(ParallelBailoutOutOfMemory, ool->lir);
  3799     if (!bail)
  3800         return false;
  3801     masm.branchTestPtr(Assembler::Zero, out, out, bail->entry());
  3802     masm.jump(ool->rejoin());
  3803     return true;
  3806 bool
  3807 CodeGenerator::visitAbortPar(LAbortPar *lir)
  3809     OutOfLineAbortPar *bail = oolAbortPar(ParallelBailoutUnsupported, lir);
  3810     if (!bail)
  3811         return false;
  3812     masm.jump(bail->entry());
  3813     return true;
  3816 typedef bool(*InitElemFn)(JSContext *cx, HandleObject obj,
  3817                           HandleValue id, HandleValue value);
  3818 static const VMFunction InitElemInfo =
  3819     FunctionInfo<InitElemFn>(InitElemOperation);
  3821 bool
  3822 CodeGenerator::visitInitElem(LInitElem *lir)
  3824     Register objReg = ToRegister(lir->getObject());
  3826     pushArg(ToValue(lir, LInitElem::ValueIndex));
  3827     pushArg(ToValue(lir, LInitElem::IdIndex));
  3828     pushArg(objReg);
  3830     return callVM(InitElemInfo, lir);
  3833 typedef bool (*InitElemGetterSetterFn)(JSContext *, jsbytecode *, HandleObject, HandleValue,
  3834                                        HandleObject);
  3835 static const VMFunction InitElemGetterSetterInfo =
  3836     FunctionInfo<InitElemGetterSetterFn>(InitGetterSetterOperation);
  3838 bool
  3839 CodeGenerator::visitInitElemGetterSetter(LInitElemGetterSetter *lir)
  3841     Register obj = ToRegister(lir->object());
  3842     Register value = ToRegister(lir->value());
  3844     pushArg(value);
  3845     pushArg(ToValue(lir, LInitElemGetterSetter::IdIndex));
  3846     pushArg(obj);
  3847     pushArg(ImmPtr(lir->mir()->resumePoint()->pc()));
  3849     return callVM(InitElemGetterSetterInfo, lir);
  3852 typedef bool(*MutatePrototypeFn)(JSContext *cx, HandleObject obj, HandleValue value);
  3853 static const VMFunction MutatePrototypeInfo =
  3854     FunctionInfo<MutatePrototypeFn>(MutatePrototype);
  3856 bool
  3857 CodeGenerator::visitMutateProto(LMutateProto *lir)
  3859     Register objReg = ToRegister(lir->getObject());
  3861     pushArg(ToValue(lir, LMutateProto::ValueIndex));
  3862     pushArg(objReg);
  3864     return callVM(MutatePrototypeInfo, lir);
  3867 typedef bool(*InitPropFn)(JSContext *cx, HandleObject obj,
  3868                           HandlePropertyName name, HandleValue value);
  3869 static const VMFunction InitPropInfo =
  3870     FunctionInfo<InitPropFn>(InitProp);
  3872 bool
  3873 CodeGenerator::visitInitProp(LInitProp *lir)
  3875     Register objReg = ToRegister(lir->getObject());
  3877     pushArg(ToValue(lir, LInitProp::ValueIndex));
  3878     pushArg(ImmGCPtr(lir->mir()->propertyName()));
  3879     pushArg(objReg);
  3881     return callVM(InitPropInfo, lir);
  3884 typedef bool(*InitPropGetterSetterFn)(JSContext *, jsbytecode *, HandleObject, HandlePropertyName,
  3885                                       HandleObject);
  3886 static const VMFunction InitPropGetterSetterInfo =
  3887     FunctionInfo<InitPropGetterSetterFn>(InitGetterSetterOperation);
  3889 bool
  3890 CodeGenerator::visitInitPropGetterSetter(LInitPropGetterSetter *lir)
  3892     Register obj = ToRegister(lir->object());
  3893     Register value = ToRegister(lir->value());
  3895     pushArg(value);
  3896     pushArg(ImmGCPtr(lir->mir()->name()));
  3897     pushArg(obj);
  3898     pushArg(ImmPtr(lir->mir()->resumePoint()->pc()));
  3900     return callVM(InitPropGetterSetterInfo, lir);
  3903 typedef bool (*CreateThisFn)(JSContext *cx, HandleObject callee, MutableHandleValue rval);
  3904 static const VMFunction CreateThisInfoCodeGen = FunctionInfo<CreateThisFn>(CreateThis);
  3906 bool
  3907 CodeGenerator::visitCreateThis(LCreateThis *lir)
  3909     const LAllocation *callee = lir->getCallee();
  3911     if (callee->isConstant())
  3912         pushArg(ImmGCPtr(&callee->toConstant()->toObject()));
  3913     else
  3914         pushArg(ToRegister(callee));
  3916     return callVM(CreateThisInfoCodeGen, lir);
  3919 static JSObject *
  3920 CreateThisForFunctionWithProtoWrapper(JSContext *cx, js::HandleObject callee, JSObject *proto)
  3922     return CreateThisForFunctionWithProto(cx, callee, proto);
  3925 typedef JSObject *(*CreateThisWithProtoFn)(JSContext *cx, HandleObject callee, JSObject *proto);
  3926 static const VMFunction CreateThisWithProtoInfo =
  3927 FunctionInfo<CreateThisWithProtoFn>(CreateThisForFunctionWithProtoWrapper);
  3929 bool
  3930 CodeGenerator::visitCreateThisWithProto(LCreateThisWithProto *lir)
  3932     const LAllocation *callee = lir->getCallee();
  3933     const LAllocation *proto = lir->getPrototype();
  3935     if (proto->isConstant())
  3936         pushArg(ImmGCPtr(&proto->toConstant()->toObject()));
  3937     else
  3938         pushArg(ToRegister(proto));
  3940     if (callee->isConstant())
  3941         pushArg(ImmGCPtr(&callee->toConstant()->toObject()));
  3942     else
  3943         pushArg(ToRegister(callee));
  3945     return callVM(CreateThisWithProtoInfo, lir);
  3948 typedef JSObject *(*NewGCObjectFn)(JSContext *cx, gc::AllocKind allocKind,
  3949                                    gc::InitialHeap initialHeap);
  3950 static const VMFunction NewGCObjectInfo =
  3951     FunctionInfo<NewGCObjectFn>(js::jit::NewGCObject);
  3953 bool
  3954 CodeGenerator::visitCreateThisWithTemplate(LCreateThisWithTemplate *lir)
  3956     JSObject *templateObject = lir->mir()->templateObject();
  3957     gc::AllocKind allocKind = templateObject->tenuredGetAllocKind();
  3958     gc::InitialHeap initialHeap = lir->mir()->initialHeap();
  3959     Register objReg = ToRegister(lir->output());
  3960     Register tempReg = ToRegister(lir->temp());
  3962     OutOfLineCode *ool = oolCallVM(NewGCObjectInfo, lir,
  3963                                    (ArgList(), Imm32(allocKind), Imm32(initialHeap)),
  3964                                    StoreRegisterTo(objReg));
  3965     if (!ool)
  3966         return false;
  3968     // Allocate. If the FreeList is empty, call to VM, which may GC.
  3969     masm.newGCThing(objReg, tempReg, templateObject, ool->entry(), lir->mir()->initialHeap());
  3971     // Initialize based on the templateObject.
  3972     masm.bind(ool->rejoin());
  3973     masm.initGCThing(objReg, tempReg, templateObject);
  3975     return true;
  3978 typedef JSObject *(*NewIonArgumentsObjectFn)(JSContext *cx, IonJSFrameLayout *frame, HandleObject);
  3979 static const VMFunction NewIonArgumentsObjectInfo =
  3980     FunctionInfo<NewIonArgumentsObjectFn>((NewIonArgumentsObjectFn) ArgumentsObject::createForIon);
  3982 bool
  3983 CodeGenerator::visitCreateArgumentsObject(LCreateArgumentsObject *lir)
  3985     // This should be getting constructed in the first block only, and not any OSR entry blocks.
  3986     JS_ASSERT(lir->mir()->block()->id() == 0);
  3988     const LAllocation *callObj = lir->getCallObject();
  3989     Register temp = ToRegister(lir->getTemp(0));
  3991     masm.movePtr(StackPointer, temp);
  3992     masm.addPtr(Imm32(frameSize()), temp);
  3994     pushArg(ToRegister(callObj));
  3995     pushArg(temp);
  3996     return callVM(NewIonArgumentsObjectInfo, lir);
  3999 bool
  4000 CodeGenerator::visitGetArgumentsObjectArg(LGetArgumentsObjectArg *lir)
  4002     Register temp = ToRegister(lir->getTemp(0));
  4003     Register argsObj = ToRegister(lir->getArgsObject());
  4004     ValueOperand out = ToOutValue(lir);
  4006     masm.loadPrivate(Address(argsObj, ArgumentsObject::getDataSlotOffset()), temp);
  4007     Address argAddr(temp, ArgumentsData::offsetOfArgs() + lir->mir()->argno() * sizeof(Value));
  4008     masm.loadValue(argAddr, out);
  4009 #ifdef DEBUG
  4010     Label success;
  4011     masm.branchTestMagic(Assembler::NotEqual, out, &success);
  4012     masm.assumeUnreachable("Result from ArgumentObject shouldn't be JSVAL_TYPE_MAGIC.");
  4013     masm.bind(&success);
  4014 #endif
  4015     return true;
  4018 bool
  4019 CodeGenerator::visitSetArgumentsObjectArg(LSetArgumentsObjectArg *lir)
  4021     Register temp = ToRegister(lir->getTemp(0));
  4022     Register argsObj = ToRegister(lir->getArgsObject());
  4023     ValueOperand value = ToValue(lir, LSetArgumentsObjectArg::ValueIndex);
  4025     masm.loadPrivate(Address(argsObj, ArgumentsObject::getDataSlotOffset()), temp);
  4026     Address argAddr(temp, ArgumentsData::offsetOfArgs() + lir->mir()->argno() * sizeof(Value));
  4027     emitPreBarrier(argAddr, MIRType_Value);
  4028 #ifdef DEBUG
  4029     Label success;
  4030     masm.branchTestMagic(Assembler::NotEqual, argAddr, &success);
  4031     masm.assumeUnreachable("Result in ArgumentObject shouldn't be JSVAL_TYPE_MAGIC.");
  4032     masm.bind(&success);
  4033 #endif
  4034     masm.storeValue(value, argAddr);
  4035     return true;
  4038 bool
  4039 CodeGenerator::visitReturnFromCtor(LReturnFromCtor *lir)
  4041     ValueOperand value = ToValue(lir, LReturnFromCtor::ValueIndex);
  4042     Register obj = ToRegister(lir->getObject());
  4043     Register output = ToRegister(lir->output());
  4045     Label valueIsObject, end;
  4047     masm.branchTestObject(Assembler::Equal, value, &valueIsObject);
  4049     // Value is not an object. Return that other object.
  4050     masm.movePtr(obj, output);
  4051     masm.jump(&end);
  4053     // Value is an object. Return unbox(Value).
  4054     masm.bind(&valueIsObject);
  4055     Register payload = masm.extractObject(value, output);
  4056     if (payload != output)
  4057         masm.movePtr(payload, output);
  4059     masm.bind(&end);
  4060     return true;
  4063 typedef JSObject *(*BoxNonStrictThisFn)(JSContext *, HandleValue);
  4064 static const VMFunction BoxNonStrictThisInfo = FunctionInfo<BoxNonStrictThisFn>(BoxNonStrictThis);
  4066 bool
  4067 CodeGenerator::visitComputeThis(LComputeThis *lir)
  4069     ValueOperand value = ToValue(lir, LComputeThis::ValueIndex);
  4070     Register output = ToRegister(lir->output());
  4072     OutOfLineCode *ool = oolCallVM(BoxNonStrictThisInfo, lir, (ArgList(), value),
  4073                                    StoreRegisterTo(output));
  4074     if (!ool)
  4075         return false;
  4077     masm.branchTestObject(Assembler::NotEqual, value, ool->entry());
  4078     masm.unboxObject(value, output);
  4080     masm.bind(ool->rejoin());
  4081     return true;
  4084 bool
  4085 CodeGenerator::visitLoadArrowThis(LLoadArrowThis *lir)
  4087     Register callee = ToRegister(lir->callee());
  4088     ValueOperand output = ToOutValue(lir);
  4089     masm.loadValue(Address(callee, FunctionExtended::offsetOfArrowThisSlot()), output);
  4090     return true;
  4093 bool
  4094 CodeGenerator::visitArrayLength(LArrayLength *lir)
  4096     Address length(ToRegister(lir->elements()), ObjectElements::offsetOfLength());
  4097     masm.load32(length, ToRegister(lir->output()));
  4098     return true;
  4101 bool
  4102 CodeGenerator::visitSetArrayLength(LSetArrayLength *lir)
  4104     Address length(ToRegister(lir->elements()), ObjectElements::offsetOfLength());
  4105     Int32Key newLength = ToInt32Key(lir->index());
  4107     masm.bumpKey(&newLength, 1);
  4108     masm.storeKey(newLength, length);
  4109     // Restore register value if it is used/captured after.
  4110     masm.bumpKey(&newLength, -1);
  4111     return true;
  4114 bool
  4115 CodeGenerator::visitTypedArrayLength(LTypedArrayLength *lir)
  4117     Register obj = ToRegister(lir->object());
  4118     Register out = ToRegister(lir->output());
  4119     masm.unboxInt32(Address(obj, TypedArrayObject::lengthOffset()), out);
  4120     return true;
  4123 bool
  4124 CodeGenerator::visitTypedArrayElements(LTypedArrayElements *lir)
  4126     Register obj = ToRegister(lir->object());
  4127     Register out = ToRegister(lir->output());
  4128     masm.loadPtr(Address(obj, TypedArrayObject::dataOffset()), out);
  4129     return true;
  4132 bool
  4133 CodeGenerator::visitNeuterCheck(LNeuterCheck *lir)
  4135     Register obj = ToRegister(lir->object());
  4136     Register temp = ToRegister(lir->temp());
  4138     masm.extractObject(Address(obj, TypedObject::offsetOfOwnerSlot()), temp);
  4139     masm.unboxInt32(Address(temp, ArrayBufferObject::flagsOffset()), temp);
  4141     Imm32 flag(ArrayBufferObject::neuteredFlag());
  4142     if (!bailoutTest32(Assembler::NonZero, temp, flag, lir->snapshot()))
  4143         return false;
  4145     return true;
  4148 bool
  4149 CodeGenerator::visitTypedObjectElements(LTypedObjectElements *lir)
  4151     Register obj = ToRegister(lir->object());
  4152     Register out = ToRegister(lir->output());
  4153     masm.loadPtr(Address(obj, TypedObject::offsetOfDataSlot()), out);
  4154     return true;
  4157 bool
  4158 CodeGenerator::visitSetTypedObjectOffset(LSetTypedObjectOffset *lir)
  4160     Register object = ToRegister(lir->object());
  4161     Register offset = ToRegister(lir->offset());
  4162     Register temp0 = ToRegister(lir->temp0());
  4164     // `offset` is an absolute offset into the base buffer. One way
  4165     // to implement this instruction would be load the base address
  4166     // from the buffer and add `offset`. But that'd be an extra load.
  4167     // We can instead load the current base pointer and current
  4168     // offset, compute the difference with `offset`, and then adjust
  4169     // the current base pointer. This is two loads but to adjacent
  4170     // fields in the same object, which should come in the same cache
  4171     // line.
  4172     //
  4173     // The C code I would probably write is the following:
  4174     //
  4175     // void SetTypedObjectOffset(TypedObject *obj, int32_t offset) {
  4176     //     int32_t temp0 = obj->byteOffset;
  4177     //     obj->pointer = obj->pointer - temp0 + offset;
  4178     //     obj->byteOffset = offset;
  4179     // }
  4180     //
  4181     // But what we actually compute is more like this, because it
  4182     // saves us a temporary to do it this way:
  4183     //
  4184     // void SetTypedObjectOffset(TypedObject *obj, int32_t offset) {
  4185     //     int32_t temp0 = obj->byteOffset;
  4186     //     obj->pointer = obj->pointer - (temp0 - offset);
  4187     //     obj->byteOffset = offset;
  4188     // }
  4190     // temp0 = typedObj->byteOffset;
  4191     masm.unboxInt32(Address(object, TypedObject::offsetOfByteOffsetSlot()), temp0);
  4193     // temp0 -= offset;
  4194     masm.subPtr(offset, temp0);
  4196     // obj->pointer -= temp0;
  4197     masm.subPtr(temp0, Address(object, TypedObject::offsetOfDataSlot()));
  4199     // obj->byteOffset = offset;
  4200     masm.storeValue(JSVAL_TYPE_INT32, offset,
  4201                     Address(object, TypedObject::offsetOfByteOffsetSlot()));
  4203     return true;
  4206 bool
  4207 CodeGenerator::visitStringLength(LStringLength *lir)
  4209     Register input = ToRegister(lir->string());
  4210     Register output = ToRegister(lir->output());
  4212     masm.loadStringLength(input, output);
  4213     return true;
  4216 bool
  4217 CodeGenerator::visitMinMaxI(LMinMaxI *ins)
  4219     Register first = ToRegister(ins->first());
  4220     Register output = ToRegister(ins->output());
  4222     JS_ASSERT(first == output);
  4224     Label done;
  4225     Assembler::Condition cond = ins->mir()->isMax()
  4226                                 ? Assembler::GreaterThan
  4227                                 : Assembler::LessThan;
  4229     if (ins->second()->isConstant()) {
  4230         masm.branch32(cond, first, Imm32(ToInt32(ins->second())), &done);
  4231         masm.move32(Imm32(ToInt32(ins->second())), output);
  4232     } else {
  4233         masm.branch32(cond, first, ToRegister(ins->second()), &done);
  4234         masm.move32(ToRegister(ins->second()), output);
  4237     masm.bind(&done);
  4238     return true;
  4241 bool
  4242 CodeGenerator::visitAbsI(LAbsI *ins)
  4244     Register input = ToRegister(ins->input());
  4245     Label positive;
  4247     JS_ASSERT(input == ToRegister(ins->output()));
  4248     masm.branchTest32(Assembler::NotSigned, input, input, &positive);
  4249     masm.neg32(input);
  4250 #ifdef JS_CODEGEN_MIPS
  4251     LSnapshot *snapshot = ins->snapshot();
  4252     if (snapshot && !bailoutCmp32(Assembler::Equal, input, Imm32(INT32_MIN), snapshot))
  4253         return false;
  4254 #else
  4255     if (ins->snapshot() && !bailoutIf(Assembler::Overflow, ins->snapshot()))
  4256         return false;
  4257 #endif
  4258     masm.bind(&positive);
  4260     return true;
  4263 bool
  4264 CodeGenerator::visitPowI(LPowI *ins)
  4266     FloatRegister value = ToFloatRegister(ins->value());
  4267     Register power = ToRegister(ins->power());
  4268     Register temp = ToRegister(ins->temp());
  4270     JS_ASSERT(power != temp);
  4272     // In all implementations, setupUnalignedABICall() relinquishes use of
  4273     // its scratch register. We can therefore save an input register by
  4274     // reusing the scratch register to pass constants to callWithABI.
  4275     masm.setupUnalignedABICall(2, temp);
  4276     masm.passABIArg(value, MoveOp::DOUBLE);
  4277     masm.passABIArg(power);
  4279     masm.callWithABI(JS_FUNC_TO_DATA_PTR(void *, js::powi), MoveOp::DOUBLE);
  4280     JS_ASSERT(ToFloatRegister(ins->output()) == ReturnFloatReg);
  4282     return true;
  4285 bool
  4286 CodeGenerator::visitPowD(LPowD *ins)
  4288     FloatRegister value = ToFloatRegister(ins->value());
  4289     FloatRegister power = ToFloatRegister(ins->power());
  4290     Register temp = ToRegister(ins->temp());
  4292     masm.setupUnalignedABICall(2, temp);
  4293     masm.passABIArg(value, MoveOp::DOUBLE);
  4294     masm.passABIArg(power, MoveOp::DOUBLE);
  4295     masm.callWithABI(JS_FUNC_TO_DATA_PTR(void *, ecmaPow), MoveOp::DOUBLE);
  4297     JS_ASSERT(ToFloatRegister(ins->output()) == ReturnFloatReg);
  4298     return true;
  4301 bool
  4302 CodeGenerator::visitRandom(LRandom *ins)
  4304     Register temp = ToRegister(ins->temp());
  4305     Register temp2 = ToRegister(ins->temp2());
  4307     masm.loadJSContext(temp);
  4309     masm.setupUnalignedABICall(1, temp2);
  4310     masm.passABIArg(temp);
  4311     masm.callWithABI(JS_FUNC_TO_DATA_PTR(void *, math_random_no_outparam), MoveOp::DOUBLE);
  4313     JS_ASSERT(ToFloatRegister(ins->output()) == ReturnFloatReg);
  4314     return true;
  4317 bool
  4318 CodeGenerator::visitMathFunctionD(LMathFunctionD *ins)
  4320     Register temp = ToRegister(ins->temp());
  4321     FloatRegister input = ToFloatRegister(ins->input());
  4322     JS_ASSERT(ToFloatRegister(ins->output()) == ReturnFloatReg);
  4324     const MathCache *mathCache = ins->mir()->cache();
  4326     masm.setupUnalignedABICall(mathCache ? 2 : 1, temp);
  4327     if (mathCache) {
  4328         masm.movePtr(ImmPtr(mathCache), temp);
  4329         masm.passABIArg(temp);
  4331     masm.passABIArg(input, MoveOp::DOUBLE);
  4333 #   define MAYBE_CACHED(fcn) (mathCache ? (void*)fcn ## _impl : (void*)fcn ## _uncached)
  4335     void *funptr = nullptr;
  4336     switch (ins->mir()->function()) {
  4337       case MMathFunction::Log:
  4338         funptr = JS_FUNC_TO_DATA_PTR(void *, MAYBE_CACHED(js::math_log));
  4339         break;
  4340       case MMathFunction::Sin:
  4341         funptr = JS_FUNC_TO_DATA_PTR(void *, MAYBE_CACHED(js::math_sin));
  4342         break;
  4343       case MMathFunction::Cos:
  4344         funptr = JS_FUNC_TO_DATA_PTR(void *, MAYBE_CACHED(js::math_cos));
  4345         break;
  4346       case MMathFunction::Exp:
  4347         funptr = JS_FUNC_TO_DATA_PTR(void *, MAYBE_CACHED(js::math_exp));
  4348         break;
  4349       case MMathFunction::Tan:
  4350         funptr = JS_FUNC_TO_DATA_PTR(void *, MAYBE_CACHED(js::math_tan));
  4351         break;
  4352       case MMathFunction::ATan:
  4353         funptr = JS_FUNC_TO_DATA_PTR(void *, MAYBE_CACHED(js::math_atan));
  4354         break;
  4355       case MMathFunction::ASin:
  4356         funptr = JS_FUNC_TO_DATA_PTR(void *, MAYBE_CACHED(js::math_asin));
  4357         break;
  4358       case MMathFunction::ACos:
  4359         funptr = JS_FUNC_TO_DATA_PTR(void *, MAYBE_CACHED(js::math_acos));
  4360         break;
  4361       case MMathFunction::Log10:
  4362         funptr = JS_FUNC_TO_DATA_PTR(void *, MAYBE_CACHED(js::math_log10));
  4363         break;
  4364       case MMathFunction::Log2:
  4365         funptr = JS_FUNC_TO_DATA_PTR(void *, MAYBE_CACHED(js::math_log2));
  4366         break;
  4367       case MMathFunction::Log1P:
  4368         funptr = JS_FUNC_TO_DATA_PTR(void *, MAYBE_CACHED(js::math_log1p));
  4369         break;
  4370       case MMathFunction::ExpM1:
  4371         funptr = JS_FUNC_TO_DATA_PTR(void *, MAYBE_CACHED(js::math_expm1));
  4372         break;
  4373       case MMathFunction::CosH:
  4374         funptr = JS_FUNC_TO_DATA_PTR(void *, MAYBE_CACHED(js::math_cosh));
  4375         break;
  4376       case MMathFunction::SinH:
  4377         funptr = JS_FUNC_TO_DATA_PTR(void *, MAYBE_CACHED(js::math_sinh));
  4378         break;
  4379       case MMathFunction::TanH:
  4380         funptr = JS_FUNC_TO_DATA_PTR(void *, MAYBE_CACHED(js::math_tanh));
  4381         break;
  4382       case MMathFunction::ACosH:
  4383         funptr = JS_FUNC_TO_DATA_PTR(void *, MAYBE_CACHED(js::math_acosh));
  4384         break;
  4385       case MMathFunction::ASinH:
  4386         funptr = JS_FUNC_TO_DATA_PTR(void *, MAYBE_CACHED(js::math_asinh));
  4387         break;
  4388       case MMathFunction::ATanH:
  4389         funptr = JS_FUNC_TO_DATA_PTR(void *, MAYBE_CACHED(js::math_atanh));
  4390         break;
  4391       case MMathFunction::Sign:
  4392         funptr = JS_FUNC_TO_DATA_PTR(void *, MAYBE_CACHED(js::math_sign));
  4393         break;
  4394       case MMathFunction::Trunc:
  4395         funptr = JS_FUNC_TO_DATA_PTR(void *, MAYBE_CACHED(js::math_trunc));
  4396         break;
  4397       case MMathFunction::Cbrt:
  4398         funptr = JS_FUNC_TO_DATA_PTR(void *, MAYBE_CACHED(js::math_cbrt));
  4399         break;
  4400       case MMathFunction::Floor:
  4401         funptr = JS_FUNC_TO_DATA_PTR(void *, js::math_floor_impl);
  4402         break;
  4403       case MMathFunction::Ceil:
  4404         funptr = JS_FUNC_TO_DATA_PTR(void *, js::math_ceil_impl);
  4405         break;
  4406       case MMathFunction::Round:
  4407         funptr = JS_FUNC_TO_DATA_PTR(void *, js::math_round_impl);
  4408         break;
  4409       default:
  4410         MOZ_ASSUME_UNREACHABLE("Unknown math function");
  4413 #   undef MAYBE_CACHED
  4415     masm.callWithABI(funptr, MoveOp::DOUBLE);
  4416     return true;
  4419 bool
  4420 CodeGenerator::visitMathFunctionF(LMathFunctionF *ins)
  4422     Register temp = ToRegister(ins->temp());
  4423     FloatRegister input = ToFloatRegister(ins->input());
  4424     JS_ASSERT(ToFloatRegister(ins->output()) == ReturnFloatReg);
  4426     masm.setupUnalignedABICall(1, temp);
  4427     masm.passABIArg(input, MoveOp::FLOAT32);
  4429     void *funptr = nullptr;
  4430     switch (ins->mir()->function()) {
  4431       case MMathFunction::Floor: funptr = JS_FUNC_TO_DATA_PTR(void *, floorf);           break;
  4432       case MMathFunction::Round: funptr = JS_FUNC_TO_DATA_PTR(void *, math_roundf_impl); break;
  4433       case MMathFunction::Ceil:  funptr = JS_FUNC_TO_DATA_PTR(void *, ceilf);            break;
  4434       default:
  4435         MOZ_ASSUME_UNREACHABLE("Unknown or unsupported float32 math function");
  4438     masm.callWithABI(funptr, MoveOp::FLOAT32);
  4439     return true;
  4442 bool
  4443 CodeGenerator::visitModD(LModD *ins)
  4445     FloatRegister lhs = ToFloatRegister(ins->lhs());
  4446     FloatRegister rhs = ToFloatRegister(ins->rhs());
  4447     Register temp = ToRegister(ins->temp());
  4449     JS_ASSERT(ToFloatRegister(ins->output()) == ReturnFloatReg);
  4451     masm.setupUnalignedABICall(2, temp);
  4452     masm.passABIArg(lhs, MoveOp::DOUBLE);
  4453     masm.passABIArg(rhs, MoveOp::DOUBLE);
  4455     if (gen->compilingAsmJS())
  4456         masm.callWithABI(AsmJSImm_ModD, MoveOp::DOUBLE);
  4457     else
  4458         masm.callWithABI(JS_FUNC_TO_DATA_PTR(void *, NumberMod), MoveOp::DOUBLE);
  4459     return true;
  4462 typedef bool (*BinaryFn)(JSContext *, MutableHandleValue, MutableHandleValue, MutableHandleValue);
  4463 typedef bool (*BinaryParFn)(ForkJoinContext *, HandleValue, HandleValue, MutableHandleValue);
  4465 static const VMFunction AddInfo = FunctionInfo<BinaryFn>(js::AddValues);
  4466 static const VMFunction SubInfo = FunctionInfo<BinaryFn>(js::SubValues);
  4467 static const VMFunction MulInfo = FunctionInfo<BinaryFn>(js::MulValues);
  4468 static const VMFunction DivInfo = FunctionInfo<BinaryFn>(js::DivValues);
  4469 static const VMFunction ModInfo = FunctionInfo<BinaryFn>(js::ModValues);
  4470 static const VMFunctionsModal UrshInfo = VMFunctionsModal(
  4471     FunctionInfo<BinaryFn>(js::UrshValues),
  4472     FunctionInfo<BinaryParFn>(UrshValuesPar));
  4474 bool
  4475 CodeGenerator::visitBinaryV(LBinaryV *lir)
  4477     pushArg(ToValue(lir, LBinaryV::RhsInput));
  4478     pushArg(ToValue(lir, LBinaryV::LhsInput));
  4480     switch (lir->jsop()) {
  4481       case JSOP_ADD:
  4482         return callVM(AddInfo, lir);
  4484       case JSOP_SUB:
  4485         return callVM(SubInfo, lir);
  4487       case JSOP_MUL:
  4488         return callVM(MulInfo, lir);
  4490       case JSOP_DIV:
  4491         return callVM(DivInfo, lir);
  4493       case JSOP_MOD:
  4494         return callVM(ModInfo, lir);
  4496       case JSOP_URSH:
  4497         return callVM(UrshInfo, lir);
  4499       default:
  4500         MOZ_ASSUME_UNREACHABLE("Unexpected binary op");
  4504 typedef bool (*StringCompareFn)(JSContext *, HandleString, HandleString, bool *);
  4505 typedef bool (*StringCompareParFn)(ForkJoinContext *, HandleString, HandleString, bool *);
  4506 static const VMFunctionsModal StringsEqualInfo = VMFunctionsModal(
  4507     FunctionInfo<StringCompareFn>(jit::StringsEqual<true>),
  4508     FunctionInfo<StringCompareParFn>(jit::StringsEqualPar));
  4509 static const VMFunctionsModal StringsNotEqualInfo = VMFunctionsModal(
  4510     FunctionInfo<StringCompareFn>(jit::StringsEqual<false>),
  4511     FunctionInfo<StringCompareParFn>(jit::StringsUnequalPar));
  4513 bool
  4514 CodeGenerator::emitCompareS(LInstruction *lir, JSOp op, Register left, Register right,
  4515                             Register output, Register temp)
  4517     JS_ASSERT(lir->isCompareS() || lir->isCompareStrictS());
  4519     OutOfLineCode *ool = nullptr;
  4521     if (op == JSOP_EQ || op == JSOP_STRICTEQ) {
  4522         ool = oolCallVM(StringsEqualInfo, lir, (ArgList(), left, right),  StoreRegisterTo(output));
  4523     } else {
  4524         JS_ASSERT(op == JSOP_NE || op == JSOP_STRICTNE);
  4525         ool = oolCallVM(StringsNotEqualInfo, lir, (ArgList(), left, right), StoreRegisterTo(output));
  4527     if (!ool)
  4528         return false;
  4530     masm.compareStrings(op, left, right, output, temp, ool->entry());
  4532     masm.bind(ool->rejoin());
  4533     return true;
  4536 bool
  4537 CodeGenerator::visitCompareStrictS(LCompareStrictS *lir)
  4539     JSOp op = lir->mir()->jsop();
  4540     JS_ASSERT(op == JSOP_STRICTEQ || op == JSOP_STRICTNE);
  4542     const ValueOperand leftV = ToValue(lir, LCompareStrictS::Lhs);
  4543     Register right = ToRegister(lir->right());
  4544     Register output = ToRegister(lir->output());
  4545     Register temp = ToRegister(lir->temp());
  4546     Register tempToUnbox = ToTempUnboxRegister(lir->tempToUnbox());
  4548     Label string, done;
  4550     masm.branchTestString(Assembler::Equal, leftV, &string);
  4551     masm.move32(Imm32(op == JSOP_STRICTNE), output);
  4552     masm.jump(&done);
  4554     masm.bind(&string);
  4555     Register left = masm.extractString(leftV, tempToUnbox);
  4556     if (!emitCompareS(lir, op, left, right, output, temp))
  4557         return false;
  4559     masm.bind(&done);
  4561     return true;
  4564 bool
  4565 CodeGenerator::visitCompareS(LCompareS *lir)
  4567     JSOp op = lir->mir()->jsop();
  4568     Register left = ToRegister(lir->left());
  4569     Register right = ToRegister(lir->right());
  4570     Register output = ToRegister(lir->output());
  4571     Register temp = ToRegister(lir->temp());
  4573     return emitCompareS(lir, op, left, right, output, temp);
  4576 typedef bool (*CompareFn)(JSContext *, MutableHandleValue, MutableHandleValue, bool *);
  4577 typedef bool (*CompareParFn)(ForkJoinContext *, MutableHandleValue, MutableHandleValue, bool *);
  4578 static const VMFunctionsModal EqInfo = VMFunctionsModal(
  4579     FunctionInfo<CompareFn>(jit::LooselyEqual<true>),
  4580     FunctionInfo<CompareParFn>(jit::LooselyEqualPar));
  4581 static const VMFunctionsModal NeInfo = VMFunctionsModal(
  4582     FunctionInfo<CompareFn>(jit::LooselyEqual<false>),
  4583     FunctionInfo<CompareParFn>(jit::LooselyUnequalPar));
  4584 static const VMFunctionsModal StrictEqInfo = VMFunctionsModal(
  4585     FunctionInfo<CompareFn>(jit::StrictlyEqual<true>),
  4586     FunctionInfo<CompareParFn>(jit::StrictlyEqualPar));
  4587 static const VMFunctionsModal StrictNeInfo = VMFunctionsModal(
  4588     FunctionInfo<CompareFn>(jit::StrictlyEqual<false>),
  4589     FunctionInfo<CompareParFn>(jit::StrictlyUnequalPar));
  4590 static const VMFunctionsModal LtInfo = VMFunctionsModal(
  4591     FunctionInfo<CompareFn>(jit::LessThan),
  4592     FunctionInfo<CompareParFn>(jit::LessThanPar));
  4593 static const VMFunctionsModal LeInfo = VMFunctionsModal(
  4594     FunctionInfo<CompareFn>(jit::LessThanOrEqual),
  4595     FunctionInfo<CompareParFn>(jit::LessThanOrEqualPar));
  4596 static const VMFunctionsModal GtInfo = VMFunctionsModal(
  4597     FunctionInfo<CompareFn>(jit::GreaterThan),
  4598     FunctionInfo<CompareParFn>(jit::GreaterThanPar));
  4599 static const VMFunctionsModal GeInfo = VMFunctionsModal(
  4600     FunctionInfo<CompareFn>(jit::GreaterThanOrEqual),
  4601     FunctionInfo<CompareParFn>(jit::GreaterThanOrEqualPar));
  4603 bool
  4604 CodeGenerator::visitCompareVM(LCompareVM *lir)
  4606     pushArg(ToValue(lir, LBinaryV::RhsInput));
  4607     pushArg(ToValue(lir, LBinaryV::LhsInput));
  4609     switch (lir->mir()->jsop()) {
  4610       case JSOP_EQ:
  4611         return callVM(EqInfo, lir);
  4613       case JSOP_NE:
  4614         return callVM(NeInfo, lir);
  4616       case JSOP_STRICTEQ:
  4617         return callVM(StrictEqInfo, lir);
  4619       case JSOP_STRICTNE:
  4620         return callVM(StrictNeInfo, lir);
  4622       case JSOP_LT:
  4623         return callVM(LtInfo, lir);
  4625       case JSOP_LE:
  4626         return callVM(LeInfo, lir);
  4628       case JSOP_GT:
  4629         return callVM(GtInfo, lir);
  4631       case JSOP_GE:
  4632         return callVM(GeInfo, lir);
  4634       default:
  4635         MOZ_ASSUME_UNREACHABLE("Unexpected compare op");
  4639 bool
  4640 CodeGenerator::visitIsNullOrLikeUndefined(LIsNullOrLikeUndefined *lir)
  4642     JSOp op = lir->mir()->jsop();
  4643     MCompare::CompareType compareType = lir->mir()->compareType();
  4644     JS_ASSERT(compareType == MCompare::Compare_Undefined ||
  4645               compareType == MCompare::Compare_Null);
  4647     const ValueOperand value = ToValue(lir, LIsNullOrLikeUndefined::Value);
  4648     Register output = ToRegister(lir->output());
  4650     if (op == JSOP_EQ || op == JSOP_NE) {
  4651         MOZ_ASSERT(lir->mir()->lhs()->type() != MIRType_Object ||
  4652                    lir->mir()->operandMightEmulateUndefined(),
  4653                    "Operands which can't emulate undefined should have been folded");
  4655         OutOfLineTestObjectWithLabels *ool = nullptr;
  4656         Maybe<Label> label1, label2;
  4657         Label *nullOrLikeUndefined;
  4658         Label *notNullOrLikeUndefined;
  4659         if (lir->mir()->operandMightEmulateUndefined()) {
  4660             ool = new(alloc()) OutOfLineTestObjectWithLabels();
  4661             if (!addOutOfLineCode(ool))
  4662                 return false;
  4663             nullOrLikeUndefined = ool->label1();
  4664             notNullOrLikeUndefined = ool->label2();
  4665         } else {
  4666             label1.construct();
  4667             label2.construct();
  4668             nullOrLikeUndefined = label1.addr();
  4669             notNullOrLikeUndefined = label2.addr();
  4672         Register tag = masm.splitTagForTest(value);
  4674         masm.branchTestNull(Assembler::Equal, tag, nullOrLikeUndefined);
  4675         masm.branchTestUndefined(Assembler::Equal, tag, nullOrLikeUndefined);
  4677         if (ool) {
  4678             // Check whether it's a truthy object or a falsy object that emulates
  4679             // undefined.
  4680             masm.branchTestObject(Assembler::NotEqual, tag, notNullOrLikeUndefined);
  4682             Register objreg = masm.extractObject(value, ToTempUnboxRegister(lir->tempToUnbox()));
  4683             branchTestObjectEmulatesUndefined(objreg, nullOrLikeUndefined, notNullOrLikeUndefined,
  4684                                               ToRegister(lir->temp()), ool);
  4685             // fall through
  4688         Label done;
  4690         // It's not null or undefined, and if it's an object it doesn't
  4691         // emulate undefined, so it's not like undefined.
  4692         masm.move32(Imm32(op == JSOP_NE), output);
  4693         masm.jump(&done);
  4695         masm.bind(nullOrLikeUndefined);
  4696         masm.move32(Imm32(op == JSOP_EQ), output);
  4698         // Both branches meet here.
  4699         masm.bind(&done);
  4700         return true;
  4703     JS_ASSERT(op == JSOP_STRICTEQ || op == JSOP_STRICTNE);
  4705     Assembler::Condition cond = JSOpToCondition(compareType, op);
  4706     if (compareType == MCompare::Compare_Null)
  4707         masm.testNullSet(cond, value, output);
  4708     else
  4709         masm.testUndefinedSet(cond, value, output);
  4711     return true;
  4714 bool
  4715 CodeGenerator::visitIsNullOrLikeUndefinedAndBranch(LIsNullOrLikeUndefinedAndBranch *lir)
  4717     JSOp op = lir->cmpMir()->jsop();
  4718     MCompare::CompareType compareType = lir->cmpMir()->compareType();
  4719     JS_ASSERT(compareType == MCompare::Compare_Undefined ||
  4720               compareType == MCompare::Compare_Null);
  4722     const ValueOperand value = ToValue(lir, LIsNullOrLikeUndefinedAndBranch::Value);
  4724     if (op == JSOP_EQ || op == JSOP_NE) {
  4725         MBasicBlock *ifTrue;
  4726         MBasicBlock *ifFalse;
  4728         if (op == JSOP_EQ) {
  4729             ifTrue = lir->ifTrue();
  4730             ifFalse = lir->ifFalse();
  4731         } else {
  4732             // Swap branches.
  4733             ifTrue = lir->ifFalse();
  4734             ifFalse = lir->ifTrue();
  4735             op = JSOP_EQ;
  4738         MOZ_ASSERT(lir->cmpMir()->lhs()->type() != MIRType_Object ||
  4739                    lir->cmpMir()->operandMightEmulateUndefined(),
  4740                    "Operands which can't emulate undefined should have been folded");
  4742         OutOfLineTestObject *ool = nullptr;
  4743         if (lir->cmpMir()->operandMightEmulateUndefined()) {
  4744             ool = new(alloc()) OutOfLineTestObject();
  4745             if (!addOutOfLineCode(ool))
  4746                 return false;
  4749         Register tag = masm.splitTagForTest(value);
  4751         Label *ifTrueLabel = getJumpLabelForBranch(ifTrue);
  4752         Label *ifFalseLabel = getJumpLabelForBranch(ifFalse);
  4754         masm.branchTestNull(Assembler::Equal, tag, ifTrueLabel);
  4755         masm.branchTestUndefined(Assembler::Equal, tag, ifTrueLabel);
  4757         if (ool) {
  4758             masm.branchTestObject(Assembler::NotEqual, tag, ifFalseLabel);
  4760             // Objects that emulate undefined are loosely equal to null/undefined.
  4761             Register objreg = masm.extractObject(value, ToTempUnboxRegister(lir->tempToUnbox()));
  4762             Register scratch = ToRegister(lir->temp());
  4763             testObjectEmulatesUndefined(objreg, ifTrueLabel, ifFalseLabel, scratch, ool);
  4764         } else {
  4765             masm.jump(ifFalseLabel);
  4767         return true;
  4770     JS_ASSERT(op == JSOP_STRICTEQ || op == JSOP_STRICTNE);
  4772     Assembler::Condition cond = JSOpToCondition(compareType, op);
  4773     if (compareType == MCompare::Compare_Null)
  4774         testNullEmitBranch(cond, value, lir->ifTrue(), lir->ifFalse());
  4775     else
  4776         testUndefinedEmitBranch(cond, value, lir->ifTrue(), lir->ifFalse());
  4778     return true;
  4781 bool
  4782 CodeGenerator::visitEmulatesUndefined(LEmulatesUndefined *lir)
  4784     MOZ_ASSERT(lir->mir()->compareType() == MCompare::Compare_Undefined ||
  4785                lir->mir()->compareType() == MCompare::Compare_Null);
  4786     MOZ_ASSERT(lir->mir()->lhs()->type() == MIRType_Object);
  4787     MOZ_ASSERT(lir->mir()->operandMightEmulateUndefined(),
  4788                "If the object couldn't emulate undefined, this should have been folded.");
  4790     JSOp op = lir->mir()->jsop();
  4791     MOZ_ASSERT(op == JSOP_EQ || op == JSOP_NE, "Strict equality should have been folded");
  4793     OutOfLineTestObjectWithLabels *ool = new(alloc()) OutOfLineTestObjectWithLabels();
  4794     if (!addOutOfLineCode(ool))
  4795         return false;
  4797     Label *emulatesUndefined = ool->label1();
  4798     Label *doesntEmulateUndefined = ool->label2();
  4800     Register objreg = ToRegister(lir->input());
  4801     Register output = ToRegister(lir->output());
  4802     branchTestObjectEmulatesUndefined(objreg, emulatesUndefined, doesntEmulateUndefined,
  4803                                       output, ool);
  4805     Label done;
  4807     masm.move32(Imm32(op == JSOP_NE), output);
  4808     masm.jump(&done);
  4810     masm.bind(emulatesUndefined);
  4811     masm.move32(Imm32(op == JSOP_EQ), output);
  4812     masm.bind(&done);
  4813     return true;
  4816 bool
  4817 CodeGenerator::visitEmulatesUndefinedAndBranch(LEmulatesUndefinedAndBranch *lir)
  4819     MOZ_ASSERT(lir->cmpMir()->compareType() == MCompare::Compare_Undefined ||
  4820                lir->cmpMir()->compareType() == MCompare::Compare_Null);
  4821     MOZ_ASSERT(lir->cmpMir()->operandMightEmulateUndefined(),
  4822                "Operands which can't emulate undefined should have been folded");
  4824     JSOp op = lir->cmpMir()->jsop();
  4825     MOZ_ASSERT(op == JSOP_EQ || op == JSOP_NE, "Strict equality should have been folded");
  4827     OutOfLineTestObject *ool = new(alloc()) OutOfLineTestObject();
  4828     if (!addOutOfLineCode(ool))
  4829         return false;
  4831     Label *equal;
  4832     Label *unequal;
  4835         MBasicBlock *ifTrue;
  4836         MBasicBlock *ifFalse;
  4838         if (op == JSOP_EQ) {
  4839             ifTrue = lir->ifTrue();
  4840             ifFalse = lir->ifFalse();
  4841         } else {
  4842             // Swap branches.
  4843             ifTrue = lir->ifFalse();
  4844             ifFalse = lir->ifTrue();
  4845             op = JSOP_EQ;
  4848         equal = getJumpLabelForBranch(ifTrue);
  4849         unequal = getJumpLabelForBranch(ifFalse);
  4852     Register objreg = ToRegister(lir->input());
  4854     testObjectEmulatesUndefined(objreg, equal, unequal, ToRegister(lir->temp()), ool);
  4855     return true;
  4858 typedef JSString *(*ConcatStringsFn)(ThreadSafeContext *, HandleString, HandleString);
  4859 typedef JSString *(*ConcatStringsParFn)(ForkJoinContext *, HandleString, HandleString);
  4860 static const VMFunctionsModal ConcatStringsInfo = VMFunctionsModal(
  4861     FunctionInfo<ConcatStringsFn>(ConcatStrings<CanGC>),
  4862     FunctionInfo<ConcatStringsParFn>(ConcatStringsPar));
  4864 bool
  4865 CodeGenerator::emitConcat(LInstruction *lir, Register lhs, Register rhs, Register output)
  4867     OutOfLineCode *ool = oolCallVM(ConcatStringsInfo, lir, (ArgList(), lhs, rhs),
  4868                                    StoreRegisterTo(output));
  4869     if (!ool)
  4870         return false;
  4872     ExecutionMode mode = gen->info().executionMode();
  4873     JitCode *stringConcatStub = gen->compartment->jitCompartment()->stringConcatStub(mode);
  4874     masm.call(stringConcatStub);
  4875     masm.branchTestPtr(Assembler::Zero, output, output, ool->entry());
  4877     masm.bind(ool->rejoin());
  4878     return true;
  4881 bool
  4882 CodeGenerator::visitConcat(LConcat *lir)
  4884     Register lhs = ToRegister(lir->lhs());
  4885     Register rhs = ToRegister(lir->rhs());
  4887     Register output = ToRegister(lir->output());
  4889     JS_ASSERT(lhs == CallTempReg0);
  4890     JS_ASSERT(rhs == CallTempReg1);
  4891     JS_ASSERT(ToRegister(lir->temp1()) == CallTempReg0);
  4892     JS_ASSERT(ToRegister(lir->temp2()) == CallTempReg1);
  4893     JS_ASSERT(ToRegister(lir->temp3()) == CallTempReg2);
  4894     JS_ASSERT(ToRegister(lir->temp4()) == CallTempReg3);
  4895     JS_ASSERT(ToRegister(lir->temp5()) == CallTempReg4);
  4896     JS_ASSERT(output == CallTempReg5);
  4898     return emitConcat(lir, lhs, rhs, output);
  4901 bool
  4902 CodeGenerator::visitConcatPar(LConcatPar *lir)
  4904     DebugOnly<Register> cx = ToRegister(lir->forkJoinContext());
  4905     Register lhs = ToRegister(lir->lhs());
  4906     Register rhs = ToRegister(lir->rhs());
  4907     Register output = ToRegister(lir->output());
  4909     JS_ASSERT(lhs == CallTempReg0);
  4910     JS_ASSERT(rhs == CallTempReg1);
  4911     JS_ASSERT((Register)cx == CallTempReg4);
  4912     JS_ASSERT(ToRegister(lir->temp1()) == CallTempReg0);
  4913     JS_ASSERT(ToRegister(lir->temp2()) == CallTempReg1);
  4914     JS_ASSERT(ToRegister(lir->temp3()) == CallTempReg2);
  4915     JS_ASSERT(ToRegister(lir->temp4()) == CallTempReg3);
  4916     JS_ASSERT(output == CallTempReg5);
  4918     return emitConcat(lir, lhs, rhs, output);
  4921 static void
  4922 CopyStringChars(MacroAssembler &masm, Register to, Register from, Register len, Register scratch)
  4924     // Copy |len| jschars from |from| to |to|. Assumes len > 0 (checked below in
  4925     // debug builds), and when done |to| must point to the next available char.
  4927 #ifdef DEBUG
  4928     Label ok;
  4929     masm.branch32(Assembler::GreaterThan, len, Imm32(0), &ok);
  4930     masm.assumeUnreachable("Length should be greater than 0.");
  4931     masm.bind(&ok);
  4932 #endif
  4934     JS_STATIC_ASSERT(sizeof(jschar) == 2);
  4936     Label start;
  4937     masm.bind(&start);
  4938     masm.load16ZeroExtend(Address(from, 0), scratch);
  4939     masm.store16(scratch, Address(to, 0));
  4940     masm.addPtr(Imm32(2), from);
  4941     masm.addPtr(Imm32(2), to);
  4942     masm.branchSub32(Assembler::NonZero, Imm32(1), len, &start);
  4945 JitCode *
  4946 JitCompartment::generateStringConcatStub(JSContext *cx, ExecutionMode mode)
  4948     MacroAssembler masm(cx);
  4950     Register lhs = CallTempReg0;
  4951     Register rhs = CallTempReg1;
  4952     Register temp1 = CallTempReg2;
  4953     Register temp2 = CallTempReg3;
  4954     Register temp3 = CallTempReg4;
  4955     Register output = CallTempReg5;
  4957     // In parallel execution, we pass in the ForkJoinContext in CallTempReg4, as
  4958     // by the time we need to use the temp3 we no longer have need of the
  4959     // cx.
  4960     Register forkJoinContext = CallTempReg4;
  4962     Label failure, failurePopTemps;
  4964     // If lhs is empty, return rhs.
  4965     Label leftEmpty;
  4966     masm.loadStringLength(lhs, temp1);
  4967     masm.branchTest32(Assembler::Zero, temp1, temp1, &leftEmpty);
  4969     // If rhs is empty, return lhs.
  4970     Label rightEmpty;
  4971     masm.loadStringLength(rhs, temp2);
  4972     masm.branchTest32(Assembler::Zero, temp2, temp2, &rightEmpty);
  4974     masm.add32(temp1, temp2);
  4976     // Check if we can use a JSFatInlineString.
  4977     Label isFatInline;
  4978     masm.branch32(Assembler::BelowOrEqual, temp2, Imm32(JSFatInlineString::MAX_FAT_INLINE_LENGTH),
  4979                   &isFatInline);
  4981     // Ensure result length <= JSString::MAX_LENGTH.
  4982     masm.branch32(Assembler::Above, temp2, Imm32(JSString::MAX_LENGTH), &failure);
  4984     // Allocate a new rope.
  4985     switch (mode) {
  4986       case SequentialExecution:
  4987         masm.newGCString(output, temp3, &failure);
  4988         break;
  4989       case ParallelExecution:
  4990         masm.push(temp1);
  4991         masm.push(temp2);
  4992         masm.newGCStringPar(output, forkJoinContext, temp1, temp2, &failurePopTemps);
  4993         masm.pop(temp2);
  4994         masm.pop(temp1);
  4995         break;
  4996       default:
  4997         MOZ_ASSUME_UNREACHABLE("No such execution mode");
  5000     // Store lengthAndFlags.
  5001     JS_STATIC_ASSERT(JSString::ROPE_FLAGS == 0);
  5002     masm.lshiftPtr(Imm32(JSString::LENGTH_SHIFT), temp2);
  5003     masm.storePtr(temp2, Address(output, JSString::offsetOfLengthAndFlags()));
  5005     // Store left and right nodes.
  5006     masm.storePtr(lhs, Address(output, JSRope::offsetOfLeft()));
  5007     masm.storePtr(rhs, Address(output, JSRope::offsetOfRight()));
  5008     masm.ret();
  5010     masm.bind(&leftEmpty);
  5011     masm.mov(rhs, output);
  5012     masm.ret();
  5014     masm.bind(&rightEmpty);
  5015     masm.mov(lhs, output);
  5016     masm.ret();
  5018     masm.bind(&isFatInline);
  5020     // State: lhs length in temp1, result length in temp2.
  5022     // Ensure both strings are linear (flags != 0).
  5023     JS_STATIC_ASSERT(JSString::ROPE_FLAGS == 0);
  5024     masm.branchTestPtr(Assembler::Zero, Address(lhs, JSString::offsetOfLengthAndFlags()),
  5025                        Imm32(JSString::FLAGS_MASK), &failure);
  5026     masm.branchTestPtr(Assembler::Zero, Address(rhs, JSString::offsetOfLengthAndFlags()),
  5027                        Imm32(JSString::FLAGS_MASK), &failure);
  5029     // Allocate a JSFatInlineString.
  5030     switch (mode) {
  5031       case SequentialExecution:
  5032         masm.newGCFatInlineString(output, temp3, &failure);
  5033         break;
  5034       case ParallelExecution:
  5035         masm.push(temp1);
  5036         masm.push(temp2);
  5037         masm.newGCFatInlineStringPar(output, forkJoinContext, temp1, temp2, &failurePopTemps);
  5038         masm.pop(temp2);
  5039         masm.pop(temp1);
  5040         break;
  5041       default:
  5042         MOZ_ASSUME_UNREACHABLE("No such execution mode");
  5045     // Set lengthAndFlags.
  5046     masm.lshiftPtr(Imm32(JSString::LENGTH_SHIFT), temp2);
  5047     masm.orPtr(Imm32(JSString::FIXED_FLAGS), temp2);
  5048     masm.storePtr(temp2, Address(output, JSString::offsetOfLengthAndFlags()));
  5050     // Set chars pointer, keep in temp2 for copy loop below.
  5051     masm.computeEffectiveAddress(Address(output, JSFatInlineString::offsetOfInlineStorage()), temp2);
  5052     masm.storePtr(temp2, Address(output, JSFatInlineString::offsetOfChars()));
  5055         // We use temp3 in this block, which in parallel execution also holds
  5056         // a live ForkJoinContext pointer. If we are compiling for parallel
  5057         // execution, be sure to save and restore the ForkJoinContext.
  5058         if (mode == ParallelExecution)
  5059             masm.push(temp3);
  5061         // Copy lhs chars. Temp1 still holds the lhs length. Note that this
  5062         // advances temp2 to point to the next char. Note that this also
  5063         // repurposes the lhs register.
  5064         masm.loadPtr(Address(lhs, JSString::offsetOfChars()), lhs);
  5065         CopyStringChars(masm, temp2, lhs, temp1, temp3);
  5067         // Copy rhs chars.
  5068         masm.loadStringLength(rhs, temp1);
  5069         masm.loadPtr(Address(rhs, JSString::offsetOfChars()), rhs);
  5070         CopyStringChars(masm, temp2, rhs, temp1, temp3);
  5072         if (mode == ParallelExecution)
  5073             masm.pop(temp3);
  5076     // Null-terminate.
  5077     masm.store16(Imm32(0), Address(temp2, 0));
  5078     masm.ret();
  5080     masm.bind(&failurePopTemps);
  5081     masm.pop(temp2);
  5082     masm.pop(temp1);
  5084     masm.bind(&failure);
  5085     masm.movePtr(ImmPtr(nullptr), output);
  5086     masm.ret();
  5088     Linker linker(masm);
  5089     AutoFlushICache afc("StringConcatStub");
  5090     JitCode *code = linker.newCode<CanGC>(cx, JSC::OTHER_CODE);
  5092 #ifdef JS_ION_PERF
  5093     writePerfSpewerJitCodeProfile(code, "StringConcatStub");
  5094 #endif
  5096     return code;
  5099 typedef bool (*CharCodeAtFn)(JSContext *, HandleString, int32_t, uint32_t *);
  5100 static const VMFunction CharCodeAtInfo = FunctionInfo<CharCodeAtFn>(jit::CharCodeAt);
  5102 bool
  5103 CodeGenerator::visitCharCodeAt(LCharCodeAt *lir)
  5105     Register str = ToRegister(lir->str());
  5106     Register index = ToRegister(lir->index());
  5107     Register output = ToRegister(lir->output());
  5109     OutOfLineCode *ool = oolCallVM(CharCodeAtInfo, lir, (ArgList(), str, index), StoreRegisterTo(output));
  5110     if (!ool)
  5111         return false;
  5113     Address lengthAndFlagsAddr(str, JSString::offsetOfLengthAndFlags());
  5114     masm.branchTest32(Assembler::Zero, lengthAndFlagsAddr, Imm32(JSString::FLAGS_MASK), ool->entry());
  5116     // getChars
  5117     Address charsAddr(str, JSString::offsetOfChars());
  5118     masm.loadPtr(charsAddr, output);
  5119     masm.load16ZeroExtend(BaseIndex(output, index, TimesTwo, 0), output);
  5121     masm.bind(ool->rejoin());
  5122     return true;
  5125 typedef JSFlatString *(*StringFromCharCodeFn)(JSContext *, int32_t);
  5126 static const VMFunction StringFromCharCodeInfo = FunctionInfo<StringFromCharCodeFn>(jit::StringFromCharCode);
  5128 bool
  5129 CodeGenerator::visitFromCharCode(LFromCharCode *lir)
  5131     Register code = ToRegister(lir->code());
  5132     Register output = ToRegister(lir->output());
  5134     OutOfLineCode *ool = oolCallVM(StringFromCharCodeInfo, lir, (ArgList(), code), StoreRegisterTo(output));
  5135     if (!ool)
  5136         return false;
  5138     // OOL path if code >= UNIT_STATIC_LIMIT.
  5139     masm.branch32(Assembler::AboveOrEqual, code, Imm32(StaticStrings::UNIT_STATIC_LIMIT),
  5140                   ool->entry());
  5142     masm.movePtr(ImmPtr(&GetIonContext()->runtime->staticStrings().unitStaticTable), output);
  5143     masm.loadPtr(BaseIndex(output, code, ScalePointer), output);
  5145     masm.bind(ool->rejoin());
  5146     return true;
  5149 typedef JSObject *(*StringSplitFn)(JSContext *, HandleTypeObject, HandleString, HandleString);
  5150 static const VMFunction StringSplitInfo = FunctionInfo<StringSplitFn>(js::str_split_string);
  5152 bool
  5153 CodeGenerator::visitStringSplit(LStringSplit *lir)
  5155     pushArg(ToRegister(lir->separator()));
  5156     pushArg(ToRegister(lir->string()));
  5157     pushArg(ImmGCPtr(lir->mir()->typeObject()));
  5159     return callVM(StringSplitInfo, lir);
  5162 bool
  5163 CodeGenerator::visitInitializedLength(LInitializedLength *lir)
  5165     Address initLength(ToRegister(lir->elements()), ObjectElements::offsetOfInitializedLength());
  5166     masm.load32(initLength, ToRegister(lir->output()));
  5167     return true;
  5170 bool
  5171 CodeGenerator::visitSetInitializedLength(LSetInitializedLength *lir)
  5173     Address initLength(ToRegister(lir->elements()), ObjectElements::offsetOfInitializedLength());
  5174     Int32Key index = ToInt32Key(lir->index());
  5176     masm.bumpKey(&index, 1);
  5177     masm.storeKey(index, initLength);
  5178     // Restore register value if it is used/captured after.
  5179     masm.bumpKey(&index, -1);
  5180     return true;
  5183 bool
  5184 CodeGenerator::visitNotO(LNotO *lir)
  5186     MOZ_ASSERT(lir->mir()->operandMightEmulateUndefined(),
  5187                "This should be constant-folded if the object can't emulate undefined.");
  5189     OutOfLineTestObjectWithLabels *ool = new(alloc()) OutOfLineTestObjectWithLabels();
  5190     if (!addOutOfLineCode(ool))
  5191         return false;
  5193     Label *ifEmulatesUndefined = ool->label1();
  5194     Label *ifDoesntEmulateUndefined = ool->label2();
  5196     Register objreg = ToRegister(lir->input());
  5197     Register output = ToRegister(lir->output());
  5198     branchTestObjectEmulatesUndefined(objreg, ifEmulatesUndefined, ifDoesntEmulateUndefined,
  5199                                       output, ool);
  5200     // fall through
  5202     Label join;
  5204     masm.move32(Imm32(0), output);
  5205     masm.jump(&join);
  5207     masm.bind(ifEmulatesUndefined);
  5208     masm.move32(Imm32(1), output);
  5210     masm.bind(&join);
  5211     return true;
  5214 bool
  5215 CodeGenerator::visitNotV(LNotV *lir)
  5217     Maybe<Label> ifTruthyLabel, ifFalsyLabel;
  5218     Label *ifTruthy;
  5219     Label *ifFalsy;
  5221     OutOfLineTestObjectWithLabels *ool = nullptr;
  5222     if (lir->mir()->operandMightEmulateUndefined()) {
  5223         ool = new(alloc()) OutOfLineTestObjectWithLabels();
  5224         if (!addOutOfLineCode(ool))
  5225             return false;
  5226         ifTruthy = ool->label1();
  5227         ifFalsy = ool->label2();
  5228     } else {
  5229         ifTruthyLabel.construct();
  5230         ifFalsyLabel.construct();
  5231         ifTruthy = ifTruthyLabel.addr();
  5232         ifFalsy = ifFalsyLabel.addr();
  5235     testValueTruthyKernel(ToValue(lir, LNotV::Input), lir->temp1(), lir->temp2(),
  5236                           ToFloatRegister(lir->tempFloat()),
  5237                           ifTruthy, ifFalsy, ool);
  5239     Label join;
  5240     Register output = ToRegister(lir->output());
  5242     // Note that the testValueTruthyKernel call above may choose to fall through
  5243     // to ifTruthy instead of branching there.
  5244     masm.bind(ifTruthy);
  5245     masm.move32(Imm32(0), output);
  5246     masm.jump(&join);
  5248     masm.bind(ifFalsy);
  5249     masm.move32(Imm32(1), output);
  5251     // both branches meet here.
  5252     masm.bind(&join);
  5253     return true;
  5256 bool
  5257 CodeGenerator::visitBoundsCheck(LBoundsCheck *lir)
  5259     if (lir->index()->isConstant()) {
  5260         // Use uint32 so that the comparison is unsigned.
  5261         uint32_t index = ToInt32(lir->index());
  5262         if (lir->length()->isConstant()) {
  5263             uint32_t length = ToInt32(lir->length());
  5264             if (index < length)
  5265                 return true;
  5266             return bailout(lir->snapshot());
  5268         return bailoutCmp32(Assembler::BelowOrEqual, ToOperand(lir->length()), Imm32(index),
  5269                             lir->snapshot());
  5271     if (lir->length()->isConstant()) {
  5272         return bailoutCmp32(Assembler::AboveOrEqual, ToRegister(lir->index()),
  5273                              Imm32(ToInt32(lir->length())), lir->snapshot());
  5275     return bailoutCmp32(Assembler::BelowOrEqual, ToOperand(lir->length()),
  5276                         ToRegister(lir->index()), lir->snapshot());
  5279 bool
  5280 CodeGenerator::visitBoundsCheckRange(LBoundsCheckRange *lir)
  5282     int32_t min = lir->mir()->minimum();
  5283     int32_t max = lir->mir()->maximum();
  5284     JS_ASSERT(max >= min);
  5286     Register temp = ToRegister(lir->getTemp(0));
  5287     if (lir->index()->isConstant()) {
  5288         int32_t nmin, nmax;
  5289         int32_t index = ToInt32(lir->index());
  5290         if (SafeAdd(index, min, &nmin) && SafeAdd(index, max, &nmax) && nmin >= 0) {
  5291             return bailoutCmp32(Assembler::BelowOrEqual, ToOperand(lir->length()), Imm32(nmax),
  5292                                 lir->snapshot());
  5294         masm.mov(ImmWord(index), temp);
  5295     } else {
  5296         masm.mov(ToRegister(lir->index()), temp);
  5299     // If the minimum and maximum differ then do an underflow check first.
  5300     // If the two are the same then doing an unsigned comparison on the
  5301     // length will also catch a negative index.
  5302     if (min != max) {
  5303         if (min != 0) {
  5304             Label bail;
  5305             masm.branchAdd32(Assembler::Overflow, Imm32(min), temp, &bail);
  5306             if (!bailoutFrom(&bail, lir->snapshot()))
  5307                 return false;
  5310         if (!bailoutCmp32(Assembler::LessThan, temp, Imm32(0), lir->snapshot()))
  5311             return false;
  5313         if (min != 0) {
  5314             int32_t diff;
  5315             if (SafeSub(max, min, &diff))
  5316                 max = diff;
  5317             else
  5318                 masm.sub32(Imm32(min), temp);
  5322     // Compute the maximum possible index. No overflow check is needed when
  5323     // max > 0. We can only wraparound to a negative number, which will test as
  5324     // larger than all nonnegative numbers in the unsigned comparison, and the
  5325     // length is required to be nonnegative (else testing a negative length
  5326     // would succeed on any nonnegative index).
  5327     if (max != 0) {
  5328         if (max < 0) {
  5329             Label bail;
  5330             masm.branchAdd32(Assembler::Overflow, Imm32(max), temp, &bail);
  5331             if (!bailoutFrom(&bail, lir->snapshot()))
  5332                 return false;
  5333         } else {
  5334             masm.add32(Imm32(max), temp);
  5338     return bailoutCmp32(Assembler::BelowOrEqual, ToOperand(lir->length()), temp, lir->snapshot());
  5341 bool
  5342 CodeGenerator::visitBoundsCheckLower(LBoundsCheckLower *lir)
  5344     int32_t min = lir->mir()->minimum();
  5345     return bailoutCmp32(Assembler::LessThan, ToRegister(lir->index()), Imm32(min),
  5346                         lir->snapshot());
  5349 class OutOfLineStoreElementHole : public OutOfLineCodeBase<CodeGenerator>
  5351     LInstruction *ins_;
  5352     Label rejoinStore_;
  5354   public:
  5355     OutOfLineStoreElementHole(LInstruction *ins)
  5356       : ins_(ins)
  5358         JS_ASSERT(ins->isStoreElementHoleV() || ins->isStoreElementHoleT());
  5361     bool accept(CodeGenerator *codegen) {
  5362         return codegen->visitOutOfLineStoreElementHole(this);
  5364     LInstruction *ins() const {
  5365         return ins_;
  5367     Label *rejoinStore() {
  5368         return &rejoinStore_;
  5370 };
  5372 bool
  5373 CodeGenerator::emitStoreHoleCheck(Register elements, const LAllocation *index, LSnapshot *snapshot)
  5375     Label bail;
  5376     if (index->isConstant()) {
  5377         masm.branchTestMagic(Assembler::Equal,
  5378                              Address(elements, ToInt32(index) * sizeof(js::Value)), &bail);
  5379     } else {
  5380         masm.branchTestMagic(Assembler::Equal,
  5381                              BaseIndex(elements, ToRegister(index), TimesEight), &bail);
  5383     return bailoutFrom(&bail, snapshot);
  5386 bool
  5387 CodeGenerator::visitStoreElementT(LStoreElementT *store)
  5389     Register elements = ToRegister(store->elements());
  5390     const LAllocation *index = store->index();
  5392     if (store->mir()->needsBarrier())
  5393        emitPreBarrier(elements, index, store->mir()->elementType());
  5395     if (store->mir()->needsHoleCheck() && !emitStoreHoleCheck(elements, index, store->snapshot()))
  5396         return false;
  5398     storeElementTyped(store->value(), store->mir()->value()->type(), store->mir()->elementType(),
  5399                       elements, index);
  5400     return true;
  5403 bool
  5404 CodeGenerator::visitStoreElementV(LStoreElementV *lir)
  5406     const ValueOperand value = ToValue(lir, LStoreElementV::Value);
  5407     Register elements = ToRegister(lir->elements());
  5408     const LAllocation *index = lir->index();
  5410     if (lir->mir()->needsBarrier())
  5411         emitPreBarrier(elements, index, MIRType_Value);
  5413     if (lir->mir()->needsHoleCheck() && !emitStoreHoleCheck(elements, index, lir->snapshot()))
  5414         return false;
  5416     if (lir->index()->isConstant())
  5417         masm.storeValue(value, Address(elements, ToInt32(lir->index()) * sizeof(js::Value)));
  5418     else
  5419         masm.storeValue(value, BaseIndex(elements, ToRegister(lir->index()), TimesEight));
  5420     return true;
  5423 bool
  5424 CodeGenerator::visitStoreElementHoleT(LStoreElementHoleT *lir)
  5426     OutOfLineStoreElementHole *ool = new(alloc()) OutOfLineStoreElementHole(lir);
  5427     if (!addOutOfLineCode(ool))
  5428         return false;
  5430     Register elements = ToRegister(lir->elements());
  5431     const LAllocation *index = lir->index();
  5433     // OOL path if index >= initializedLength.
  5434     Address initLength(elements, ObjectElements::offsetOfInitializedLength());
  5435     masm.branchKey(Assembler::BelowOrEqual, initLength, ToInt32Key(index), ool->entry());
  5437     if (lir->mir()->needsBarrier())
  5438         emitPreBarrier(elements, index, lir->mir()->elementType());
  5440     masm.bind(ool->rejoinStore());
  5441     storeElementTyped(lir->value(), lir->mir()->value()->type(), lir->mir()->elementType(),
  5442                       elements, index);
  5444     masm.bind(ool->rejoin());
  5445     return true;
  5448 bool
  5449 CodeGenerator::visitStoreElementHoleV(LStoreElementHoleV *lir)
  5451     OutOfLineStoreElementHole *ool = new(alloc()) OutOfLineStoreElementHole(lir);
  5452     if (!addOutOfLineCode(ool))
  5453         return false;
  5455     Register elements = ToRegister(lir->elements());
  5456     const LAllocation *index = lir->index();
  5457     const ValueOperand value = ToValue(lir, LStoreElementHoleV::Value);
  5459     // OOL path if index >= initializedLength.
  5460     Address initLength(elements, ObjectElements::offsetOfInitializedLength());
  5461     masm.branchKey(Assembler::BelowOrEqual, initLength, ToInt32Key(index), ool->entry());
  5463     if (lir->mir()->needsBarrier())
  5464         emitPreBarrier(elements, index, lir->mir()->elementType());
  5466     masm.bind(ool->rejoinStore());
  5467     if (lir->index()->isConstant())
  5468         masm.storeValue(value, Address(elements, ToInt32(lir->index()) * sizeof(js::Value)));
  5469     else
  5470         masm.storeValue(value, BaseIndex(elements, ToRegister(lir->index()), TimesEight));
  5472     masm.bind(ool->rejoin());
  5473     return true;
  5476 typedef bool (*SetDenseElementFn)(JSContext *, HandleObject, int32_t, HandleValue,
  5477                                   bool strict);
  5478 typedef bool (*SetDenseElementParFn)(ForkJoinContext *, HandleObject, int32_t, HandleValue, bool);
  5479 static const VMFunctionsModal SetDenseElementInfo = VMFunctionsModal(
  5480     FunctionInfo<SetDenseElementFn>(SetDenseElement),
  5481     FunctionInfo<SetDenseElementParFn>(SetDenseElementPar));
  5483 bool
  5484 CodeGenerator::visitOutOfLineStoreElementHole(OutOfLineStoreElementHole *ool)
  5486     Register object, elements;
  5487     LInstruction *ins = ool->ins();
  5488     const LAllocation *index;
  5489     MIRType valueType;
  5490     ConstantOrRegister value;
  5492     if (ins->isStoreElementHoleV()) {
  5493         LStoreElementHoleV *store = ins->toStoreElementHoleV();
  5494         object = ToRegister(store->object());
  5495         elements = ToRegister(store->elements());
  5496         index = store->index();
  5497         valueType = store->mir()->value()->type();
  5498         value = TypedOrValueRegister(ToValue(store, LStoreElementHoleV::Value));
  5499     } else {
  5500         LStoreElementHoleT *store = ins->toStoreElementHoleT();
  5501         object = ToRegister(store->object());
  5502         elements = ToRegister(store->elements());
  5503         index = store->index();
  5504         valueType = store->mir()->value()->type();
  5505         if (store->value()->isConstant())
  5506             value = ConstantOrRegister(*store->value()->toConstant());
  5507         else
  5508             value = TypedOrValueRegister(valueType, ToAnyRegister(store->value()));
  5511     // If index == initializedLength, try to bump the initialized length inline.
  5512     // If index > initializedLength, call a stub. Note that this relies on the
  5513     // condition flags sticking from the incoming branch.
  5514     Label callStub;
  5515 #ifdef JS_CODEGEN_MIPS
  5516     // Had to reimplement for MIPS because there are no flags.
  5517     Address initLength(elements, ObjectElements::offsetOfInitializedLength());
  5518     masm.branchKey(Assembler::NotEqual, initLength, ToInt32Key(index), &callStub);
  5519 #else
  5520     masm.j(Assembler::NotEqual, &callStub);
  5521 #endif
  5523     Int32Key key = ToInt32Key(index);
  5525     // Check array capacity.
  5526     masm.branchKey(Assembler::BelowOrEqual, Address(elements, ObjectElements::offsetOfCapacity()),
  5527                    key, &callStub);
  5529     // Update initialized length. The capacity guard above ensures this won't overflow,
  5530     // due to NELEMENTS_LIMIT.
  5531     masm.bumpKey(&key, 1);
  5532     masm.storeKey(key, Address(elements, ObjectElements::offsetOfInitializedLength()));
  5534     // Update length if length < initializedLength.
  5535     Label dontUpdate;
  5536     masm.branchKey(Assembler::AboveOrEqual, Address(elements, ObjectElements::offsetOfLength()),
  5537                    key, &dontUpdate);
  5538     masm.storeKey(key, Address(elements, ObjectElements::offsetOfLength()));
  5539     masm.bind(&dontUpdate);
  5541     masm.bumpKey(&key, -1);
  5543     if (ins->isStoreElementHoleT() && valueType != MIRType_Double) {
  5544         // The inline path for StoreElementHoleT does not always store the type tag,
  5545         // so we do the store on the OOL path. We use MIRType_None for the element type
  5546         // so that storeElementTyped will always store the type tag.
  5547         storeElementTyped(ins->toStoreElementHoleT()->value(), valueType, MIRType_None, elements,
  5548                           index);
  5549         masm.jump(ool->rejoin());
  5550     } else {
  5551         // Jump to the inline path where we will store the value.
  5552         masm.jump(ool->rejoinStore());
  5555     masm.bind(&callStub);
  5556     saveLive(ins);
  5558     pushArg(Imm32(current->mir()->strict()));
  5559     pushArg(value);
  5560     if (index->isConstant())
  5561         pushArg(Imm32(ToInt32(index)));
  5562     else
  5563         pushArg(ToRegister(index));
  5564     pushArg(object);
  5565     if (!callVM(SetDenseElementInfo, ins))
  5566         return false;
  5568     restoreLive(ins);
  5569     masm.jump(ool->rejoin());
  5570     return true;
  5573 typedef bool (*ArrayPopShiftFn)(JSContext *, HandleObject, MutableHandleValue);
  5574 static const VMFunction ArrayPopDenseInfo = FunctionInfo<ArrayPopShiftFn>(jit::ArrayPopDense);
  5575 static const VMFunction ArrayShiftDenseInfo = FunctionInfo<ArrayPopShiftFn>(jit::ArrayShiftDense);
  5577 bool
  5578 CodeGenerator::emitArrayPopShift(LInstruction *lir, const MArrayPopShift *mir, Register obj,
  5579                                  Register elementsTemp, Register lengthTemp, TypedOrValueRegister out)
  5581     OutOfLineCode *ool;
  5583     if (mir->mode() == MArrayPopShift::Pop) {
  5584         ool = oolCallVM(ArrayPopDenseInfo, lir, (ArgList(), obj), StoreValueTo(out));
  5585         if (!ool)
  5586             return false;
  5587     } else {
  5588         JS_ASSERT(mir->mode() == MArrayPopShift::Shift);
  5589         ool = oolCallVM(ArrayShiftDenseInfo, lir, (ArgList(), obj), StoreValueTo(out));
  5590         if (!ool)
  5591             return false;
  5594     // VM call if a write barrier is necessary.
  5595     masm.branchTestNeedsBarrier(Assembler::NonZero, lengthTemp, ool->entry());
  5597     // Load elements and length.
  5598     masm.loadPtr(Address(obj, JSObject::offsetOfElements()), elementsTemp);
  5599     masm.load32(Address(elementsTemp, ObjectElements::offsetOfLength()), lengthTemp);
  5601     // VM call if length != initializedLength.
  5602     Int32Key key = Int32Key(lengthTemp);
  5603     Address initLength(elementsTemp, ObjectElements::offsetOfInitializedLength());
  5604     masm.branchKey(Assembler::NotEqual, initLength, key, ool->entry());
  5606     // Test for length != 0. On zero length either take a VM call or generate
  5607     // an undefined value, depending on whether the call is known to produce
  5608     // undefined.
  5609     Label done;
  5610     if (mir->maybeUndefined()) {
  5611         Label notEmpty;
  5612         masm.branchTest32(Assembler::NonZero, lengthTemp, lengthTemp, &notEmpty);
  5613         masm.moveValue(UndefinedValue(), out.valueReg());
  5614         masm.jump(&done);
  5615         masm.bind(&notEmpty);
  5616     } else {
  5617         masm.branchTest32(Assembler::Zero, lengthTemp, lengthTemp, ool->entry());
  5620     masm.bumpKey(&key, -1);
  5622     if (mir->mode() == MArrayPopShift::Pop) {
  5623         masm.loadElementTypedOrValue(BaseIndex(elementsTemp, lengthTemp, TimesEight), out,
  5624                                      mir->needsHoleCheck(), ool->entry());
  5625     } else {
  5626         JS_ASSERT(mir->mode() == MArrayPopShift::Shift);
  5627         masm.loadElementTypedOrValue(Address(elementsTemp, 0), out, mir->needsHoleCheck(),
  5628                                      ool->entry());
  5631     // Handle the failure case when the array length is non-writable in the
  5632     // OOL path.  (Unlike in the adding-an-element cases, we can't rely on the
  5633     // capacity <= length invariant for such arrays to avoid an explicit
  5634     // check.)
  5635     Address elementFlags(elementsTemp, ObjectElements::offsetOfFlags());
  5636     Imm32 bit(ObjectElements::NONWRITABLE_ARRAY_LENGTH);
  5637     masm.branchTest32(Assembler::NonZero, elementFlags, bit, ool->entry());
  5639     // Now adjust length and initializedLength.
  5640     masm.store32(lengthTemp, Address(elementsTemp, ObjectElements::offsetOfLength()));
  5641     masm.store32(lengthTemp, Address(elementsTemp, ObjectElements::offsetOfInitializedLength()));
  5643     if (mir->mode() == MArrayPopShift::Shift) {
  5644         // Don't save the temp registers.
  5645         RegisterSet temps;
  5646         temps.add(elementsTemp);
  5647         temps.add(lengthTemp);
  5649         saveVolatile(temps);
  5650         masm.setupUnalignedABICall(1, lengthTemp);
  5651         masm.passABIArg(obj);
  5652         masm.callWithABI(JS_FUNC_TO_DATA_PTR(void *, js::ArrayShiftMoveElements));
  5653         restoreVolatile(temps);
  5656     masm.bind(&done);
  5657     masm.bind(ool->rejoin());
  5658     return true;
  5661 bool
  5662 CodeGenerator::visitArrayPopShiftV(LArrayPopShiftV *lir)
  5664     Register obj = ToRegister(lir->object());
  5665     Register elements = ToRegister(lir->temp0());
  5666     Register length = ToRegister(lir->temp1());
  5667     TypedOrValueRegister out(ToOutValue(lir));
  5668     return emitArrayPopShift(lir, lir->mir(), obj, elements, length, out);
  5671 bool
  5672 CodeGenerator::visitArrayPopShiftT(LArrayPopShiftT *lir)
  5674     Register obj = ToRegister(lir->object());
  5675     Register elements = ToRegister(lir->temp0());
  5676     Register length = ToRegister(lir->temp1());
  5677     TypedOrValueRegister out(lir->mir()->type(), ToAnyRegister(lir->output()));
  5678     return emitArrayPopShift(lir, lir->mir(), obj, elements, length, out);
  5681 typedef bool (*ArrayPushDenseFn)(JSContext *, HandleObject, HandleValue, uint32_t *);
  5682 static const VMFunction ArrayPushDenseInfo =
  5683     FunctionInfo<ArrayPushDenseFn>(jit::ArrayPushDense);
  5685 bool
  5686 CodeGenerator::emitArrayPush(LInstruction *lir, const MArrayPush *mir, Register obj,
  5687                              ConstantOrRegister value, Register elementsTemp, Register length)
  5689     OutOfLineCode *ool = oolCallVM(ArrayPushDenseInfo, lir, (ArgList(), obj, value), StoreRegisterTo(length));
  5690     if (!ool)
  5691         return false;
  5693     // Load elements and length.
  5694     masm.loadPtr(Address(obj, JSObject::offsetOfElements()), elementsTemp);
  5695     masm.load32(Address(elementsTemp, ObjectElements::offsetOfLength()), length);
  5697     Int32Key key = Int32Key(length);
  5698     Address initLength(elementsTemp, ObjectElements::offsetOfInitializedLength());
  5699     Address capacity(elementsTemp, ObjectElements::offsetOfCapacity());
  5701     // Guard length == initializedLength.
  5702     masm.branchKey(Assembler::NotEqual, initLength, key, ool->entry());
  5704     // Guard length < capacity.
  5705     masm.branchKey(Assembler::BelowOrEqual, capacity, key, ool->entry());
  5707     masm.storeConstantOrRegister(value, BaseIndex(elementsTemp, length, TimesEight));
  5709     masm.bumpKey(&key, 1);
  5710     masm.store32(length, Address(elementsTemp, ObjectElements::offsetOfLength()));
  5711     masm.store32(length, Address(elementsTemp, ObjectElements::offsetOfInitializedLength()));
  5713     masm.bind(ool->rejoin());
  5714     return true;
  5717 bool
  5718 CodeGenerator::visitArrayPushV(LArrayPushV *lir)
  5720     Register obj = ToRegister(lir->object());
  5721     Register elementsTemp = ToRegister(lir->temp());
  5722     Register length = ToRegister(lir->output());
  5723     ConstantOrRegister value = TypedOrValueRegister(ToValue(lir, LArrayPushV::Value));
  5724     return emitArrayPush(lir, lir->mir(), obj, value, elementsTemp, length);
  5727 bool
  5728 CodeGenerator::visitArrayPushT(LArrayPushT *lir)
  5730     Register obj = ToRegister(lir->object());
  5731     Register elementsTemp = ToRegister(lir->temp());
  5732     Register length = ToRegister(lir->output());
  5733     ConstantOrRegister value;
  5734     if (lir->value()->isConstant())
  5735         value = ConstantOrRegister(*lir->value()->toConstant());
  5736     else
  5737         value = TypedOrValueRegister(lir->mir()->value()->type(), ToAnyRegister(lir->value()));
  5738     return emitArrayPush(lir, lir->mir(), obj, value, elementsTemp, length);
  5741 typedef JSObject *(*ArrayConcatDenseFn)(JSContext *, HandleObject, HandleObject, HandleObject);
  5742 static const VMFunction ArrayConcatDenseInfo = FunctionInfo<ArrayConcatDenseFn>(ArrayConcatDense);
  5744 bool
  5745 CodeGenerator::visitArrayConcat(LArrayConcat *lir)
  5747     Register lhs = ToRegister(lir->lhs());
  5748     Register rhs = ToRegister(lir->rhs());
  5749     Register temp1 = ToRegister(lir->temp1());
  5750     Register temp2 = ToRegister(lir->temp2());
  5752     // If 'length == initializedLength' for both arrays we try to allocate an object
  5753     // inline and pass it to the stub. Else, we just pass nullptr and the stub falls
  5754     // back to a slow path.
  5755     Label fail, call;
  5756     masm.loadPtr(Address(lhs, JSObject::offsetOfElements()), temp1);
  5757     masm.load32(Address(temp1, ObjectElements::offsetOfInitializedLength()), temp2);
  5758     masm.branch32(Assembler::NotEqual, Address(temp1, ObjectElements::offsetOfLength()), temp2, &fail);
  5760     masm.loadPtr(Address(rhs, JSObject::offsetOfElements()), temp1);
  5761     masm.load32(Address(temp1, ObjectElements::offsetOfInitializedLength()), temp2);
  5762     masm.branch32(Assembler::NotEqual, Address(temp1, ObjectElements::offsetOfLength()), temp2, &fail);
  5764     // Try to allocate an object.
  5765     JSObject *templateObj = lir->mir()->templateObj();
  5766     masm.newGCThing(temp1, temp2, templateObj, &fail, lir->mir()->initialHeap());
  5767     masm.initGCThing(temp1, temp2, templateObj);
  5768     masm.jump(&call);
  5770         masm.bind(&fail);
  5771         masm.movePtr(ImmPtr(nullptr), temp1);
  5773     masm.bind(&call);
  5775     pushArg(temp1);
  5776     pushArg(ToRegister(lir->rhs()));
  5777     pushArg(ToRegister(lir->lhs()));
  5778     return callVM(ArrayConcatDenseInfo, lir);
  5781 typedef JSObject *(*GetIteratorObjectFn)(JSContext *, HandleObject, uint32_t);
  5782 static const VMFunction GetIteratorObjectInfo = FunctionInfo<GetIteratorObjectFn>(GetIteratorObject);
  5784 bool
  5785 CodeGenerator::visitCallIteratorStart(LCallIteratorStart *lir)
  5787     pushArg(Imm32(lir->mir()->flags()));
  5788     pushArg(ToRegister(lir->object()));
  5789     return callVM(GetIteratorObjectInfo, lir);
  5792 bool
  5793 CodeGenerator::visitIteratorStart(LIteratorStart *lir)
  5795     const Register obj = ToRegister(lir->object());
  5796     const Register output = ToRegister(lir->output());
  5798     uint32_t flags = lir->mir()->flags();
  5800     OutOfLineCode *ool = oolCallVM(GetIteratorObjectInfo, lir,
  5801                                    (ArgList(), obj, Imm32(flags)), StoreRegisterTo(output));
  5802     if (!ool)
  5803         return false;
  5805     const Register temp1 = ToRegister(lir->temp1());
  5806     const Register temp2 = ToRegister(lir->temp2());
  5807     const Register niTemp = ToRegister(lir->temp3()); // Holds the NativeIterator object.
  5809     // Iterators other than for-in should use LCallIteratorStart.
  5810     JS_ASSERT(flags == JSITER_ENUMERATE);
  5812     // Fetch the most recent iterator and ensure it's not nullptr.
  5813     masm.loadPtr(AbsoluteAddress(GetIonContext()->runtime->addressOfLastCachedNativeIterator()), output);
  5814     masm.branchTestPtr(Assembler::Zero, output, output, ool->entry());
  5816     // Load NativeIterator.
  5817     masm.loadObjPrivate(output, JSObject::ITER_CLASS_NFIXED_SLOTS, niTemp);
  5819     // Ensure the |active| and |unreusable| bits are not set.
  5820     masm.branchTest32(Assembler::NonZero, Address(niTemp, offsetof(NativeIterator, flags)),
  5821                       Imm32(JSITER_ACTIVE|JSITER_UNREUSABLE), ool->entry());
  5823     // Load the iterator's shape array.
  5824     masm.loadPtr(Address(niTemp, offsetof(NativeIterator, shapes_array)), temp2);
  5826     // Compare shape of object with the first shape.
  5827     masm.loadObjShape(obj, temp1);
  5828     masm.branchPtr(Assembler::NotEqual, Address(temp2, 0), temp1, ool->entry());
  5830     // Compare shape of object's prototype with the second shape.
  5831     masm.loadObjProto(obj, temp1);
  5832     masm.loadObjShape(temp1, temp1);
  5833     masm.branchPtr(Assembler::NotEqual, Address(temp2, sizeof(Shape *)), temp1, ool->entry());
  5835     // Ensure the object's prototype's prototype is nullptr. The last native
  5836     // iterator will always have a prototype chain length of one (i.e. it must
  5837     // be a plain ), so we do not need to generate a loop here.
  5838     masm.loadObjProto(obj, temp1);
  5839     masm.loadObjProto(temp1, temp1);
  5840     masm.branchTestPtr(Assembler::NonZero, temp1, temp1, ool->entry());
  5842     // Ensure the object does not have any elements. The presence of dense
  5843     // elements is not captured by the shape tests above.
  5844     masm.branchPtr(Assembler::NotEqual,
  5845                    Address(obj, JSObject::offsetOfElements()),
  5846                    ImmPtr(js::emptyObjectElements),
  5847                    ool->entry());
  5849     // Write barrier for stores to the iterator. We only need to take a write
  5850     // barrier if NativeIterator::obj is actually going to change.
  5852 #ifdef JSGC_GENERATIONAL
  5853         // Bug 867815: When using a nursery, we unconditionally take this out-
  5854         // of-line so that we do not have to post-barrier the store to
  5855         // NativeIter::obj. This just needs JIT support for the Cell* buffer.
  5856         Address objAddr(niTemp, offsetof(NativeIterator, obj));
  5857         masm.branchPtr(Assembler::NotEqual, objAddr, obj, ool->entry());
  5858 #else
  5859         Label noBarrier;
  5860         masm.branchTestNeedsBarrier(Assembler::Zero, temp1, &noBarrier);
  5862         Address objAddr(niTemp, offsetof(NativeIterator, obj));
  5863         masm.branchPtr(Assembler::NotEqual, objAddr, obj, ool->entry());
  5865         masm.bind(&noBarrier);
  5866 #endif // !JSGC_GENERATIONAL
  5869     // Mark iterator as active.
  5870     masm.storePtr(obj, Address(niTemp, offsetof(NativeIterator, obj)));
  5871     masm.or32(Imm32(JSITER_ACTIVE), Address(niTemp, offsetof(NativeIterator, flags)));
  5873     // Chain onto the active iterator stack.
  5874     masm.loadPtr(AbsoluteAddress(gen->compartment->addressOfEnumerators()), temp1);
  5876     // ni->next = list
  5877     masm.storePtr(temp1, Address(niTemp, NativeIterator::offsetOfNext()));
  5879     // ni->prev = list->prev
  5880     masm.loadPtr(Address(temp1, NativeIterator::offsetOfPrev()), temp2);
  5881     masm.storePtr(temp2, Address(niTemp, NativeIterator::offsetOfPrev()));
  5883     // list->prev->next = ni
  5884     masm.storePtr(niTemp, Address(temp2, NativeIterator::offsetOfNext()));
  5886     // list->prev = ni
  5887     masm.storePtr(niTemp, Address(temp1, NativeIterator::offsetOfPrev()));
  5889     masm.bind(ool->rejoin());
  5890     return true;
  5893 static void
  5894 LoadNativeIterator(MacroAssembler &masm, Register obj, Register dest, Label *failures)
  5896     JS_ASSERT(obj != dest);
  5898     // Test class.
  5899     masm.branchTestObjClass(Assembler::NotEqual, obj, dest, &PropertyIteratorObject::class_, failures);
  5901     // Load NativeIterator object.
  5902     masm.loadObjPrivate(obj, JSObject::ITER_CLASS_NFIXED_SLOTS, dest);
  5905 typedef bool (*IteratorNextFn)(JSContext *, HandleObject, MutableHandleValue);
  5906 static const VMFunction IteratorNextInfo = FunctionInfo<IteratorNextFn>(js_IteratorNext);
  5908 bool
  5909 CodeGenerator::visitIteratorNext(LIteratorNext *lir)
  5911     const Register obj = ToRegister(lir->object());
  5912     const Register temp = ToRegister(lir->temp());
  5913     const ValueOperand output = ToOutValue(lir);
  5915     OutOfLineCode *ool = oolCallVM(IteratorNextInfo, lir, (ArgList(), obj), StoreValueTo(output));
  5916     if (!ool)
  5917         return false;
  5919     LoadNativeIterator(masm, obj, temp, ool->entry());
  5921     masm.branchTest32(Assembler::NonZero, Address(temp, offsetof(NativeIterator, flags)),
  5922                       Imm32(JSITER_FOREACH), ool->entry());
  5924     // Get cursor, next string.
  5925     masm.loadPtr(Address(temp, offsetof(NativeIterator, props_cursor)), output.scratchReg());
  5926     masm.loadPtr(Address(output.scratchReg(), 0), output.scratchReg());
  5927     masm.tagValue(JSVAL_TYPE_STRING, output.scratchReg(), output);
  5929     // Increase the cursor.
  5930     masm.addPtr(Imm32(sizeof(JSString *)), Address(temp, offsetof(NativeIterator, props_cursor)));
  5932     masm.bind(ool->rejoin());
  5933     return true;
  5936 typedef bool (*IteratorMoreFn)(JSContext *, HandleObject, bool *);
  5937 static const VMFunction IteratorMoreInfo = FunctionInfo<IteratorMoreFn>(jit::IteratorMore);
  5939 bool
  5940 CodeGenerator::visitIteratorMore(LIteratorMore *lir)
  5942     const Register obj = ToRegister(lir->object());
  5943     const Register output = ToRegister(lir->output());
  5944     const Register temp = ToRegister(lir->temp());
  5946     OutOfLineCode *ool = oolCallVM(IteratorMoreInfo, lir,
  5947                                    (ArgList(), obj), StoreRegisterTo(output));
  5948     if (!ool)
  5949         return false;
  5951     LoadNativeIterator(masm, obj, output, ool->entry());
  5953     masm.branchTest32(Assembler::NonZero, Address(output, offsetof(NativeIterator, flags)),
  5954                       Imm32(JSITER_FOREACH), ool->entry());
  5956     // Set output to true if props_cursor < props_end.
  5957     masm.loadPtr(Address(output, offsetof(NativeIterator, props_end)), temp);
  5958     masm.cmpPtrSet(Assembler::LessThan, Address(output, offsetof(NativeIterator, props_cursor)),
  5959                    temp, output);
  5961     masm.bind(ool->rejoin());
  5962     return true;
  5965 typedef bool (*CloseIteratorFn)(JSContext *, HandleObject);
  5966 static const VMFunction CloseIteratorInfo = FunctionInfo<CloseIteratorFn>(CloseIterator);
  5968 bool
  5969 CodeGenerator::visitIteratorEnd(LIteratorEnd *lir)
  5971     const Register obj = ToRegister(lir->object());
  5972     const Register temp1 = ToRegister(lir->temp1());
  5973     const Register temp2 = ToRegister(lir->temp2());
  5974     const Register temp3 = ToRegister(lir->temp3());
  5976     OutOfLineCode *ool = oolCallVM(CloseIteratorInfo, lir, (ArgList(), obj), StoreNothing());
  5977     if (!ool)
  5978         return false;
  5980     LoadNativeIterator(masm, obj, temp1, ool->entry());
  5982     masm.branchTest32(Assembler::Zero, Address(temp1, offsetof(NativeIterator, flags)),
  5983                       Imm32(JSITER_ENUMERATE), ool->entry());
  5985     // Clear active bit.
  5986     masm.and32(Imm32(~JSITER_ACTIVE), Address(temp1, offsetof(NativeIterator, flags)));
  5988     // Reset property cursor.
  5989     masm.loadPtr(Address(temp1, offsetof(NativeIterator, props_array)), temp2);
  5990     masm.storePtr(temp2, Address(temp1, offsetof(NativeIterator, props_cursor)));
  5992     // Unlink from the iterator list.
  5993     const Register next = temp2;
  5994     const Register prev = temp3;
  5995     masm.loadPtr(Address(temp1, NativeIterator::offsetOfNext()), next);
  5996     masm.loadPtr(Address(temp1, NativeIterator::offsetOfPrev()), prev);
  5997     masm.storePtr(prev, Address(next, NativeIterator::offsetOfPrev()));
  5998     masm.storePtr(next, Address(prev, NativeIterator::offsetOfNext()));
  5999 #ifdef DEBUG
  6000     masm.storePtr(ImmPtr(nullptr), Address(temp1, NativeIterator::offsetOfNext()));
  6001     masm.storePtr(ImmPtr(nullptr), Address(temp1, NativeIterator::offsetOfPrev()));
  6002 #endif
  6004     masm.bind(ool->rejoin());
  6005     return true;
  6008 bool
  6009 CodeGenerator::visitArgumentsLength(LArgumentsLength *lir)
  6011     // read number of actual arguments from the JS frame.
  6012     Register argc = ToRegister(lir->output());
  6013     Address ptr(StackPointer, frameSize() + IonJSFrameLayout::offsetOfNumActualArgs());
  6015     masm.loadPtr(ptr, argc);
  6016     return true;
  6019 bool
  6020 CodeGenerator::visitGetFrameArgument(LGetFrameArgument *lir)
  6022     ValueOperand result = GetValueOutput(lir);
  6023     const LAllocation *index = lir->index();
  6024     size_t argvOffset = frameSize() + IonJSFrameLayout::offsetOfActualArgs();
  6026     if (index->isConstant()) {
  6027         int32_t i = index->toConstant()->toInt32();
  6028         Address argPtr(StackPointer, sizeof(Value) * i + argvOffset);
  6029         masm.loadValue(argPtr, result);
  6030     } else {
  6031         Register i = ToRegister(index);
  6032         BaseIndex argPtr(StackPointer, i, ScaleFromElemWidth(sizeof(Value)), argvOffset);
  6033         masm.loadValue(argPtr, result);
  6035     return true;
  6038 bool
  6039 CodeGenerator::visitSetFrameArgumentT(LSetFrameArgumentT *lir)
  6041     size_t argOffset = frameSize() + IonJSFrameLayout::offsetOfActualArgs() +
  6042                        (sizeof(Value) * lir->mir()->argno());
  6044     MIRType type = lir->mir()->value()->type();
  6046     if (type == MIRType_Double) {
  6047         // Store doubles directly.
  6048         FloatRegister input = ToFloatRegister(lir->input());
  6049         masm.storeDouble(input, Address(StackPointer, argOffset));
  6051     } else {
  6052         Register input = ToRegister(lir->input());
  6053         masm.storeValue(ValueTypeFromMIRType(type), input, Address(StackPointer, argOffset));
  6055     return true;
  6058 bool
  6059 CodeGenerator:: visitSetFrameArgumentC(LSetFrameArgumentC *lir)
  6061     size_t argOffset = frameSize() + IonJSFrameLayout::offsetOfActualArgs() +
  6062                        (sizeof(Value) * lir->mir()->argno());
  6063     masm.storeValue(lir->val(), Address(StackPointer, argOffset));
  6064     return true;
  6067 bool
  6068 CodeGenerator:: visitSetFrameArgumentV(LSetFrameArgumentV *lir)
  6070     const ValueOperand val = ToValue(lir, LSetFrameArgumentV::Input);
  6071     size_t argOffset = frameSize() + IonJSFrameLayout::offsetOfActualArgs() +
  6072                        (sizeof(Value) * lir->mir()->argno());
  6073     masm.storeValue(val, Address(StackPointer, argOffset));
  6074     return true;
  6077 typedef bool (*RunOnceScriptPrologueFn)(JSContext *, HandleScript);
  6078 static const VMFunction RunOnceScriptPrologueInfo =
  6079     FunctionInfo<RunOnceScriptPrologueFn>(js::RunOnceScriptPrologue);
  6081 bool
  6082 CodeGenerator::visitRunOncePrologue(LRunOncePrologue *lir)
  6084     pushArg(ImmGCPtr(lir->mir()->block()->info().script()));
  6085     return callVM(RunOnceScriptPrologueInfo, lir);
  6089 typedef JSObject *(*InitRestParameterFn)(JSContext *, uint32_t, Value *, HandleObject,
  6090                                          HandleObject);
  6091 typedef JSObject *(*InitRestParameterParFn)(ForkJoinContext *, uint32_t, Value *,
  6092                                             HandleObject, HandleObject);
  6093 static const VMFunctionsModal InitRestParameterInfo = VMFunctionsModal(
  6094     FunctionInfo<InitRestParameterFn>(InitRestParameter),
  6095     FunctionInfo<InitRestParameterParFn>(InitRestParameterPar));
  6097 bool
  6098 CodeGenerator::emitRest(LInstruction *lir, Register array, Register numActuals,
  6099                         Register temp0, Register temp1, unsigned numFormals,
  6100                         JSObject *templateObject)
  6102     // Compute actuals() + numFormals.
  6103     size_t actualsOffset = frameSize() + IonJSFrameLayout::offsetOfActualArgs();
  6104     masm.movePtr(StackPointer, temp1);
  6105     masm.addPtr(Imm32(sizeof(Value) * numFormals + actualsOffset), temp1);
  6107     // Compute numActuals - numFormals.
  6108     Label emptyLength, joinLength;
  6109     masm.movePtr(numActuals, temp0);
  6110     masm.branch32(Assembler::LessThanOrEqual, temp0, Imm32(numFormals), &emptyLength);
  6111     masm.sub32(Imm32(numFormals), temp0);
  6112     masm.jump(&joinLength);
  6114         masm.bind(&emptyLength);
  6115         masm.move32(Imm32(0), temp0);
  6117     masm.bind(&joinLength);
  6119     pushArg(array);
  6120     pushArg(ImmGCPtr(templateObject));
  6121     pushArg(temp1);
  6122     pushArg(temp0);
  6124     return callVM(InitRestParameterInfo, lir);
  6127 bool
  6128 CodeGenerator::visitRest(LRest *lir)
  6130     Register numActuals = ToRegister(lir->numActuals());
  6131     Register temp0 = ToRegister(lir->getTemp(0));
  6132     Register temp1 = ToRegister(lir->getTemp(1));
  6133     Register temp2 = ToRegister(lir->getTemp(2));
  6134     unsigned numFormals = lir->mir()->numFormals();
  6135     JSObject *templateObject = lir->mir()->templateObject();
  6137     Label joinAlloc, failAlloc;
  6138     masm.newGCThing(temp2, temp0, templateObject, &failAlloc, gc::DefaultHeap);
  6139     masm.initGCThing(temp2, temp0, templateObject);
  6140     masm.jump(&joinAlloc);
  6142         masm.bind(&failAlloc);
  6143         masm.movePtr(ImmPtr(nullptr), temp2);
  6145     masm.bind(&joinAlloc);
  6147     return emitRest(lir, temp2, numActuals, temp0, temp1, numFormals, templateObject);
  6150 bool
  6151 CodeGenerator::visitRestPar(LRestPar *lir)
  6153     Register numActuals = ToRegister(lir->numActuals());
  6154     Register cx = ToRegister(lir->forkJoinContext());
  6155     Register temp0 = ToRegister(lir->getTemp(0));
  6156     Register temp1 = ToRegister(lir->getTemp(1));
  6157     Register temp2 = ToRegister(lir->getTemp(2));
  6158     unsigned numFormals = lir->mir()->numFormals();
  6159     JSObject *templateObject = lir->mir()->templateObject();
  6161     if (!emitAllocateGCThingPar(lir, temp2, cx, temp0, temp1, templateObject))
  6162         return false;
  6164     return emitRest(lir, temp2, numActuals, temp0, temp1, numFormals, templateObject);
  6167 bool
  6168 CodeGenerator::generateAsmJS(Label *stackOverflowLabel)
  6170     IonSpew(IonSpew_Codegen, "# Emitting asm.js code");
  6172     // AsmJS doesn't do profiler instrumentation.
  6173     sps_.disable();
  6175     // The caller (either another asm.js function or the external-entry
  6176     // trampoline) has placed all arguments in registers and on the stack
  6177     // according to the system ABI. The MAsmJSParameters which represent these
  6178     // parameters have been useFixed()ed to these ABI-specified positions.
  6179     // Thus, there is nothing special to do in the prologue except (possibly)
  6180     // bump the stack.
  6181     if (!generateAsmJSPrologue(stackOverflowLabel))
  6182         return false;
  6183     if (!generateBody())
  6184         return false;
  6185     if (!generateEpilogue())
  6186         return false;
  6187 #if defined(JS_ION_PERF)
  6188     // Note the end of the inline code and start of the OOL code.
  6189     gen->perfSpewer().noteEndInlineCode(masm);
  6190 #endif
  6191     if (!generateOutOfLineCode())
  6192         return false;
  6194     // The only remaining work needed to compile this function is to patch the
  6195     // switch-statement jump tables (the entries of the table need the absolute
  6196     // address of the cases). These table entries are accmulated as CodeLabels
  6197     // in the MacroAssembler's codeLabels_ list and processed all at once at in
  6198     // the "static-link" phase of module compilation. It is critical that there
  6199     // is nothing else to do after this point since the LifoAlloc memory
  6200     // holding the MIR graph is about to be popped and reused. In particular,
  6201     // every step in CodeGenerator::link must be a nop, as asserted here:
  6202     JS_ASSERT(snapshots_.listSize() == 0);
  6203     JS_ASSERT(snapshots_.RVATableSize() == 0);
  6204     JS_ASSERT(recovers_.size() == 0);
  6205     JS_ASSERT(bailouts_.empty());
  6206     JS_ASSERT(graph.numConstants() == 0);
  6207     JS_ASSERT(safepointIndices_.empty());
  6208     JS_ASSERT(osiIndices_.empty());
  6209     JS_ASSERT(cacheList_.empty());
  6210     JS_ASSERT(safepoints_.size() == 0);
  6211     return true;
  6214 bool
  6215 CodeGenerator::generate()
  6217     IonSpew(IonSpew_Codegen, "# Emitting code for script %s:%d",
  6218             gen->info().script()->filename(),
  6219             gen->info().script()->lineno());
  6221     if (!snapshots_.init())
  6222         return false;
  6224     if (!safepoints_.init(gen->alloc(), graph.totalSlotCount()))
  6225         return false;
  6227 #ifdef JS_TRACE_LOGGING
  6228     if (!gen->compilingAsmJS() && gen->info().executionMode() == SequentialExecution) {
  6229         if (!emitTracelogScriptStart())
  6230             return false;
  6231         if (!emitTracelogStartEvent(TraceLogger::IonMonkey))
  6232             return false;
  6234 #endif
  6236     // Before generating any code, we generate type checks for all parameters.
  6237     // This comes before deoptTable_, because we can't use deopt tables without
  6238     // creating the actual frame.
  6239     if (!generateArgumentsChecks())
  6240         return false;
  6242     if (frameClass_ != FrameSizeClass::None()) {
  6243         deoptTable_ = gen->jitRuntime()->getBailoutTable(frameClass_);
  6244         if (!deoptTable_)
  6245             return false;
  6248 #ifdef JS_TRACE_LOGGING
  6249     Label skip;
  6250     masm.jump(&skip);
  6251 #endif
  6253     // Remember the entry offset to skip the argument check.
  6254     masm.flushBuffer();
  6255     setSkipArgCheckEntryOffset(masm.size());
  6257 #ifdef JS_TRACE_LOGGING
  6258     if (!gen->compilingAsmJS() && gen->info().executionMode() == SequentialExecution) {
  6259         if (!emitTracelogScriptStart())
  6260             return false;
  6261         if (!emitTracelogStartEvent(TraceLogger::IonMonkey))
  6262             return false;
  6264     masm.bind(&skip);
  6265 #endif
  6267 #ifdef DEBUG
  6268     // Assert that the argument types are correct.
  6269     if (!generateArgumentsChecks(/* bailout = */ false))
  6270         return false;
  6271 #endif
  6273     if (!generatePrologue())
  6274         return false;
  6275     if (!generateBody())
  6276         return false;
  6277     if (!generateEpilogue())
  6278         return false;
  6279     if (!generateInvalidateEpilogue())
  6280         return false;
  6281 #if defined(JS_ION_PERF)
  6282     // Note the end of the inline code and start of the OOL code.
  6283     perfSpewer_.noteEndInlineCode(masm);
  6284 #endif
  6285     if (!generateOutOfLineCode())
  6286         return false;
  6288     return !masm.oom();
  6291 bool
  6292 CodeGenerator::link(JSContext *cx, types::CompilerConstraintList *constraints)
  6294     RootedScript script(cx, gen->info().script());
  6295     ExecutionMode executionMode = gen->info().executionMode();
  6296     OptimizationLevel optimizationLevel = gen->optimizationInfo().level();
  6298     JS_ASSERT_IF(HasIonScript(script, executionMode), executionMode == SequentialExecution);
  6300     // We finished the new IonScript. Invalidate the current active IonScript,
  6301     // so we can replace it with this new (probably higher optimized) version.
  6302     if (HasIonScript(script, executionMode)) {
  6303         JS_ASSERT(GetIonScript(script, executionMode)->isRecompiling());
  6304         // Do a normal invalidate, except don't cancel offThread compilations,
  6305         // since that will cancel this compilation too.
  6306         if (!Invalidate(cx, script, SequentialExecution,
  6307                         /* resetUses */ false, /* cancelOffThread*/ false))
  6309             return false;
  6313     // Check to make sure we didn't have a mid-build invalidation. If so, we
  6314     // will trickle to jit::Compile() and return Method_Skipped.
  6315     types::RecompileInfo recompileInfo;
  6316     if (!types::FinishCompilation(cx, script, executionMode, constraints, &recompileInfo))
  6317         return true;
  6319     uint32_t scriptFrameSize = frameClass_ == FrameSizeClass::None()
  6320                            ? frameDepth_
  6321                            : FrameSizeClass::FromDepth(frameDepth_).frameSize();
  6323     // We encode safepoints after the OSI-point offsets have been determined.
  6324     encodeSafepoints();
  6326     // List of possible scripts that this graph may call. Currently this is
  6327     // only tracked when compiling for parallel execution.
  6328     CallTargetVector callTargets(alloc());
  6329     if (executionMode == ParallelExecution)
  6330         AddPossibleCallees(cx, graph.mir(), callTargets);
  6332     IonScript *ionScript =
  6333       IonScript::New(cx, recompileInfo,
  6334                      graph.totalSlotCount(), scriptFrameSize,
  6335                      snapshots_.listSize(), snapshots_.RVATableSize(),
  6336                      recovers_.size(), bailouts_.length(), graph.numConstants(),
  6337                      safepointIndices_.length(), osiIndices_.length(),
  6338                      cacheList_.length(), runtimeData_.length(),
  6339                      safepoints_.size(), callTargets.length(),
  6340                      patchableBackedges_.length(), optimizationLevel);
  6341     if (!ionScript) {
  6342         recompileInfo.compilerOutput(cx->zone()->types)->invalidate();
  6343         return false;
  6346     // Lock the runtime against interrupt callbacks during the link.
  6347     // We don't want an interrupt request to protect the code for the script
  6348     // before it has been filled in, as we could segv before the runtime's
  6349     // patchable backedges have been fully updated.
  6350     JSRuntime::AutoLockForInterrupt lock(cx->runtime());
  6352     // Make sure we don't segv while filling in the code, to avoid deadlocking
  6353     // inside the signal handler.
  6354     cx->runtime()->jitRuntime()->ensureIonCodeAccessible(cx->runtime());
  6356     // Implicit interrupts are used only for sequential code. In parallel mode
  6357     // use the normal executable allocator so that we cannot segv during
  6358     // execution off the main thread.
  6359     Linker linker(masm);
  6360     AutoFlushICache afc("IonLink");
  6361     JitCode *code = (executionMode == SequentialExecution)
  6362                     ? linker.newCodeForIonScript(cx)
  6363                     : linker.newCode<CanGC>(cx, JSC::ION_CODE);
  6364     if (!code) {
  6365         // Use js_free instead of IonScript::Destroy: the cache list and
  6366         // backedge list are still uninitialized.
  6367         js_free(ionScript);
  6368         recompileInfo.compilerOutput(cx->zone()->types)->invalidate();
  6369         return false;
  6372     ionScript->setMethod(code);
  6373     ionScript->setSkipArgCheckEntryOffset(getSkipArgCheckEntryOffset());
  6375     // If SPS is enabled, mark IonScript as having been instrumented with SPS
  6376     if (sps_.enabled())
  6377         ionScript->setHasSPSInstrumentation();
  6379     SetIonScript(script, executionMode, ionScript);
  6381     if (cx->runtime()->spsProfiler.enabled()) {
  6382         const char *filename = script->filename();
  6383         if (filename == nullptr)
  6384             filename = "<unknown>";
  6385         unsigned len = strlen(filename) + 50;
  6386         char *buf = js_pod_malloc<char>(len);
  6387         if (!buf)
  6388             return false;
  6389         JS_snprintf(buf, len, "Ion compiled %s:%d", filename, (int) script->lineno());
  6390         cx->runtime()->spsProfiler.markEvent(buf);
  6391         js_free(buf);
  6394     // In parallel execution mode, when we first compile a script, we
  6395     // don't know that its potential callees are compiled, so set a
  6396     // flag warning that the callees may not be fully compiled.
  6397     if (!callTargets.empty())
  6398         ionScript->setHasUncompiledCallTarget();
  6400     invalidateEpilogueData_.fixup(&masm);
  6401     Assembler::patchDataWithValueCheck(CodeLocationLabel(code, invalidateEpilogueData_),
  6402                                        ImmPtr(ionScript),
  6403                                        ImmPtr((void*)-1));
  6405     IonSpew(IonSpew_Codegen, "Created IonScript %p (raw %p)",
  6406             (void *) ionScript, (void *) code->raw());
  6408     ionScript->setInvalidationEpilogueDataOffset(invalidateEpilogueData_.offset());
  6409     ionScript->setOsrPc(gen->info().osrPc());
  6410     ionScript->setOsrEntryOffset(getOsrEntryOffset());
  6411     ptrdiff_t real_invalidate = masm.actualOffset(invalidate_.offset());
  6412     ionScript->setInvalidationEpilogueOffset(real_invalidate);
  6414     ionScript->setDeoptTable(deoptTable_);
  6416 #if defined(JS_ION_PERF)
  6417     if (PerfEnabled())
  6418         perfSpewer_.writeProfile(script, code, masm);
  6419 #endif
  6421     for (size_t i = 0; i < ionScriptLabels_.length(); i++) {
  6422         ionScriptLabels_[i].fixup(&masm);
  6423         Assembler::patchDataWithValueCheck(CodeLocationLabel(code, ionScriptLabels_[i]),
  6424                                            ImmPtr(ionScript),
  6425                                            ImmPtr((void*)-1));
  6428     // for generating inline caches during the execution.
  6429     if (runtimeData_.length())
  6430         ionScript->copyRuntimeData(&runtimeData_[0]);
  6431     if (cacheList_.length())
  6432         ionScript->copyCacheEntries(&cacheList_[0], masm);
  6434     // for marking during GC.
  6435     if (safepointIndices_.length())
  6436         ionScript->copySafepointIndices(&safepointIndices_[0], masm);
  6437     if (safepoints_.size())
  6438         ionScript->copySafepoints(&safepoints_);
  6440     // for reconvering from an Ion Frame.
  6441     if (bailouts_.length())
  6442         ionScript->copyBailoutTable(&bailouts_[0]);
  6443     if (osiIndices_.length())
  6444         ionScript->copyOsiIndices(&osiIndices_[0], masm);
  6445     if (snapshots_.listSize())
  6446         ionScript->copySnapshots(&snapshots_);
  6447     MOZ_ASSERT_IF(snapshots_.listSize(), recovers_.size());
  6448     if (recovers_.size())
  6449         ionScript->copyRecovers(&recovers_);
  6450     if (graph.numConstants())
  6451         ionScript->copyConstants(graph.constantPool());
  6452     if (callTargets.length() > 0)
  6453         ionScript->copyCallTargetEntries(callTargets.begin());
  6454     if (patchableBackedges_.length() > 0)
  6455         ionScript->copyPatchableBackedges(cx, code, patchableBackedges_.begin());
  6457 #ifdef JS_TRACE_LOGGING
  6458     TraceLogger *logger = TraceLoggerForMainThread(cx->runtime());
  6459     for (uint32_t i = 0; i < patchableTraceLoggers_.length(); i++) {
  6460         patchableTraceLoggers_[i].fixup(&masm);
  6461         Assembler::patchDataWithValueCheck(CodeLocationLabel(code, patchableTraceLoggers_[i]),
  6462                                            ImmPtr(logger),
  6463                                            ImmPtr(nullptr));
  6465     uint32_t scriptId = TraceLogCreateTextId(logger, script);
  6466     for (uint32_t i = 0; i < patchableTLScripts_.length(); i++) {
  6467         patchableTLScripts_[i].fixup(&masm);
  6468         Assembler::patchDataWithValueCheck(CodeLocationLabel(code, patchableTLScripts_[i]),
  6469                                            ImmPtr((void *) uintptr_t(scriptId)),
  6470                                            ImmPtr((void *)0));
  6472 #endif
  6474     switch (executionMode) {
  6475       case SequentialExecution:
  6476         // The correct state for prebarriers is unknown until the end of compilation,
  6477         // since a GC can occur during code generation. All barriers are emitted
  6478         // off-by-default, and are toggled on here if necessary.
  6479         if (cx->zone()->needsBarrier())
  6480             ionScript->toggleBarriers(true);
  6481         break;
  6482       case ParallelExecution:
  6483         // We don't run incremental GC during parallel execution; no need to
  6484         // turn on barriers.
  6485         break;
  6486       default:
  6487         MOZ_ASSUME_UNREACHABLE("No such execution mode");
  6490     return true;
  6493 // An out-of-line path to convert a boxed int32 to either a float or double.
  6494 class OutOfLineUnboxFloatingPoint : public OutOfLineCodeBase<CodeGenerator>
  6496     LUnboxFloatingPoint *unboxFloatingPoint_;
  6498   public:
  6499     OutOfLineUnboxFloatingPoint(LUnboxFloatingPoint *unboxFloatingPoint)
  6500       : unboxFloatingPoint_(unboxFloatingPoint)
  6501     { }
  6503     bool accept(CodeGenerator *codegen) {
  6504         return codegen->visitOutOfLineUnboxFloatingPoint(this);
  6507     LUnboxFloatingPoint *unboxFloatingPoint() const {
  6508         return unboxFloatingPoint_;
  6510 };
  6512 bool
  6513 CodeGenerator::visitUnboxFloatingPoint(LUnboxFloatingPoint *lir)
  6515     const ValueOperand box = ToValue(lir, LUnboxFloatingPoint::Input);
  6516     const LDefinition *result = lir->output();
  6518     // Out-of-line path to convert int32 to double or bailout
  6519     // if this instruction is fallible.
  6520     OutOfLineUnboxFloatingPoint *ool = new(alloc()) OutOfLineUnboxFloatingPoint(lir);
  6521     if (!addOutOfLineCode(ool))
  6522         return false;
  6524     FloatRegister resultReg = ToFloatRegister(result);
  6525     masm.branchTestDouble(Assembler::NotEqual, box, ool->entry());
  6526     masm.unboxDouble(box, resultReg);
  6527     if (lir->type() == MIRType_Float32)
  6528         masm.convertDoubleToFloat32(resultReg, resultReg);
  6529     masm.bind(ool->rejoin());
  6530     return true;
  6533 bool
  6534 CodeGenerator::visitOutOfLineUnboxFloatingPoint(OutOfLineUnboxFloatingPoint *ool)
  6536     LUnboxFloatingPoint *ins = ool->unboxFloatingPoint();
  6537     const ValueOperand value = ToValue(ins, LUnboxFloatingPoint::Input);
  6539     if (ins->mir()->fallible()) {
  6540         Label bail;
  6541         masm.branchTestInt32(Assembler::NotEqual, value, &bail);
  6542         if (!bailoutFrom(&bail, ins->snapshot()))
  6543             return false;
  6545     masm.int32ValueToFloatingPoint(value, ToFloatRegister(ins->output()), ins->type());
  6546     masm.jump(ool->rejoin());
  6547     return true;
  6550 typedef bool (*GetPropertyFn)(JSContext *, HandleValue, HandlePropertyName, MutableHandleValue);
  6551 static const VMFunction GetPropertyInfo = FunctionInfo<GetPropertyFn>(GetProperty);
  6552 static const VMFunction CallPropertyInfo = FunctionInfo<GetPropertyFn>(CallProperty);
  6554 bool
  6555 CodeGenerator::visitCallGetProperty(LCallGetProperty *lir)
  6557     pushArg(ImmGCPtr(lir->mir()->name()));
  6558     pushArg(ToValue(lir, LCallGetProperty::Value));
  6560     if (lir->mir()->callprop())
  6561         return callVM(CallPropertyInfo, lir);
  6562     return callVM(GetPropertyInfo, lir);
  6565 typedef bool (*GetOrCallElementFn)(JSContext *, MutableHandleValue, HandleValue, MutableHandleValue);
  6566 static const VMFunction GetElementInfo = FunctionInfo<GetOrCallElementFn>(js::GetElement);
  6567 static const VMFunction CallElementInfo = FunctionInfo<GetOrCallElementFn>(js::CallElement);
  6569 bool
  6570 CodeGenerator::visitCallGetElement(LCallGetElement *lir)
  6572     pushArg(ToValue(lir, LCallGetElement::RhsInput));
  6573     pushArg(ToValue(lir, LCallGetElement::LhsInput));
  6575     JSOp op = JSOp(*lir->mir()->resumePoint()->pc());
  6577     if (op == JSOP_GETELEM) {
  6578         return callVM(GetElementInfo, lir);
  6579     } else {
  6580         JS_ASSERT(op == JSOP_CALLELEM);
  6581         return callVM(CallElementInfo, lir);
  6585 typedef bool (*SetObjectElementFn)(JSContext *, HandleObject, HandleValue, HandleValue,
  6586                                    bool strict);
  6587 typedef bool (*SetElementParFn)(ForkJoinContext *, HandleObject, HandleValue, HandleValue, bool);
  6588 static const VMFunctionsModal SetObjectElementInfo = VMFunctionsModal(
  6589     FunctionInfo<SetObjectElementFn>(SetObjectElement),
  6590     FunctionInfo<SetElementParFn>(SetElementPar));
  6592 bool
  6593 CodeGenerator::visitCallSetElement(LCallSetElement *lir)
  6595     pushArg(Imm32(current->mir()->strict()));
  6596     pushArg(ToValue(lir, LCallSetElement::Value));
  6597     pushArg(ToValue(lir, LCallSetElement::Index));
  6598     pushArg(ToRegister(lir->getOperand(0)));
  6599     return callVM(SetObjectElementInfo, lir);
  6602 typedef bool (*InitElementArrayFn)(JSContext *, jsbytecode *, HandleObject, uint32_t, HandleValue);
  6603 static const VMFunction InitElementArrayInfo = FunctionInfo<InitElementArrayFn>(js::InitElementArray);
  6605 bool
  6606 CodeGenerator::visitCallInitElementArray(LCallInitElementArray *lir)
  6608     pushArg(ToValue(lir, LCallInitElementArray::Value));
  6609     pushArg(Imm32(lir->mir()->index()));
  6610     pushArg(ToRegister(lir->getOperand(0)));
  6611     pushArg(ImmPtr(lir->mir()->resumePoint()->pc()));
  6612     return callVM(InitElementArrayInfo, lir);
  6615 bool
  6616 CodeGenerator::visitLoadFixedSlotV(LLoadFixedSlotV *ins)
  6618     const Register obj = ToRegister(ins->getOperand(0));
  6619     size_t slot = ins->mir()->slot();
  6620     ValueOperand result = GetValueOutput(ins);
  6622     masm.loadValue(Address(obj, JSObject::getFixedSlotOffset(slot)), result);
  6623     return true;
  6626 bool
  6627 CodeGenerator::visitLoadFixedSlotT(LLoadFixedSlotT *ins)
  6629     const Register obj = ToRegister(ins->getOperand(0));
  6630     size_t slot = ins->mir()->slot();
  6631     AnyRegister result = ToAnyRegister(ins->getDef(0));
  6632     MIRType type = ins->mir()->type();
  6634     masm.loadUnboxedValue(Address(obj, JSObject::getFixedSlotOffset(slot)), type, result);
  6636     return true;
  6639 bool
  6640 CodeGenerator::visitStoreFixedSlotV(LStoreFixedSlotV *ins)
  6642     const Register obj = ToRegister(ins->getOperand(0));
  6643     size_t slot = ins->mir()->slot();
  6645     const ValueOperand value = ToValue(ins, LStoreFixedSlotV::Value);
  6647     Address address(obj, JSObject::getFixedSlotOffset(slot));
  6648     if (ins->mir()->needsBarrier())
  6649         emitPreBarrier(address, MIRType_Value);
  6651     masm.storeValue(value, address);
  6653     return true;
  6656 bool
  6657 CodeGenerator::visitStoreFixedSlotT(LStoreFixedSlotT *ins)
  6659     const Register obj = ToRegister(ins->getOperand(0));
  6660     size_t slot = ins->mir()->slot();
  6662     const LAllocation *value = ins->value();
  6663     MIRType valueType = ins->mir()->value()->type();
  6665     ConstantOrRegister nvalue = value->isConstant()
  6666                               ? ConstantOrRegister(*value->toConstant())
  6667                               : TypedOrValueRegister(valueType, ToAnyRegister(value));
  6669     Address address(obj, JSObject::getFixedSlotOffset(slot));
  6670     if (ins->mir()->needsBarrier())
  6671         emitPreBarrier(address, MIRType_Value);
  6673     masm.storeConstantOrRegister(nvalue, address);
  6675     return true;
  6678 bool
  6679 CodeGenerator::visitCallsiteCloneCache(LCallsiteCloneCache *ins)
  6681     const MCallsiteCloneCache *mir = ins->mir();
  6682     Register callee = ToRegister(ins->callee());
  6683     Register output = ToRegister(ins->output());
  6685     CallsiteCloneIC cache(callee, mir->block()->info().script(), mir->callPc(), output);
  6686     return addCache(ins, allocateCache(cache));
  6689 typedef JSObject *(*CallsiteCloneICFn)(JSContext *, size_t, HandleObject);
  6690 const VMFunction CallsiteCloneIC::UpdateInfo =
  6691     FunctionInfo<CallsiteCloneICFn>(CallsiteCloneIC::update);
  6693 bool
  6694 CodeGenerator::visitCallsiteCloneIC(OutOfLineUpdateCache *ool, DataPtr<CallsiteCloneIC> &ic)
  6696     LInstruction *lir = ool->lir();
  6697     saveLive(lir);
  6699     pushArg(ic->calleeReg());
  6700     pushArg(Imm32(ool->getCacheIndex()));
  6701     if (!callVM(CallsiteCloneIC::UpdateInfo, lir))
  6702         return false;
  6703     StoreRegisterTo(ic->outputReg()).generate(this);
  6704     restoreLiveIgnore(lir, StoreRegisterTo(ic->outputReg()).clobbered());
  6706     masm.jump(ool->rejoin());
  6707     return true;
  6710 bool
  6711 CodeGenerator::visitGetNameCache(LGetNameCache *ins)
  6713     RegisterSet liveRegs = ins->safepoint()->liveRegs();
  6714     Register scopeChain = ToRegister(ins->scopeObj());
  6715     TypedOrValueRegister output(GetValueOutput(ins));
  6716     bool isTypeOf = ins->mir()->accessKind() != MGetNameCache::NAME;
  6718     NameIC cache(liveRegs, isTypeOf, scopeChain, ins->mir()->name(), output);
  6719     return addCache(ins, allocateCache(cache));
  6722 typedef bool (*NameICFn)(JSContext *, size_t, HandleObject, MutableHandleValue);
  6723 const VMFunction NameIC::UpdateInfo = FunctionInfo<NameICFn>(NameIC::update);
  6725 bool
  6726 CodeGenerator::visitNameIC(OutOfLineUpdateCache *ool, DataPtr<NameIC> &ic)
  6728     LInstruction *lir = ool->lir();
  6729     saveLive(lir);
  6731     pushArg(ic->scopeChainReg());
  6732     pushArg(Imm32(ool->getCacheIndex()));
  6733     if (!callVM(NameIC::UpdateInfo, lir))
  6734         return false;
  6735     StoreValueTo(ic->outputReg()).generate(this);
  6736     restoreLiveIgnore(lir, StoreValueTo(ic->outputReg()).clobbered());
  6738     masm.jump(ool->rejoin());
  6739     return true;
  6742 bool
  6743 CodeGenerator::addGetPropertyCache(LInstruction *ins, RegisterSet liveRegs, Register objReg,
  6744                                    PropertyName *name, TypedOrValueRegister output,
  6745                                    bool monitoredResult)
  6747     switch (gen->info().executionMode()) {
  6748       case SequentialExecution: {
  6749         GetPropertyIC cache(liveRegs, objReg, name, output, monitoredResult);
  6750         return addCache(ins, allocateCache(cache));
  6752       case ParallelExecution: {
  6753         GetPropertyParIC cache(objReg, name, output);
  6754         return addCache(ins, allocateCache(cache));
  6756       default:
  6757         MOZ_ASSUME_UNREACHABLE("Bad execution mode");
  6761 bool
  6762 CodeGenerator::addSetPropertyCache(LInstruction *ins, RegisterSet liveRegs, Register objReg,
  6763                                    PropertyName *name, ConstantOrRegister value, bool strict,
  6764                                    bool needsTypeBarrier)
  6766     switch (gen->info().executionMode()) {
  6767       case SequentialExecution: {
  6768           SetPropertyIC cache(liveRegs, objReg, name, value, strict, needsTypeBarrier);
  6769           return addCache(ins, allocateCache(cache));
  6771       case ParallelExecution: {
  6772           SetPropertyParIC cache(objReg, name, value, strict, needsTypeBarrier);
  6773           return addCache(ins, allocateCache(cache));
  6775       default:
  6776         MOZ_ASSUME_UNREACHABLE("Bad execution mode");
  6780 bool
  6781 CodeGenerator::addSetElementCache(LInstruction *ins, Register obj, Register unboxIndex,
  6782                                   Register temp, FloatRegister tempFloat, ValueOperand index,
  6783                                   ConstantOrRegister value, bool strict, bool guardHoles)
  6785     switch (gen->info().executionMode()) {
  6786       case SequentialExecution: {
  6787         SetElementIC cache(obj, unboxIndex, temp, tempFloat, index, value, strict,
  6788                            guardHoles);
  6789         return addCache(ins, allocateCache(cache));
  6791       case ParallelExecution: {
  6792         SetElementParIC cache(obj, unboxIndex, temp, tempFloat, index, value, strict,
  6793                               guardHoles);
  6794         return addCache(ins, allocateCache(cache));
  6796       default:
  6797         MOZ_ASSUME_UNREACHABLE("Bad execution mode");
  6801 bool
  6802 CodeGenerator::visitGetPropertyCacheV(LGetPropertyCacheV *ins)
  6804     RegisterSet liveRegs = ins->safepoint()->liveRegs();
  6805     Register objReg = ToRegister(ins->getOperand(0));
  6806     PropertyName *name = ins->mir()->name();
  6807     bool monitoredResult = ins->mir()->monitoredResult();
  6808     TypedOrValueRegister output = TypedOrValueRegister(GetValueOutput(ins));
  6810     return addGetPropertyCache(ins, liveRegs, objReg, name, output, monitoredResult);
  6813 bool
  6814 CodeGenerator::visitGetPropertyCacheT(LGetPropertyCacheT *ins)
  6816     RegisterSet liveRegs = ins->safepoint()->liveRegs();
  6817     Register objReg = ToRegister(ins->getOperand(0));
  6818     PropertyName *name = ins->mir()->name();
  6819     bool monitoredResult = ins->mir()->monitoredResult();
  6820     TypedOrValueRegister output(ins->mir()->type(), ToAnyRegister(ins->getDef(0)));
  6822     return addGetPropertyCache(ins, liveRegs, objReg, name, output, monitoredResult);
  6825 typedef bool (*GetPropertyICFn)(JSContext *, size_t, HandleObject, MutableHandleValue);
  6826 const VMFunction GetPropertyIC::UpdateInfo =
  6827     FunctionInfo<GetPropertyICFn>(GetPropertyIC::update);
  6829 bool
  6830 CodeGenerator::visitGetPropertyIC(OutOfLineUpdateCache *ool, DataPtr<GetPropertyIC> &ic)
  6832     LInstruction *lir = ool->lir();
  6834     if (ic->idempotent()) {
  6835         size_t numLocs;
  6836         CacheLocationList &cacheLocs = lir->mirRaw()->toGetPropertyCache()->location();
  6837         size_t locationBase = addCacheLocations(cacheLocs, &numLocs);
  6838         ic->setLocationInfo(locationBase, numLocs);
  6841     saveLive(lir);
  6843     pushArg(ic->object());
  6844     pushArg(Imm32(ool->getCacheIndex()));
  6845     if (!callVM(GetPropertyIC::UpdateInfo, lir))
  6846         return false;
  6847     StoreValueTo(ic->output()).generate(this);
  6848     restoreLiveIgnore(lir, StoreValueTo(ic->output()).clobbered());
  6850     masm.jump(ool->rejoin());
  6851     return true;
  6854 typedef bool (*GetPropertyParICFn)(ForkJoinContext *, size_t, HandleObject, MutableHandleValue);
  6855 const VMFunction GetPropertyParIC::UpdateInfo =
  6856     FunctionInfo<GetPropertyParICFn>(GetPropertyParIC::update);
  6858 bool
  6859 CodeGenerator::visitGetPropertyParIC(OutOfLineUpdateCache *ool, DataPtr<GetPropertyParIC> &ic)
  6861     LInstruction *lir = ool->lir();
  6862     saveLive(lir);
  6864     pushArg(ic->object());
  6865     pushArg(Imm32(ool->getCacheIndex()));
  6866     if (!callVM(GetPropertyParIC::UpdateInfo, lir))
  6867         return false;
  6868     StoreValueTo(ic->output()).generate(this);
  6869     restoreLiveIgnore(lir, StoreValueTo(ic->output()).clobbered());
  6871     masm.jump(ool->rejoin());
  6872     return true;
  6875 bool
  6876 CodeGenerator::addGetElementCache(LInstruction *ins, Register obj, ConstantOrRegister index,
  6877                                   TypedOrValueRegister output, bool monitoredResult,
  6878                                   bool allowDoubleResult)
  6880     switch (gen->info().executionMode()) {
  6881       case SequentialExecution: {
  6882         RegisterSet liveRegs = ins->safepoint()->liveRegs();
  6883         GetElementIC cache(liveRegs, obj, index, output, monitoredResult, allowDoubleResult);
  6884         return addCache(ins, allocateCache(cache));
  6886       case ParallelExecution: {
  6887         GetElementParIC cache(obj, index, output, monitoredResult, allowDoubleResult);
  6888         return addCache(ins, allocateCache(cache));
  6890       default:
  6891         MOZ_ASSUME_UNREACHABLE("No such execution mode");
  6895 bool
  6896 CodeGenerator::visitGetElementCacheV(LGetElementCacheV *ins)
  6898     Register obj = ToRegister(ins->object());
  6899     ConstantOrRegister index = TypedOrValueRegister(ToValue(ins, LGetElementCacheV::Index));
  6900     TypedOrValueRegister output = TypedOrValueRegister(GetValueOutput(ins));
  6901     const MGetElementCache *mir = ins->mir();
  6903     return addGetElementCache(ins, obj, index, output, mir->monitoredResult(), mir->allowDoubleResult());
  6906 bool
  6907 CodeGenerator::visitGetElementCacheT(LGetElementCacheT *ins)
  6909     Register obj = ToRegister(ins->object());
  6910     ConstantOrRegister index = TypedOrValueRegister(MIRType_Int32, ToAnyRegister(ins->index()));
  6911     TypedOrValueRegister output(ins->mir()->type(), ToAnyRegister(ins->output()));
  6912     const MGetElementCache *mir = ins->mir();
  6914     return addGetElementCache(ins, obj, index, output, mir->monitoredResult(), mir->allowDoubleResult());
  6917 typedef bool (*GetElementICFn)(JSContext *, size_t, HandleObject, HandleValue, MutableHandleValue);
  6918 const VMFunction GetElementIC::UpdateInfo =
  6919     FunctionInfo<GetElementICFn>(GetElementIC::update);
  6921 bool
  6922 CodeGenerator::visitGetElementIC(OutOfLineUpdateCache *ool, DataPtr<GetElementIC> &ic)
  6924     LInstruction *lir = ool->lir();
  6925     saveLive(lir);
  6927     pushArg(ic->index());
  6928     pushArg(ic->object());
  6929     pushArg(Imm32(ool->getCacheIndex()));
  6930     if (!callVM(GetElementIC::UpdateInfo, lir))
  6931         return false;
  6932     StoreValueTo(ic->output()).generate(this);
  6933     restoreLiveIgnore(lir, StoreValueTo(ic->output()).clobbered());
  6935     masm.jump(ool->rejoin());
  6936     return true;
  6939 bool
  6940 CodeGenerator::visitSetElementCacheV(LSetElementCacheV *ins)
  6942     Register obj = ToRegister(ins->object());
  6943     Register unboxIndex = ToTempUnboxRegister(ins->tempToUnboxIndex());
  6944     Register temp = ToRegister(ins->temp());
  6945     FloatRegister tempFloat = ToFloatRegister(ins->tempFloat());
  6946     ValueOperand index = ToValue(ins, LSetElementCacheV::Index);
  6947     ConstantOrRegister value = TypedOrValueRegister(ToValue(ins, LSetElementCacheV::Value));
  6949     return addSetElementCache(ins, obj, unboxIndex, temp, tempFloat, index, value,
  6950                               ins->mir()->strict(), ins->mir()->guardHoles());
  6953 bool
  6954 CodeGenerator::visitSetElementCacheT(LSetElementCacheT *ins)
  6956     Register obj = ToRegister(ins->object());
  6957     Register unboxIndex = ToTempUnboxRegister(ins->tempToUnboxIndex());
  6958     Register temp = ToRegister(ins->temp());
  6959     FloatRegister tempFloat = ToFloatRegister(ins->tempFloat());
  6960     ValueOperand index = ToValue(ins, LSetElementCacheT::Index);
  6961     ConstantOrRegister value;
  6962     const LAllocation *tmp = ins->value();
  6963     if (tmp->isConstant())
  6964         value = *tmp->toConstant();
  6965     else
  6966         value = TypedOrValueRegister(ins->mir()->value()->type(), ToAnyRegister(tmp));
  6968     return addSetElementCache(ins, obj, unboxIndex, temp, tempFloat, index, value,
  6969                               ins->mir()->strict(), ins->mir()->guardHoles());
  6972 typedef bool (*SetElementICFn)(JSContext *, size_t, HandleObject, HandleValue, HandleValue);
  6973 const VMFunction SetElementIC::UpdateInfo =
  6974     FunctionInfo<SetElementICFn>(SetElementIC::update);
  6976 bool
  6977 CodeGenerator::visitSetElementIC(OutOfLineUpdateCache *ool, DataPtr<SetElementIC> &ic)
  6979     LInstruction *lir = ool->lir();
  6980     saveLive(lir);
  6982     pushArg(ic->value());
  6983     pushArg(ic->index());
  6984     pushArg(ic->object());
  6985     pushArg(Imm32(ool->getCacheIndex()));
  6986     if (!callVM(SetElementIC::UpdateInfo, lir))
  6987         return false;
  6988     restoreLive(lir);
  6990     masm.jump(ool->rejoin());
  6991     return true;
  6994 typedef bool (*SetElementParICFn)(ForkJoinContext *, size_t, HandleObject, HandleValue, HandleValue);
  6995 const VMFunction SetElementParIC::UpdateInfo =
  6996     FunctionInfo<SetElementParICFn>(SetElementParIC::update);
  6998 bool
  6999 CodeGenerator::visitSetElementParIC(OutOfLineUpdateCache *ool, DataPtr<SetElementParIC> &ic)
  7001     LInstruction *lir = ool->lir();
  7002     saveLive(lir);
  7004     pushArg(ic->value());
  7005     pushArg(ic->index());
  7006     pushArg(ic->object());
  7007     pushArg(Imm32(ool->getCacheIndex()));
  7008     if (!callVM(SetElementParIC::UpdateInfo, lir))
  7009         return false;
  7010     restoreLive(lir);
  7012     masm.jump(ool->rejoin());
  7013     return true;
  7016 typedef bool (*GetElementParICFn)(ForkJoinContext *, size_t, HandleObject, HandleValue,
  7017                                   MutableHandleValue);
  7018 const VMFunction GetElementParIC::UpdateInfo =
  7019     FunctionInfo<GetElementParICFn>(GetElementParIC::update);
  7021 bool
  7022 CodeGenerator::visitGetElementParIC(OutOfLineUpdateCache *ool, DataPtr<GetElementParIC> &ic)
  7024     LInstruction *lir = ool->lir();
  7025     saveLive(lir);
  7027     pushArg(ic->index());
  7028     pushArg(ic->object());
  7029     pushArg(Imm32(ool->getCacheIndex()));
  7030     if (!callVM(GetElementParIC::UpdateInfo, lir))
  7031         return false;
  7032     StoreValueTo(ic->output()).generate(this);
  7033     restoreLiveIgnore(lir, StoreValueTo(ic->output()).clobbered());
  7035     masm.jump(ool->rejoin());
  7036     return true;
  7039 bool
  7040 CodeGenerator::visitBindNameCache(LBindNameCache *ins)
  7042     Register scopeChain = ToRegister(ins->scopeChain());
  7043     Register output = ToRegister(ins->output());
  7044     BindNameIC cache(scopeChain, ins->mir()->name(), output);
  7046     return addCache(ins, allocateCache(cache));
  7049 typedef JSObject *(*BindNameICFn)(JSContext *, size_t, HandleObject);
  7050 const VMFunction BindNameIC::UpdateInfo =
  7051     FunctionInfo<BindNameICFn>(BindNameIC::update);
  7053 bool
  7054 CodeGenerator::visitBindNameIC(OutOfLineUpdateCache *ool, DataPtr<BindNameIC> &ic)
  7056     LInstruction *lir = ool->lir();
  7057     saveLive(lir);
  7059     pushArg(ic->scopeChainReg());
  7060     pushArg(Imm32(ool->getCacheIndex()));
  7061     if (!callVM(BindNameIC::UpdateInfo, lir))
  7062         return false;
  7063     StoreRegisterTo(ic->outputReg()).generate(this);
  7064     restoreLiveIgnore(lir, StoreRegisterTo(ic->outputReg()).clobbered());
  7066     masm.jump(ool->rejoin());
  7067     return true;
  7070 typedef bool (*SetPropertyFn)(JSContext *, HandleObject,
  7071                               HandlePropertyName, const HandleValue, bool, jsbytecode *);
  7072 typedef bool (*SetPropertyParFn)(ForkJoinContext *, HandleObject,
  7073                                  HandlePropertyName, const HandleValue, bool, jsbytecode *);
  7074 static const VMFunctionsModal SetPropertyInfo = VMFunctionsModal(
  7075     FunctionInfo<SetPropertyFn>(SetProperty),
  7076     FunctionInfo<SetPropertyParFn>(SetPropertyPar));
  7078 bool
  7079 CodeGenerator::visitCallSetProperty(LCallSetProperty *ins)
  7081     ConstantOrRegister value = TypedOrValueRegister(ToValue(ins, LCallSetProperty::Value));
  7083     const Register objReg = ToRegister(ins->getOperand(0));
  7085     pushArg(ImmPtr(ins->mir()->resumePoint()->pc()));
  7086     pushArg(Imm32(ins->mir()->strict()));
  7088     pushArg(value);
  7089     pushArg(ImmGCPtr(ins->mir()->name()));
  7090     pushArg(objReg);
  7092     return callVM(SetPropertyInfo, ins);
  7095 typedef bool (*DeletePropertyFn)(JSContext *, HandleValue, HandlePropertyName, bool *);
  7096 static const VMFunction DeletePropertyStrictInfo =
  7097     FunctionInfo<DeletePropertyFn>(DeleteProperty<true>);
  7098 static const VMFunction DeletePropertyNonStrictInfo =
  7099     FunctionInfo<DeletePropertyFn>(DeleteProperty<false>);
  7101 bool
  7102 CodeGenerator::visitCallDeleteProperty(LCallDeleteProperty *lir)
  7104     pushArg(ImmGCPtr(lir->mir()->name()));
  7105     pushArg(ToValue(lir, LCallDeleteProperty::Value));
  7107     if (lir->mir()->block()->info().script()->strict())
  7108         return callVM(DeletePropertyStrictInfo, lir);
  7110     return callVM(DeletePropertyNonStrictInfo, lir);
  7113 typedef bool (*DeleteElementFn)(JSContext *, HandleValue, HandleValue, bool *);
  7114 static const VMFunction DeleteElementStrictInfo =
  7115     FunctionInfo<DeleteElementFn>(DeleteElement<true>);
  7116 static const VMFunction DeleteElementNonStrictInfo =
  7117     FunctionInfo<DeleteElementFn>(DeleteElement<false>);
  7119 bool
  7120 CodeGenerator::visitCallDeleteElement(LCallDeleteElement *lir)
  7122     pushArg(ToValue(lir, LCallDeleteElement::Index));
  7123     pushArg(ToValue(lir, LCallDeleteElement::Value));
  7125     if (lir->mir()->block()->info().script()->strict())
  7126         return callVM(DeleteElementStrictInfo, lir);
  7128     return callVM(DeleteElementNonStrictInfo, lir);
  7131 bool
  7132 CodeGenerator::visitSetPropertyCacheV(LSetPropertyCacheV *ins)
  7134     RegisterSet liveRegs = ins->safepoint()->liveRegs();
  7135     Register objReg = ToRegister(ins->getOperand(0));
  7136     ConstantOrRegister value = TypedOrValueRegister(ToValue(ins, LSetPropertyCacheV::Value));
  7138     return addSetPropertyCache(ins, liveRegs, objReg, ins->mir()->name(), value,
  7139                                ins->mir()->strict(), ins->mir()->needsTypeBarrier());
  7142 bool
  7143 CodeGenerator::visitSetPropertyCacheT(LSetPropertyCacheT *ins)
  7145     RegisterSet liveRegs = ins->safepoint()->liveRegs();
  7146     Register objReg = ToRegister(ins->getOperand(0));
  7147     ConstantOrRegister value;
  7149     if (ins->getOperand(1)->isConstant())
  7150         value = ConstantOrRegister(*ins->getOperand(1)->toConstant());
  7151     else
  7152         value = TypedOrValueRegister(ins->valueType(), ToAnyRegister(ins->getOperand(1)));
  7154     return addSetPropertyCache(ins, liveRegs, objReg, ins->mir()->name(), value,
  7155                                ins->mir()->strict(), ins->mir()->needsTypeBarrier());
  7158 typedef bool (*SetPropertyICFn)(JSContext *, size_t, HandleObject, HandleValue);
  7159 const VMFunction SetPropertyIC::UpdateInfo =
  7160     FunctionInfo<SetPropertyICFn>(SetPropertyIC::update);
  7162 bool
  7163 CodeGenerator::visitSetPropertyIC(OutOfLineUpdateCache *ool, DataPtr<SetPropertyIC> &ic)
  7165     LInstruction *lir = ool->lir();
  7166     saveLive(lir);
  7168     pushArg(ic->value());
  7169     pushArg(ic->object());
  7170     pushArg(Imm32(ool->getCacheIndex()));
  7171     if (!callVM(SetPropertyIC::UpdateInfo, lir))
  7172         return false;
  7173     restoreLive(lir);
  7175     masm.jump(ool->rejoin());
  7176     return true;
  7179 typedef bool (*SetPropertyParICFn)(ForkJoinContext *, size_t, HandleObject, HandleValue);
  7180 const VMFunction SetPropertyParIC::UpdateInfo =
  7181     FunctionInfo<SetPropertyParICFn>(SetPropertyParIC::update);
  7183 bool
  7184 CodeGenerator::visitSetPropertyParIC(OutOfLineUpdateCache *ool, DataPtr<SetPropertyParIC> &ic)
  7186     LInstruction *lir = ool->lir();
  7187     saveLive(lir);
  7189     pushArg(ic->value());
  7190     pushArg(ic->object());
  7191     pushArg(Imm32(ool->getCacheIndex()));
  7192     if (!callVM(SetPropertyParIC::UpdateInfo, lir))
  7193         return false;
  7194     restoreLive(lir);
  7196     masm.jump(ool->rejoin());
  7197     return true;
  7200 typedef bool (*ThrowFn)(JSContext *, HandleValue);
  7201 static const VMFunction ThrowInfoCodeGen = FunctionInfo<ThrowFn>(js::Throw);
  7203 bool
  7204 CodeGenerator::visitThrow(LThrow *lir)
  7206     pushArg(ToValue(lir, LThrow::Value));
  7207     return callVM(ThrowInfoCodeGen, lir);
  7210 typedef bool (*BitNotFn)(JSContext *, HandleValue, int *p);
  7211 typedef bool (*BitNotParFn)(ForkJoinContext *, HandleValue, int32_t *);
  7212 static const VMFunctionsModal BitNotInfo = VMFunctionsModal(
  7213     FunctionInfo<BitNotFn>(BitNot),
  7214     FunctionInfo<BitNotParFn>(BitNotPar));
  7216 bool
  7217 CodeGenerator::visitBitNotV(LBitNotV *lir)
  7219     pushArg(ToValue(lir, LBitNotV::Input));
  7220     return callVM(BitNotInfo, lir);
  7223 typedef bool (*BitopFn)(JSContext *, HandleValue, HandleValue, int *p);
  7224 typedef bool (*BitopParFn)(ForkJoinContext *, HandleValue, HandleValue, int32_t *);
  7225 static const VMFunctionsModal BitAndInfo = VMFunctionsModal(
  7226     FunctionInfo<BitopFn>(BitAnd),
  7227     FunctionInfo<BitopParFn>(BitAndPar));
  7228 static const VMFunctionsModal BitOrInfo = VMFunctionsModal(
  7229     FunctionInfo<BitopFn>(BitOr),
  7230     FunctionInfo<BitopParFn>(BitOrPar));
  7231 static const VMFunctionsModal BitXorInfo = VMFunctionsModal(
  7232     FunctionInfo<BitopFn>(BitXor),
  7233     FunctionInfo<BitopParFn>(BitXorPar));
  7234 static const VMFunctionsModal BitLhsInfo = VMFunctionsModal(
  7235     FunctionInfo<BitopFn>(BitLsh),
  7236     FunctionInfo<BitopParFn>(BitLshPar));
  7237 static const VMFunctionsModal BitRhsInfo = VMFunctionsModal(
  7238     FunctionInfo<BitopFn>(BitRsh),
  7239     FunctionInfo<BitopParFn>(BitRshPar));
  7241 bool
  7242 CodeGenerator::visitBitOpV(LBitOpV *lir)
  7244     pushArg(ToValue(lir, LBitOpV::RhsInput));
  7245     pushArg(ToValue(lir, LBitOpV::LhsInput));
  7247     switch (lir->jsop()) {
  7248       case JSOP_BITAND:
  7249         return callVM(BitAndInfo, lir);
  7250       case JSOP_BITOR:
  7251         return callVM(BitOrInfo, lir);
  7252       case JSOP_BITXOR:
  7253         return callVM(BitXorInfo, lir);
  7254       case JSOP_LSH:
  7255         return callVM(BitLhsInfo, lir);
  7256       case JSOP_RSH:
  7257         return callVM(BitRhsInfo, lir);
  7258       default:
  7259         break;
  7261     MOZ_ASSUME_UNREACHABLE("unexpected bitop");
  7264 class OutOfLineTypeOfV : public OutOfLineCodeBase<CodeGenerator>
  7266     LTypeOfV *ins_;
  7268   public:
  7269     OutOfLineTypeOfV(LTypeOfV *ins)
  7270       : ins_(ins)
  7271     { }
  7273     bool accept(CodeGenerator *codegen) {
  7274         return codegen->visitOutOfLineTypeOfV(this);
  7276     LTypeOfV *ins() const {
  7277         return ins_;
  7279 };
  7281 bool
  7282 CodeGenerator::visitTypeOfV(LTypeOfV *lir)
  7284     const ValueOperand value = ToValue(lir, LTypeOfV::Input);
  7285     Register output = ToRegister(lir->output());
  7286     Register tag = masm.splitTagForTest(value);
  7288     const JSAtomState &names = GetIonContext()->runtime->names();
  7289     Label done;
  7291     OutOfLineTypeOfV *ool = nullptr;
  7292     if (lir->mir()->inputMaybeCallableOrEmulatesUndefined()) {
  7293         // The input may be a callable object (result is "function") or may
  7294         // emulate undefined (result is "undefined"). Use an OOL path.
  7295         ool = new(alloc()) OutOfLineTypeOfV(lir);
  7296         if (!addOutOfLineCode(ool))
  7297             return false;
  7299         masm.branchTestObject(Assembler::Equal, tag, ool->entry());
  7300     } else {
  7301         // Input is not callable and does not emulate undefined, so if
  7302         // it's an object the result is always "object".
  7303         Label notObject;
  7304         masm.branchTestObject(Assembler::NotEqual, tag, &notObject);
  7305         masm.movePtr(ImmGCPtr(names.object), output);
  7306         masm.jump(&done);
  7307         masm.bind(&notObject);
  7310     Label notNumber;
  7311     masm.branchTestNumber(Assembler::NotEqual, tag, &notNumber);
  7312     masm.movePtr(ImmGCPtr(names.number), output);
  7313     masm.jump(&done);
  7314     masm.bind(&notNumber);
  7316     Label notUndefined;
  7317     masm.branchTestUndefined(Assembler::NotEqual, tag, &notUndefined);
  7318     masm.movePtr(ImmGCPtr(names.undefined), output);
  7319     masm.jump(&done);
  7320     masm.bind(&notUndefined);
  7322     Label notNull;
  7323     masm.branchTestNull(Assembler::NotEqual, tag, &notNull);
  7324     masm.movePtr(ImmGCPtr(names.object), output);
  7325     masm.jump(&done);
  7326     masm.bind(&notNull);
  7328     Label notBoolean;
  7329     masm.branchTestBoolean(Assembler::NotEqual, tag, &notBoolean);
  7330     masm.movePtr(ImmGCPtr(names.boolean), output);
  7331     masm.jump(&done);
  7332     masm.bind(&notBoolean);
  7334     masm.movePtr(ImmGCPtr(names.string), output);
  7336     masm.bind(&done);
  7337     if (ool)
  7338         masm.bind(ool->rejoin());
  7339     return true;
  7342 bool
  7343 CodeGenerator::visitOutOfLineTypeOfV(OutOfLineTypeOfV *ool)
  7345     LTypeOfV *ins = ool->ins();
  7347     ValueOperand input = ToValue(ins, LTypeOfV::Input);
  7348     Register temp = ToTempUnboxRegister(ins->tempToUnbox());
  7349     Register output = ToRegister(ins->output());
  7351     Register obj = masm.extractObject(input, temp);
  7353     saveVolatile(output);
  7354     masm.setupUnalignedABICall(2, output);
  7355     masm.passABIArg(obj);
  7356     masm.movePtr(ImmPtr(GetIonContext()->runtime), output);
  7357     masm.passABIArg(output);
  7358     masm.callWithABI(JS_FUNC_TO_DATA_PTR(void *, js::TypeOfObjectOperation));
  7359     masm.storeCallResult(output);
  7360     restoreVolatile(output);
  7362     masm.jump(ool->rejoin());
  7363     return true;
  7366 typedef bool (*ToIdFn)(JSContext *, HandleScript, jsbytecode *, HandleValue, HandleValue,
  7367                        MutableHandleValue);
  7368 static const VMFunction ToIdInfo = FunctionInfo<ToIdFn>(ToIdOperation);
  7370 bool
  7371 CodeGenerator::visitToIdV(LToIdV *lir)
  7373     Label notInt32;
  7374     FloatRegister temp = ToFloatRegister(lir->tempFloat());
  7375     const ValueOperand out = ToOutValue(lir);
  7376     ValueOperand index = ToValue(lir, LToIdV::Index);
  7378     OutOfLineCode *ool = oolCallVM(ToIdInfo, lir,
  7379                                    (ArgList(),
  7380                                    ImmGCPtr(current->mir()->info().script()),
  7381                                    ImmPtr(lir->mir()->resumePoint()->pc()),
  7382                                    ToValue(lir, LToIdV::Object),
  7383                                    ToValue(lir, LToIdV::Index)),
  7384                                    StoreValueTo(out));
  7386     Register tag = masm.splitTagForTest(index);
  7388     masm.branchTestInt32(Assembler::NotEqual, tag, &notInt32);
  7389     masm.moveValue(index, out);
  7390     masm.jump(ool->rejoin());
  7392     masm.bind(&notInt32);
  7393     masm.branchTestDouble(Assembler::NotEqual, tag, ool->entry());
  7394     masm.unboxDouble(index, temp);
  7395     masm.convertDoubleToInt32(temp, out.scratchReg(), ool->entry(), true);
  7396     masm.tagValue(JSVAL_TYPE_INT32, out.scratchReg(), out);
  7398     masm.bind(ool->rejoin());
  7399     return true;
  7402 bool
  7403 CodeGenerator::visitLoadElementV(LLoadElementV *load)
  7405     Register elements = ToRegister(load->elements());
  7406     const ValueOperand out = ToOutValue(load);
  7408     if (load->index()->isConstant())
  7409         masm.loadValue(Address(elements, ToInt32(load->index()) * sizeof(Value)), out);
  7410     else
  7411         masm.loadValue(BaseIndex(elements, ToRegister(load->index()), TimesEight), out);
  7413     if (load->mir()->needsHoleCheck()) {
  7414         Label testMagic;
  7415         masm.branchTestMagic(Assembler::Equal, out, &testMagic);
  7416         if (!bailoutFrom(&testMagic, load->snapshot()))
  7417             return false;
  7420     return true;
  7423 bool
  7424 CodeGenerator::visitLoadElementHole(LLoadElementHole *lir)
  7426     Register elements = ToRegister(lir->elements());
  7427     Register initLength = ToRegister(lir->initLength());
  7428     const ValueOperand out = ToOutValue(lir);
  7430     const MLoadElementHole *mir = lir->mir();
  7432     // If the index is out of bounds, load |undefined|. Otherwise, load the
  7433     // value.
  7434     Label undefined, done;
  7435     if (lir->index()->isConstant()) {
  7436         masm.branch32(Assembler::BelowOrEqual, initLength, Imm32(ToInt32(lir->index())), &undefined);
  7437         masm.loadValue(Address(elements, ToInt32(lir->index()) * sizeof(Value)), out);
  7438     } else {
  7439         masm.branch32(Assembler::BelowOrEqual, initLength, ToRegister(lir->index()), &undefined);
  7440         masm.loadValue(BaseIndex(elements, ToRegister(lir->index()), TimesEight), out);
  7443     // If a hole check is needed, and the value wasn't a hole, we're done.
  7444     // Otherwise, we'll load undefined.
  7445     if (lir->mir()->needsHoleCheck())
  7446         masm.branchTestMagic(Assembler::NotEqual, out, &done);
  7447     else
  7448         masm.jump(&done);
  7450     masm.bind(&undefined);
  7452     if (mir->needsNegativeIntCheck()) {
  7453         if (lir->index()->isConstant()) {
  7454             if (ToInt32(lir->index()) < 0 && !bailout(lir->snapshot()))
  7455                 return false;
  7456         } else {
  7457             Label negative;
  7458             masm.branch32(Assembler::LessThan, ToRegister(lir->index()), Imm32(0), &negative);
  7459             if (!bailoutFrom(&negative, lir->snapshot()))
  7460                 return false;
  7464     masm.moveValue(UndefinedValue(), out);
  7465     masm.bind(&done);
  7466     return true;
  7469 bool
  7470 CodeGenerator::visitLoadTypedArrayElement(LLoadTypedArrayElement *lir)
  7472     Register elements = ToRegister(lir->elements());
  7473     Register temp = lir->temp()->isBogusTemp() ? InvalidReg : ToRegister(lir->temp());
  7474     AnyRegister out = ToAnyRegister(lir->output());
  7476     int arrayType = lir->mir()->arrayType();
  7477     int width = TypedArrayObject::slotWidth(arrayType);
  7479     Label fail;
  7480     if (lir->index()->isConstant()) {
  7481         Address source(elements, ToInt32(lir->index()) * width);
  7482         masm.loadFromTypedArray(arrayType, source, out, temp, &fail);
  7483     } else {
  7484         BaseIndex source(elements, ToRegister(lir->index()), ScaleFromElemWidth(width));
  7485         masm.loadFromTypedArray(arrayType, source, out, temp, &fail);
  7488     if (fail.used() && !bailoutFrom(&fail, lir->snapshot()))
  7489         return false;
  7491     return true;
  7494 bool
  7495 CodeGenerator::visitLoadTypedArrayElementHole(LLoadTypedArrayElementHole *lir)
  7497     Register object = ToRegister(lir->object());
  7498     const ValueOperand out = ToOutValue(lir);
  7500     // Load the length.
  7501     Register scratch = out.scratchReg();
  7502     Int32Key key = ToInt32Key(lir->index());
  7503     masm.unboxInt32(Address(object, TypedArrayObject::lengthOffset()), scratch);
  7505     // Load undefined unless length > key.
  7506     Label inbounds, done;
  7507     masm.branchKey(Assembler::Above, scratch, key, &inbounds);
  7508     masm.moveValue(UndefinedValue(), out);
  7509     masm.jump(&done);
  7511     // Load the elements vector.
  7512     masm.bind(&inbounds);
  7513     masm.loadPtr(Address(object, TypedArrayObject::dataOffset()), scratch);
  7515     int arrayType = lir->mir()->arrayType();
  7516     int width = TypedArrayObject::slotWidth(arrayType);
  7518     Label fail;
  7519     if (key.isConstant()) {
  7520         Address source(scratch, key.constant() * width);
  7521         masm.loadFromTypedArray(arrayType, source, out, lir->mir()->allowDouble(),
  7522                                 out.scratchReg(), &fail);
  7523     } else {
  7524         BaseIndex source(scratch, key.reg(), ScaleFromElemWidth(width));
  7525         masm.loadFromTypedArray(arrayType, source, out, lir->mir()->allowDouble(),
  7526                                 out.scratchReg(), &fail);
  7529     if (fail.used() && !bailoutFrom(&fail, lir->snapshot()))
  7530         return false;
  7532     masm.bind(&done);
  7533     return true;
  7536 template <typename T>
  7537 static inline void
  7538 StoreToTypedArray(MacroAssembler &masm, int arrayType, const LAllocation *value, const T &dest)
  7540     if (arrayType == ScalarTypeDescr::TYPE_FLOAT32 ||
  7541         arrayType == ScalarTypeDescr::TYPE_FLOAT64)
  7543         masm.storeToTypedFloatArray(arrayType, ToFloatRegister(value), dest);
  7544     } else {
  7545         if (value->isConstant())
  7546             masm.storeToTypedIntArray(arrayType, Imm32(ToInt32(value)), dest);
  7547         else
  7548             masm.storeToTypedIntArray(arrayType, ToRegister(value), dest);
  7552 bool
  7553 CodeGenerator::visitStoreTypedArrayElement(LStoreTypedArrayElement *lir)
  7555     Register elements = ToRegister(lir->elements());
  7556     const LAllocation *value = lir->value();
  7558     int arrayType = lir->mir()->arrayType();
  7559     int width = TypedArrayObject::slotWidth(arrayType);
  7561     if (lir->index()->isConstant()) {
  7562         Address dest(elements, ToInt32(lir->index()) * width);
  7563         StoreToTypedArray(masm, arrayType, value, dest);
  7564     } else {
  7565         BaseIndex dest(elements, ToRegister(lir->index()), ScaleFromElemWidth(width));
  7566         StoreToTypedArray(masm, arrayType, value, dest);
  7569     return true;
  7572 bool
  7573 CodeGenerator::visitStoreTypedArrayElementHole(LStoreTypedArrayElementHole *lir)
  7575     Register elements = ToRegister(lir->elements());
  7576     const LAllocation *value = lir->value();
  7578     int arrayType = lir->mir()->arrayType();
  7579     int width = TypedArrayObject::slotWidth(arrayType);
  7581     bool guardLength = true;
  7582     if (lir->index()->isConstant() && lir->length()->isConstant()) {
  7583         uint32_t idx = ToInt32(lir->index());
  7584         uint32_t len = ToInt32(lir->length());
  7585         if (idx >= len)
  7586             return true;
  7587         guardLength = false;
  7589     Label skip;
  7590     if (lir->index()->isConstant()) {
  7591         uint32_t idx = ToInt32(lir->index());
  7592         if (guardLength)
  7593             masm.branch32(Assembler::BelowOrEqual, ToOperand(lir->length()), Imm32(idx), &skip);
  7594         Address dest(elements, idx * width);
  7595         StoreToTypedArray(masm, arrayType, value, dest);
  7596     } else {
  7597         Register idxReg = ToRegister(lir->index());
  7598         JS_ASSERT(guardLength);
  7599         if (lir->length()->isConstant())
  7600             masm.branch32(Assembler::AboveOrEqual, idxReg, Imm32(ToInt32(lir->length())), &skip);
  7601         else
  7602             masm.branch32(Assembler::BelowOrEqual, ToOperand(lir->length()), idxReg, &skip);
  7603         BaseIndex dest(elements, ToRegister(lir->index()), ScaleFromElemWidth(width));
  7604         StoreToTypedArray(masm, arrayType, value, dest);
  7606     if (guardLength)
  7607         masm.bind(&skip);
  7609     return true;
  7612 bool
  7613 CodeGenerator::visitClampIToUint8(LClampIToUint8 *lir)
  7615     Register output = ToRegister(lir->output());
  7616     JS_ASSERT(output == ToRegister(lir->input()));
  7617     masm.clampIntToUint8(output);
  7618     return true;
  7621 bool
  7622 CodeGenerator::visitClampDToUint8(LClampDToUint8 *lir)
  7624     FloatRegister input = ToFloatRegister(lir->input());
  7625     Register output = ToRegister(lir->output());
  7626     masm.clampDoubleToUint8(input, output);
  7627     return true;
  7630 bool
  7631 CodeGenerator::visitClampVToUint8(LClampVToUint8 *lir)
  7633     ValueOperand operand = ToValue(lir, LClampVToUint8::Input);
  7634     FloatRegister tempFloat = ToFloatRegister(lir->tempFloat());
  7635     Register output = ToRegister(lir->output());
  7636     MDefinition *input = lir->mir()->input();
  7638     Label *stringEntry, *stringRejoin;
  7639     if (input->mightBeType(MIRType_String)) {
  7640         OutOfLineCode *oolString = oolCallVM(StringToNumberInfo, lir, (ArgList(), output),
  7641                                              StoreFloatRegisterTo(tempFloat));
  7642         if (!oolString)
  7643             return false;
  7644         stringEntry = oolString->entry();
  7645         stringRejoin = oolString->rejoin();
  7646     } else {
  7647         stringEntry = nullptr;
  7648         stringRejoin = nullptr;
  7651     Label fails;
  7652     masm.clampValueToUint8(operand, input,
  7653                            stringEntry, stringRejoin,
  7654                            output, tempFloat, output, &fails);
  7656     if (!bailoutFrom(&fails, lir->snapshot()))
  7657         return false;
  7659     return true;
  7662 typedef bool (*OperatorInFn)(JSContext *, HandleValue, HandleObject, bool *);
  7663 static const VMFunction OperatorInInfo = FunctionInfo<OperatorInFn>(OperatorIn);
  7665 bool
  7666 CodeGenerator::visitIn(LIn *ins)
  7668     pushArg(ToRegister(ins->rhs()));
  7669     pushArg(ToValue(ins, LIn::LHS));
  7671     return callVM(OperatorInInfo, ins);
  7674 typedef bool (*OperatorInIFn)(JSContext *, uint32_t, HandleObject, bool *);
  7675 static const VMFunction OperatorInIInfo = FunctionInfo<OperatorInIFn>(OperatorInI);
  7677 bool
  7678 CodeGenerator::visitInArray(LInArray *lir)
  7680     const MInArray *mir = lir->mir();
  7681     Register elements = ToRegister(lir->elements());
  7682     Register initLength = ToRegister(lir->initLength());
  7683     Register output = ToRegister(lir->output());
  7685     // When the array is not packed we need to do a hole check in addition to the bounds check.
  7686     Label falseBranch, done, trueBranch;
  7688     OutOfLineCode *ool = nullptr;
  7689     Label* failedInitLength = &falseBranch;
  7691     if (lir->index()->isConstant()) {
  7692         int32_t index = ToInt32(lir->index());
  7694         JS_ASSERT_IF(index < 0, mir->needsNegativeIntCheck());
  7695         if (mir->needsNegativeIntCheck()) {
  7696             ool = oolCallVM(OperatorInIInfo, lir,
  7697                             (ArgList(), Imm32(index), ToRegister(lir->object())),
  7698                             StoreRegisterTo(output));
  7699             failedInitLength = ool->entry();
  7702         masm.branch32(Assembler::BelowOrEqual, initLength, Imm32(index), failedInitLength);
  7703         if (mir->needsHoleCheck()) {
  7704             Address address = Address(elements, index * sizeof(Value));
  7705             masm.branchTestMagic(Assembler::Equal, address, &falseBranch);
  7707     } else {
  7708         Label negativeIntCheck;
  7709         Register index = ToRegister(lir->index());
  7711         if (mir->needsNegativeIntCheck())
  7712             failedInitLength = &negativeIntCheck;
  7714         masm.branch32(Assembler::BelowOrEqual, initLength, index, failedInitLength);
  7715         if (mir->needsHoleCheck()) {
  7716             BaseIndex address = BaseIndex(elements, ToRegister(lir->index()), TimesEight);
  7717             masm.branchTestMagic(Assembler::Equal, address, &falseBranch);
  7719         masm.jump(&trueBranch);
  7721         if (mir->needsNegativeIntCheck()) {
  7722             masm.bind(&negativeIntCheck);
  7723             ool = oolCallVM(OperatorInIInfo, lir,
  7724                             (ArgList(), index, ToRegister(lir->object())),
  7725                             StoreRegisterTo(output));
  7727             masm.branch32(Assembler::LessThan, index, Imm32(0), ool->entry());
  7728             masm.jump(&falseBranch);
  7732     masm.bind(&trueBranch);
  7733     masm.move32(Imm32(1), output);
  7734     masm.jump(&done);
  7736     masm.bind(&falseBranch);
  7737     masm.move32(Imm32(0), output);
  7738     masm.bind(&done);
  7740     if (ool)
  7741         masm.bind(ool->rejoin());
  7743     return true;
  7746 bool
  7747 CodeGenerator::visitInstanceOfO(LInstanceOfO *ins)
  7749     return emitInstanceOf(ins, ins->mir()->prototypeObject());
  7752 bool
  7753 CodeGenerator::visitInstanceOfV(LInstanceOfV *ins)
  7755     return emitInstanceOf(ins, ins->mir()->prototypeObject());
  7758 // Wrap IsDelegateOfObject, which takes a JSObject*, not a HandleObject
  7759 static bool
  7760 IsDelegateObject(JSContext *cx, HandleObject protoObj, HandleObject obj, bool *res)
  7762     return IsDelegateOfObject(cx, protoObj, obj, res);
  7765 typedef bool (*IsDelegateObjectFn)(JSContext *, HandleObject, HandleObject, bool *);
  7766 static const VMFunction IsDelegateObjectInfo = FunctionInfo<IsDelegateObjectFn>(IsDelegateObject);
  7768 bool
  7769 CodeGenerator::emitInstanceOf(LInstruction *ins, JSObject *prototypeObject)
  7771     // This path implements fun_hasInstance when the function's prototype is
  7772     // known to be prototypeObject.
  7774     Label done;
  7775     Register output = ToRegister(ins->getDef(0));
  7777     // If the lhs is a primitive, the result is false.
  7778     Register objReg;
  7779     if (ins->isInstanceOfV()) {
  7780         Label isObject;
  7781         ValueOperand lhsValue = ToValue(ins, LInstanceOfV::LHS);
  7782         masm.branchTestObject(Assembler::Equal, lhsValue, &isObject);
  7783         masm.mov(ImmWord(0), output);
  7784         masm.jump(&done);
  7785         masm.bind(&isObject);
  7786         objReg = masm.extractObject(lhsValue, output);
  7787     } else {
  7788         objReg = ToRegister(ins->toInstanceOfO()->lhs());
  7791     // Crawl the lhs's prototype chain in a loop to search for prototypeObject.
  7792     // This follows the main loop of js::IsDelegate, though additionally breaks
  7793     // out of the loop on Proxy::LazyProto.
  7795     // Load the lhs's prototype.
  7796     masm.loadObjProto(objReg, output);
  7798     Label testLazy;
  7800         Label loopPrototypeChain;
  7801         masm.bind(&loopPrototypeChain);
  7803         // Test for the target prototype object.
  7804         Label notPrototypeObject;
  7805         masm.branchPtr(Assembler::NotEqual, output, ImmGCPtr(prototypeObject), &notPrototypeObject);
  7806         masm.mov(ImmWord(1), output);
  7807         masm.jump(&done);
  7808         masm.bind(&notPrototypeObject);
  7810         JS_ASSERT(uintptr_t(TaggedProto::LazyProto) == 1);
  7812         // Test for nullptr or Proxy::LazyProto
  7813         masm.branchPtr(Assembler::BelowOrEqual, output, ImmWord(1), &testLazy);
  7815         // Load the current object's prototype.
  7816         masm.loadObjProto(output, output);
  7818         masm.jump(&loopPrototypeChain);
  7821     // Make a VM call if an object with a lazy proto was found on the prototype
  7822     // chain. This currently occurs only for cross compartment wrappers, which
  7823     // we do not expect to be compared with non-wrapper functions from this
  7824     // compartment. Otherwise, we stopped on a nullptr prototype and the output
  7825     // register is already correct.
  7827     OutOfLineCode *ool = oolCallVM(IsDelegateObjectInfo, ins,
  7828                                    (ArgList(), ImmGCPtr(prototypeObject), objReg),
  7829                                    StoreRegisterTo(output));
  7831     // Regenerate the original lhs object for the VM call.
  7832     Label regenerate, *lazyEntry;
  7833     if (objReg != output) {
  7834         lazyEntry = ool->entry();
  7835     } else {
  7836         masm.bind(&regenerate);
  7837         lazyEntry = &regenerate;
  7838         if (ins->isInstanceOfV()) {
  7839             ValueOperand lhsValue = ToValue(ins, LInstanceOfV::LHS);
  7840             objReg = masm.extractObject(lhsValue, output);
  7841         } else {
  7842             objReg = ToRegister(ins->toInstanceOfO()->lhs());
  7844         JS_ASSERT(objReg == output);
  7845         masm.jump(ool->entry());
  7848     masm.bind(&testLazy);
  7849     masm.branchPtr(Assembler::Equal, output, ImmWord(1), lazyEntry);
  7851     masm.bind(&done);
  7852     masm.bind(ool->rejoin());
  7853     return true;
  7856 typedef bool (*HasInstanceFn)(JSContext *, HandleObject, HandleValue, bool *);
  7857 static const VMFunction HasInstanceInfo = FunctionInfo<HasInstanceFn>(js::HasInstance);
  7859 bool
  7860 CodeGenerator::visitCallInstanceOf(LCallInstanceOf *ins)
  7862     ValueOperand lhs = ToValue(ins, LCallInstanceOf::LHS);
  7863     Register rhs = ToRegister(ins->rhs());
  7864     JS_ASSERT(ToRegister(ins->output()) == ReturnReg);
  7866     pushArg(lhs);
  7867     pushArg(rhs);
  7868     return callVM(HasInstanceInfo, ins);
  7871 bool
  7872 CodeGenerator::visitGetDOMProperty(LGetDOMProperty *ins)
  7874     const Register JSContextReg = ToRegister(ins->getJSContextReg());
  7875     const Register ObjectReg = ToRegister(ins->getObjectReg());
  7876     const Register PrivateReg = ToRegister(ins->getPrivReg());
  7877     const Register ValueReg = ToRegister(ins->getValueReg());
  7879     DebugOnly<uint32_t> initialStack = masm.framePushed();
  7881     masm.checkStackAlignment();
  7883     // Make space for the outparam.  Pre-initialize it to UndefinedValue so we
  7884     // can trace it at GC time.
  7885     masm.Push(UndefinedValue());
  7886     // We pass the pointer to our out param as an instance of
  7887     // JSJitGetterCallArgs, since on the binary level it's the same thing.
  7888     JS_STATIC_ASSERT(sizeof(JSJitGetterCallArgs) == sizeof(Value*));
  7889     masm.movePtr(StackPointer, ValueReg);
  7891     masm.Push(ObjectReg);
  7893     // GetReservedSlot(obj, DOM_OBJECT_SLOT).toPrivate()
  7894     masm.loadPrivate(Address(ObjectReg, JSObject::getFixedSlotOffset(0)), PrivateReg);
  7896     // Rooting will happen at GC time.
  7897     masm.movePtr(StackPointer, ObjectReg);
  7899     uint32_t safepointOffset;
  7900     if (!masm.buildFakeExitFrame(JSContextReg, &safepointOffset))
  7901         return false;
  7902     masm.enterFakeExitFrame(ION_FRAME_DOMGETTER);
  7904     if (!markSafepointAt(safepointOffset, ins))
  7905         return false;
  7907     masm.setupUnalignedABICall(4, JSContextReg);
  7909     masm.loadJSContext(JSContextReg);
  7911     masm.passABIArg(JSContextReg);
  7912     masm.passABIArg(ObjectReg);
  7913     masm.passABIArg(PrivateReg);
  7914     masm.passABIArg(ValueReg);
  7915     masm.callWithABI(JS_FUNC_TO_DATA_PTR(void *, ins->mir()->fun()));
  7917     if (ins->mir()->isInfallible()) {
  7918         masm.loadValue(Address(StackPointer, IonDOMExitFrameLayout::offsetOfResult()),
  7919                        JSReturnOperand);
  7920     } else {
  7921         masm.branchIfFalseBool(ReturnReg, masm.exceptionLabel());
  7923         masm.loadValue(Address(StackPointer, IonDOMExitFrameLayout::offsetOfResult()),
  7924                        JSReturnOperand);
  7926     masm.adjustStack(IonDOMExitFrameLayout::Size());
  7928     JS_ASSERT(masm.framePushed() == initialStack);
  7929     return true;
  7932 bool
  7933 CodeGenerator::visitGetDOMMember(LGetDOMMember *ins)
  7935     // It's simple to duplicate visitLoadFixedSlotV here than it is to try to
  7936     // use an LLoadFixedSlotV or some subclass of it for this case: that would
  7937     // require us to have MGetDOMMember inherit from MLoadFixedSlot, and then
  7938     // we'd have to duplicate a bunch of stuff we now get for free from
  7939     // MGetDOMProperty.
  7940     Register object = ToRegister(ins->object());
  7941     size_t slot = ins->mir()->domMemberSlotIndex();
  7942     ValueOperand result = GetValueOutput(ins);
  7944     masm.loadValue(Address(object, JSObject::getFixedSlotOffset(slot)), result);
  7945     return true;
  7948 bool
  7949 CodeGenerator::visitSetDOMProperty(LSetDOMProperty *ins)
  7951     const Register JSContextReg = ToRegister(ins->getJSContextReg());
  7952     const Register ObjectReg = ToRegister(ins->getObjectReg());
  7953     const Register PrivateReg = ToRegister(ins->getPrivReg());
  7954     const Register ValueReg = ToRegister(ins->getValueReg());
  7956     DebugOnly<uint32_t> initialStack = masm.framePushed();
  7958     masm.checkStackAlignment();
  7960     // Push the argument. Rooting will happen at GC time.
  7961     ValueOperand argVal = ToValue(ins, LSetDOMProperty::Value);
  7962     masm.Push(argVal);
  7963     // We pass the pointer to our out param as an instance of
  7964     // JSJitGetterCallArgs, since on the binary level it's the same thing.
  7965     JS_STATIC_ASSERT(sizeof(JSJitSetterCallArgs) == sizeof(Value*));
  7966     masm.movePtr(StackPointer, ValueReg);
  7968     masm.Push(ObjectReg);
  7970     // GetReservedSlot(obj, DOM_OBJECT_SLOT).toPrivate()
  7971     masm.loadPrivate(Address(ObjectReg, JSObject::getFixedSlotOffset(0)), PrivateReg);
  7973     // Rooting will happen at GC time.
  7974     masm.movePtr(StackPointer, ObjectReg);
  7976     uint32_t safepointOffset;
  7977     if (!masm.buildFakeExitFrame(JSContextReg, &safepointOffset))
  7978         return false;
  7979     masm.enterFakeExitFrame(ION_FRAME_DOMSETTER);
  7981     if (!markSafepointAt(safepointOffset, ins))
  7982         return false;
  7984     masm.setupUnalignedABICall(4, JSContextReg);
  7986     masm.loadJSContext(JSContextReg);
  7988     masm.passABIArg(JSContextReg);
  7989     masm.passABIArg(ObjectReg);
  7990     masm.passABIArg(PrivateReg);
  7991     masm.passABIArg(ValueReg);
  7992     masm.callWithABI(JS_FUNC_TO_DATA_PTR(void *, ins->mir()->fun()));
  7994     masm.branchIfFalseBool(ReturnReg, masm.exceptionLabel());
  7996     masm.adjustStack(IonDOMExitFrameLayout::Size());
  7998     JS_ASSERT(masm.framePushed() == initialStack);
  7999     return true;
  8002 typedef bool(*SPSFn)(JSContext *, HandleScript);
  8003 static const VMFunction SPSEnterInfo = FunctionInfo<SPSFn>(SPSEnter);
  8004 static const VMFunction SPSExitInfo = FunctionInfo<SPSFn>(SPSExit);
  8006 bool
  8007 CodeGenerator::visitProfilerStackOp(LProfilerStackOp *lir)
  8009     Register temp = ToRegister(lir->temp()->output());
  8010     bool inlinedFunction = lir->inlineLevel() > 0;
  8012     switch (lir->type()) {
  8013         case MProfilerStackOp::InlineEnter:
  8014             // Multiple scripts can be inlined at one depth, but there is only
  8015             // one InlineExit node to signify this. To deal with this, if we
  8016             // reach the entry of another inline script on the same level, then
  8017             // just reset the sps metadata about the frame. We must balance
  8018             // calls to leave()/reenter(), so perform the balance without
  8019             // emitting any instrumentation. Technically the previous inline
  8020             // call at this same depth has reentered, but the instrumentation
  8021             // will be emitted at the common join point for all inlines at the
  8022             // same depth.
  8023             if (sps_.inliningDepth() == lir->inlineLevel()) {
  8024                 sps_.leaveInlineFrame();
  8025                 sps_.skipNextReenter();
  8026                 sps_.reenter(masm, temp);
  8029             sps_.leave(masm, temp, /* inlinedFunction = */ true);
  8030             if (!sps_.enterInlineFrame())
  8031                 return false;
  8032             // fallthrough
  8034         case MProfilerStackOp::Enter:
  8035             if (gen->options.spsSlowAssertionsEnabled()) {
  8036                 if (!inlinedFunction || js_JitOptions.profileInlineFrames) {
  8037                     saveLive(lir);
  8038                     pushArg(ImmGCPtr(lir->script()));
  8039                     if (!callVM(SPSEnterInfo, lir))
  8040                         return false;
  8041                     restoreLive(lir);
  8043                 sps_.pushManual(lir->script(), masm, temp, /* inlinedFunction = */ inlinedFunction);
  8044                 return true;
  8047             return sps_.push(lir->script(), masm, temp, /* inlinedFunction = */ inlinedFunction);
  8049         case MProfilerStackOp::InlineExit:
  8050             // all inline returns were covered with ::Exit, so we just need to
  8051             // maintain the state of inline frames currently active and then
  8052             // reenter the caller
  8053             sps_.leaveInlineFrame();
  8054             sps_.reenter(masm, temp, /* inlinedFunction = */ true);
  8055             return true;
  8057         case MProfilerStackOp::Exit:
  8058             if (gen->options.spsSlowAssertionsEnabled()) {
  8059                 if (!inlinedFunction || js_JitOptions.profileInlineFrames) {
  8060                     saveLive(lir);
  8061                     pushArg(ImmGCPtr(lir->script()));
  8062                     // Once we've exited, then we shouldn't emit instrumentation for
  8063                     // the corresponding reenter() because we no longer have a
  8064                     // frame.
  8065                     sps_.skipNextReenter();
  8066                     if (!callVM(SPSExitInfo, lir))
  8067                         return false;
  8068                     restoreLive(lir);
  8070                 return true;
  8073             sps_.pop(masm, temp, /* inlinedFunction = */ inlinedFunction);
  8074             return true;
  8076         default:
  8077             MOZ_ASSUME_UNREACHABLE("invalid LProfilerStackOp type");
  8081 bool
  8082 CodeGenerator::visitOutOfLineAbortPar(OutOfLineAbortPar *ool)
  8084     ParallelBailoutCause cause = ool->cause();
  8085     jsbytecode *bytecode = ool->bytecode();
  8087     masm.move32(Imm32(cause), CallTempReg0);
  8088     loadOutermostJSScript(CallTempReg1);
  8089     loadJSScriptForBlock(ool->basicBlock(), CallTempReg2);
  8090     masm.movePtr(ImmPtr(bytecode), CallTempReg3);
  8092     masm.setupUnalignedABICall(4, CallTempReg4);
  8093     masm.passABIArg(CallTempReg0);
  8094     masm.passABIArg(CallTempReg1);
  8095     masm.passABIArg(CallTempReg2);
  8096     masm.passABIArg(CallTempReg3);
  8097     masm.callWithABI(JS_FUNC_TO_DATA_PTR(void *, AbortPar));
  8099     masm.moveValue(MagicValue(JS_ION_ERROR), JSReturnOperand);
  8100     masm.jump(&returnLabel_);
  8101     return true;
  8104 bool
  8105 CodeGenerator::visitIsCallable(LIsCallable *ins)
  8107     Register object = ToRegister(ins->object());
  8108     Register output = ToRegister(ins->output());
  8110     masm.loadObjClass(object, output);
  8112     // An object is callable iff (is<JSFunction>() || getClass()->call).
  8113     Label notFunction, done, notCall;
  8114     masm.branchPtr(Assembler::NotEqual, output, ImmPtr(&JSFunction::class_), &notFunction);
  8115     masm.move32(Imm32(1), output);
  8116     masm.jump(&done);
  8118     masm.bind(&notFunction);
  8119     masm.cmpPtrSet(Assembler::NonZero, Address(output, offsetof(js::Class, call)), ImmPtr(nullptr), output);
  8120     masm.bind(&done);
  8122     return true;
  8125 void
  8126 CodeGenerator::loadOutermostJSScript(Register reg)
  8128     // The "outermost" JSScript means the script that we are compiling
  8129     // basically; this is not always the script associated with the
  8130     // current basic block, which might be an inlined script.
  8132     MIRGraph &graph = current->mir()->graph();
  8133     MBasicBlock *entryBlock = graph.entryBlock();
  8134     masm.movePtr(ImmGCPtr(entryBlock->info().script()), reg);
  8137 void
  8138 CodeGenerator::loadJSScriptForBlock(MBasicBlock *block, Register reg)
  8140     // The current JSScript means the script for the current
  8141     // basic block. This may be an inlined script.
  8143     JSScript *script = block->info().script();
  8144     masm.movePtr(ImmGCPtr(script), reg);
  8147 bool
  8148 CodeGenerator::visitOutOfLinePropagateAbortPar(OutOfLinePropagateAbortPar *ool)
  8150     loadOutermostJSScript(CallTempReg0);
  8151     loadJSScriptForBlock(ool->lir()->mirRaw()->block(), CallTempReg1);
  8153     masm.setupUnalignedABICall(2, CallTempReg2);
  8154     masm.passABIArg(CallTempReg0);
  8155     masm.passABIArg(CallTempReg1);
  8156     masm.callWithABI(JS_FUNC_TO_DATA_PTR(void *, PropagateAbortPar));
  8158     masm.moveValue(MagicValue(JS_ION_ERROR), JSReturnOperand);
  8159     masm.jump(&returnLabel_);
  8160     return true;
  8163 bool
  8164 CodeGenerator::visitHaveSameClass(LHaveSameClass *ins)
  8166     Register lhs = ToRegister(ins->lhs());
  8167     Register rhs = ToRegister(ins->rhs());
  8168     Register temp = ToRegister(ins->getTemp(0));
  8169     Register output = ToRegister(ins->output());
  8171     masm.loadObjClass(lhs, temp);
  8172     masm.loadObjClass(rhs, output);
  8173     masm.cmpPtrSet(Assembler::Equal, temp, output, output);
  8175     return true;
  8178 bool
  8179 CodeGenerator::visitHasClass(LHasClass *ins)
  8181     Register lhs = ToRegister(ins->lhs());
  8182     Register output = ToRegister(ins->output());
  8184     masm.loadObjClass(lhs, output);
  8185     masm.cmpPtrSet(Assembler::Equal, output, ImmPtr(ins->mir()->getClass()), output);
  8187     return true;
  8190 bool
  8191 CodeGenerator::visitAsmJSCall(LAsmJSCall *ins)
  8193     MAsmJSCall *mir = ins->mir();
  8195 #if defined(JS_CODEGEN_ARM)
  8196     if (!useHardFpABI() && mir->callee().which() == MAsmJSCall::Callee::Builtin) {
  8197         for (unsigned i = 0, e = ins->numOperands(); i < e; i++) {
  8198             LAllocation *a = ins->getOperand(i);
  8199             if (a->isFloatReg()) {
  8200                 FloatRegister fr = ToFloatRegister(a);
  8201                 int srcId = fr.code() * 2;
  8202                 masm.ma_vxfer(fr, Register::FromCode(srcId), Register::FromCode(srcId+1));
  8206 #endif
  8208    if (mir->spIncrement())
  8209         masm.freeStack(mir->spIncrement());
  8211    JS_ASSERT((AlignmentAtPrologue +  masm.framePushed()) % StackAlignment == 0);
  8213 #ifdef DEBUG
  8214     Label ok;
  8215     JS_ASSERT(IsPowerOfTwo(StackAlignment));
  8216     masm.branchTestPtr(Assembler::Zero, StackPointer, Imm32(StackAlignment - 1), &ok);
  8217     masm.assumeUnreachable("Stack should be aligned.");
  8218     masm.bind(&ok);
  8219 #endif
  8221     MAsmJSCall::Callee callee = mir->callee();
  8222     switch (callee.which()) {
  8223       case MAsmJSCall::Callee::Internal:
  8224         masm.call(mir->desc(), callee.internal());
  8225         break;
  8226       case MAsmJSCall::Callee::Dynamic:
  8227         masm.call(mir->desc(), ToRegister(ins->getOperand(mir->dynamicCalleeOperandIndex())));
  8228         break;
  8229       case MAsmJSCall::Callee::Builtin:
  8230         masm.call(mir->desc(), callee.builtin());
  8231         break;
  8234     if (mir->spIncrement())
  8235         masm.reserveStack(mir->spIncrement());
  8237     postAsmJSCall(ins);
  8238     return true;
  8241 bool
  8242 CodeGenerator::visitAsmJSParameter(LAsmJSParameter *lir)
  8244     return true;
  8247 bool
  8248 CodeGenerator::visitAsmJSReturn(LAsmJSReturn *lir)
  8250     // Don't emit a jump to the return label if this is the last block.
  8251     if (current->mir() != *gen->graph().poBegin())
  8252         masm.jump(&returnLabel_);
  8253     return true;
  8256 bool
  8257 CodeGenerator::visitAsmJSVoidReturn(LAsmJSVoidReturn *lir)
  8259     // Don't emit a jump to the return label if this is the last block.
  8260     if (current->mir() != *gen->graph().poBegin())
  8261         masm.jump(&returnLabel_);
  8262     return true;
  8265 bool
  8266 CodeGenerator::emitAssertRangeI(const Range *r, Register input)
  8268     // Check the lower bound.
  8269     if (r->hasInt32LowerBound() && r->lower() > INT32_MIN) {
  8270         Label success;
  8271         masm.branch32(Assembler::GreaterThanOrEqual, input, Imm32(r->lower()), &success);
  8272         masm.assumeUnreachable("Integer input should be equal or higher than Lowerbound.");
  8273         masm.bind(&success);
  8276     // Check the upper bound.
  8277     if (r->hasInt32UpperBound() && r->upper() < INT32_MAX) {
  8278         Label success;
  8279         masm.branch32(Assembler::LessThanOrEqual, input, Imm32(r->upper()), &success);
  8280         masm.assumeUnreachable("Integer input should be lower or equal than Upperbound.");
  8281         masm.bind(&success);
  8284     // For r->canHaveFractionalPart() and r->exponent(), there's nothing to check, because
  8285     // if we ended up in the integer range checking code, the value is already
  8286     // in an integer register in the integer range.
  8288     return true;
  8291 bool
  8292 CodeGenerator::emitAssertRangeD(const Range *r, FloatRegister input, FloatRegister temp)
  8294     // Check the lower bound.
  8295     if (r->hasInt32LowerBound()) {
  8296         Label success;
  8297         masm.loadConstantDouble(r->lower(), temp);
  8298         if (r->canBeNaN())
  8299             masm.branchDouble(Assembler::DoubleUnordered, input, input, &success);
  8300         masm.branchDouble(Assembler::DoubleGreaterThanOrEqual, input, temp, &success);
  8301         masm.assumeUnreachable("Double input should be equal or higher than Lowerbound.");
  8302         masm.bind(&success);
  8304     // Check the upper bound.
  8305     if (r->hasInt32UpperBound()) {
  8306         Label success;
  8307         masm.loadConstantDouble(r->upper(), temp);
  8308         if (r->canBeNaN())
  8309             masm.branchDouble(Assembler::DoubleUnordered, input, input, &success);
  8310         masm.branchDouble(Assembler::DoubleLessThanOrEqual, input, temp, &success);
  8311         masm.assumeUnreachable("Double input should be lower or equal than Upperbound.");
  8312         masm.bind(&success);
  8315     // This code does not yet check r->canHaveFractionalPart(). This would require new
  8316     // assembler interfaces to make rounding instructions available.
  8318     if (!r->hasInt32Bounds() && !r->canBeInfiniteOrNaN() &&
  8319         r->exponent() < FloatingPoint<double>::ExponentBias)
  8321         // Check the bounds implied by the maximum exponent.
  8322         Label exponentLoOk;
  8323         masm.loadConstantDouble(pow(2.0, r->exponent() + 1), temp);
  8324         masm.branchDouble(Assembler::DoubleUnordered, input, input, &exponentLoOk);
  8325         masm.branchDouble(Assembler::DoubleLessThanOrEqual, input, temp, &exponentLoOk);
  8326         masm.assumeUnreachable("Check for exponent failed.");
  8327         masm.bind(&exponentLoOk);
  8329         Label exponentHiOk;
  8330         masm.loadConstantDouble(-pow(2.0, r->exponent() + 1), temp);
  8331         masm.branchDouble(Assembler::DoubleUnordered, input, input, &exponentHiOk);
  8332         masm.branchDouble(Assembler::DoubleGreaterThanOrEqual, input, temp, &exponentHiOk);
  8333         masm.assumeUnreachable("Check for exponent failed.");
  8334         masm.bind(&exponentHiOk);
  8335     } else if (!r->hasInt32Bounds() && !r->canBeNaN()) {
  8336         // If we think the value can't be NaN, check that it isn't.
  8337         Label notnan;
  8338         masm.branchDouble(Assembler::DoubleOrdered, input, input, &notnan);
  8339         masm.assumeUnreachable("Input shouldn't be NaN.");
  8340         masm.bind(&notnan);
  8342         // If we think the value also can't be an infinity, check that it isn't.
  8343         if (!r->canBeInfiniteOrNaN()) {
  8344             Label notposinf;
  8345             masm.loadConstantDouble(PositiveInfinity<double>(), temp);
  8346             masm.branchDouble(Assembler::DoubleLessThan, input, temp, &notposinf);
  8347             masm.assumeUnreachable("Input shouldn't be +Inf.");
  8348             masm.bind(&notposinf);
  8350             Label notneginf;
  8351             masm.loadConstantDouble(NegativeInfinity<double>(), temp);
  8352             masm.branchDouble(Assembler::DoubleGreaterThan, input, temp, &notneginf);
  8353             masm.assumeUnreachable("Input shouldn't be -Inf.");
  8354             masm.bind(&notneginf);
  8358     return true;
  8361 bool
  8362 CodeGenerator::visitAssertRangeI(LAssertRangeI *ins)
  8364     Register input = ToRegister(ins->input());
  8365     const Range *r = ins->range();
  8367     return emitAssertRangeI(r, input);
  8370 bool
  8371 CodeGenerator::visitAssertRangeD(LAssertRangeD *ins)
  8373     FloatRegister input = ToFloatRegister(ins->input());
  8374     FloatRegister temp = ToFloatRegister(ins->temp());
  8375     const Range *r = ins->range();
  8377     return emitAssertRangeD(r, input, temp);
  8380 bool
  8381 CodeGenerator::visitAssertRangeF(LAssertRangeF *ins)
  8383     FloatRegister input = ToFloatRegister(ins->input());
  8384     FloatRegister temp = ToFloatRegister(ins->temp());
  8385     const Range *r = ins->range();
  8387     masm.convertFloat32ToDouble(input, input);
  8388     bool success = emitAssertRangeD(r, input, temp);
  8389     masm.convertDoubleToFloat32(input, input);
  8390     return success;
  8393 bool
  8394 CodeGenerator::visitAssertRangeV(LAssertRangeV *ins)
  8396     const Range *r = ins->range();
  8397     const ValueOperand value = ToValue(ins, LAssertRangeV::Input);
  8398     Register tag = masm.splitTagForTest(value);
  8399     Label done;
  8402         Label isNotInt32;
  8403         masm.branchTestInt32(Assembler::NotEqual, tag, &isNotInt32);
  8404         Register unboxInt32 = ToTempUnboxRegister(ins->temp());
  8405         Register input = masm.extractInt32(value, unboxInt32);
  8406         emitAssertRangeI(r, input);
  8407         masm.jump(&done);
  8408         masm.bind(&isNotInt32);
  8412         Label isNotDouble;
  8413         masm.branchTestDouble(Assembler::NotEqual, tag, &isNotDouble);
  8414         FloatRegister input = ToFloatRegister(ins->floatTemp1());
  8415         FloatRegister temp = ToFloatRegister(ins->floatTemp2());
  8416         masm.unboxDouble(value, input);
  8417         emitAssertRangeD(r, input, temp);
  8418         masm.jump(&done);
  8419         masm.bind(&isNotDouble);
  8422     masm.assumeUnreachable("Incorrect range for Value.");
  8423     masm.bind(&done);
  8424     return true;
  8427 typedef bool (*RecompileFn)(JSContext *);
  8428 static const VMFunction RecompileFnInfo = FunctionInfo<RecompileFn>(Recompile);
  8430 bool
  8431 CodeGenerator::visitRecompileCheck(LRecompileCheck *ins)
  8433     Label done;
  8434     Register tmp = ToRegister(ins->scratch());
  8435     OutOfLineCode *ool = oolCallVM(RecompileFnInfo, ins, (ArgList()), StoreRegisterTo(tmp));
  8437     // Check if usecount is high enough.
  8438     masm.movePtr(ImmPtr(ins->mir()->script()->addressOfUseCount()), tmp);
  8439     Address ptr(tmp, 0);
  8440     masm.add32(Imm32(1), tmp);
  8441     masm.branch32(Assembler::BelowOrEqual, ptr, Imm32(ins->mir()->useCount()), &done);
  8443     // Check if not yet recompiling.
  8444     CodeOffsetLabel label = masm.movWithPatch(ImmWord(uintptr_t(-1)), tmp);
  8445     if (!ionScriptLabels_.append(label))
  8446         return false;
  8447     masm.branch32(Assembler::Equal,
  8448                   Address(tmp, IonScript::offsetOfRecompiling()),
  8449                   Imm32(0),
  8450                   ool->entry());
  8451     masm.bind(ool->rejoin());
  8452     masm.bind(&done);
  8454     return true;
  8457 } // namespace jit
  8458 } // namespace js

mercurial