LCOV - code coverage report
Current view: top level - js/src/jit - CodeGenerator.cpp (source / functions) Hit Total Coverage
Test: output.info Lines: 1978 7009 28.2 %
Date: 2017-07-14 16:53:18 Functions: 149 512 29.1 %
Legend: Lines: hit not hit

          Line data    Source code
       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/. */
       6             : 
       7             : #include "jit/CodeGenerator.h"
       8             : 
       9             : #include "mozilla/Assertions.h"
      10             : #include "mozilla/Attributes.h"
      11             : #include "mozilla/Casting.h"
      12             : #include "mozilla/DebugOnly.h"
      13             : #include "mozilla/EnumeratedArray.h"
      14             : #include "mozilla/EnumeratedRange.h"
      15             : #include "mozilla/MathAlgorithms.h"
      16             : #include "mozilla/ScopeExit.h"
      17             : #include "mozilla/SizePrintfMacros.h"
      18             : 
      19             : #include "jslibmath.h"
      20             : #include "jsmath.h"
      21             : #include "jsnum.h"
      22             : #include "jsprf.h"
      23             : #include "jsstr.h"
      24             : 
      25             : #include "builtin/Eval.h"
      26             : #include "builtin/RegExp.h"
      27             : #include "builtin/SelfHostingDefines.h"
      28             : #include "builtin/TypedObject.h"
      29             : #include "gc/Nursery.h"
      30             : #include "irregexp/NativeRegExpMacroAssembler.h"
      31             : #include "jit/AtomicOperations.h"
      32             : #include "jit/BaselineCompiler.h"
      33             : #include "jit/IonBuilder.h"
      34             : #include "jit/IonCaches.h"
      35             : #include "jit/IonIC.h"
      36             : #include "jit/IonOptimizationLevels.h"
      37             : #include "jit/JitcodeMap.h"
      38             : #include "jit/JitSpewer.h"
      39             : #include "jit/Linker.h"
      40             : #include "jit/Lowering.h"
      41             : #include "jit/MIRGenerator.h"
      42             : #include "jit/MoveEmitter.h"
      43             : #include "jit/RangeAnalysis.h"
      44             : #include "jit/SharedICHelpers.h"
      45             : #include "vm/AsyncFunction.h"
      46             : #include "vm/AsyncIteration.h"
      47             : #include "vm/MatchPairs.h"
      48             : #include "vm/RegExpObject.h"
      49             : #include "vm/RegExpStatics.h"
      50             : #include "vm/TraceLogging.h"
      51             : #include "vm/Unicode.h"
      52             : #include "vtune/VTuneWrapper.h"
      53             : 
      54             : #include "jsboolinlines.h"
      55             : 
      56             : #include "jit/MacroAssembler-inl.h"
      57             : #include "jit/shared/CodeGenerator-shared-inl.h"
      58             : #include "jit/shared/Lowering-shared-inl.h"
      59             : #include "vm/Interpreter-inl.h"
      60             : 
      61             : using namespace js;
      62             : using namespace js::jit;
      63             : 
      64             : using mozilla::AssertedCast;
      65             : using mozilla::DebugOnly;
      66             : using mozilla::FloatingPoint;
      67             : using mozilla::Maybe;
      68             : using mozilla::NegativeInfinity;
      69             : using mozilla::PositiveInfinity;
      70             : using JS::GenericNaN;
      71             : 
      72             : namespace js {
      73             : namespace jit {
      74             : 
      75             : class OutOfLineICFallback : public OutOfLineCodeBase<CodeGenerator>
      76             : {
      77             :   private:
      78             :     LInstruction* lir_;
      79             :     size_t cacheIndex_;
      80             :     size_t cacheInfoIndex_;
      81             : 
      82             :   public:
      83          35 :     OutOfLineICFallback(LInstruction* lir, size_t cacheIndex, size_t cacheInfoIndex)
      84          35 :       : lir_(lir),
      85             :         cacheIndex_(cacheIndex),
      86          35 :         cacheInfoIndex_(cacheInfoIndex)
      87          35 :     { }
      88             : 
      89          35 :     void bind(MacroAssembler* masm) {
      90             :         // The binding of the initial jump is done in
      91             :         // CodeGenerator::visitOutOfLineICFallback.
      92          35 :     }
      93             : 
      94          35 :     size_t cacheIndex() const {
      95          35 :         return cacheIndex_;
      96             :     }
      97          35 :     size_t cacheInfoIndex() const {
      98          35 :         return cacheInfoIndex_;
      99             :     }
     100          35 :     LInstruction* lir() const {
     101          35 :         return lir_;
     102             :     }
     103             : 
     104          35 :     void accept(CodeGenerator* codegen) {
     105          35 :         codegen->visitOutOfLineICFallback(this);
     106          35 :     }
     107             : };
     108             : 
     109             : void
     110          35 : CodeGeneratorShared::addIC(LInstruction* lir, size_t cacheIndex)
     111             : {
     112          35 :     if (cacheIndex == SIZE_MAX) {
     113           0 :         masm.setOOM();
     114           0 :         return;
     115             :     }
     116             : 
     117          35 :     DataPtr<IonIC> cache(this, cacheIndex);
     118          35 :     MInstruction* mir = lir->mirRaw()->toInstruction();
     119          35 :     if (mir->resumePoint()) {
     120          32 :         cache->setScriptedLocation(mir->block()->info().script(),
     121          32 :                                    mir->resumePoint()->pc());
     122             :     } else {
     123           3 :         cache->setIdempotent();
     124             :     }
     125             : 
     126          35 :     Register temp = cache->scratchRegisterForEntryJump();
     127          35 :     icInfo_.back().icOffsetForJump = masm.movWithPatch(ImmWord(-1), temp);
     128          35 :     masm.jump(Address(temp, 0));
     129             : 
     130          35 :     MOZ_ASSERT(!icInfo_.empty());
     131             : 
     132          35 :     OutOfLineICFallback* ool = new(alloc()) OutOfLineICFallback(lir, cacheIndex, icInfo_.length() - 1);
     133          35 :     addOutOfLineCode(ool, mir);
     134             : 
     135          35 :     masm.bind(ool->rejoin());
     136          35 :     cache->setRejoinLabel(CodeOffset(ool->rejoin()->offset()));
     137             : }
     138             : 
     139             : typedef bool (*IonGetPropertyICFn)(JSContext*, HandleScript, IonGetPropertyIC*, HandleValue, HandleValue,
     140             :                                    MutableHandleValue);
     141           3 : static const VMFunction IonGetPropertyICInfo =
     142           6 :     FunctionInfo<IonGetPropertyICFn>(IonGetPropertyIC::update, "IonGetPropertyIC::update");
     143             : 
     144             : typedef bool (*IonSetPropertyICFn)(JSContext*, HandleScript, IonSetPropertyIC*, HandleObject,
     145             :                                    HandleValue, HandleValue);
     146           3 : static const VMFunction IonSetPropertyICInfo =
     147           6 :     FunctionInfo<IonSetPropertyICFn>(IonSetPropertyIC::update, "IonSetPropertyIC::update");
     148             : 
     149             : typedef bool (*IonGetNameICFn)(JSContext*, HandleScript, IonGetNameIC*, HandleObject,
     150             :                                MutableHandleValue);
     151           3 : static const VMFunction IonGetNameICInfo =
     152           6 :     FunctionInfo<IonGetNameICFn>(IonGetNameIC::update, "IonGetNameIC::update");
     153             : 
     154             : typedef bool (*IonHasOwnICFn)(JSContext*, HandleScript, IonHasOwnIC*, HandleValue, HandleValue,
     155             :                               int32_t*);
     156           3 : static const VMFunction IonHasOwnICInfo =
     157           6 :     FunctionInfo<IonHasOwnICFn>(IonHasOwnIC::update, "IonHasOwnIC::update");
     158             : 
     159             : typedef JSObject* (*IonBindNameICFn)(JSContext*, HandleScript, IonBindNameIC*, HandleObject);
     160           3 : static const VMFunction IonBindNameICInfo =
     161           6 :     FunctionInfo<IonBindNameICFn>(IonBindNameIC::update, "IonBindNameIC::update");
     162             : 
     163             : typedef bool (*IonInICFn)(JSContext*, HandleScript, IonInIC*, HandleValue, HandleObject, bool*);
     164           3 : static const VMFunction IonInICInfo =
     165           6 :     FunctionInfo<IonInICFn>(IonInIC::update, "IonInIC::update");
     166             : 
     167             : void
     168          35 : CodeGenerator::visitOutOfLineICFallback(OutOfLineICFallback* ool)
     169             : {
     170          35 :     LInstruction* lir = ool->lir();
     171          35 :     size_t cacheIndex = ool->cacheIndex();
     172          35 :     size_t cacheInfoIndex = ool->cacheInfoIndex();
     173             : 
     174          35 :     DataPtr<IonIC> ic(this, cacheIndex);
     175             : 
     176             :     // Register the location of the OOL path in the IC.
     177          35 :     ic->setFallbackLabel(masm.labelForPatch());
     178             : 
     179          35 :     switch (ic->kind()) {
     180             :       case CacheKind::GetProp:
     181             :       case CacheKind::GetElem: {
     182          23 :         IonGetPropertyIC* getPropIC = ic->asGetPropertyIC();
     183             : 
     184          23 :         saveLive(lir);
     185             : 
     186          23 :         pushArg(getPropIC->id());
     187          23 :         pushArg(getPropIC->value());
     188          23 :         icInfo_[cacheInfoIndex].icOffsetForPush = pushArgWithPatch(ImmWord(-1));
     189          23 :         pushArg(ImmGCPtr(gen->info().script()));
     190             : 
     191          23 :         callVM(IonGetPropertyICInfo, lir);
     192             : 
     193          23 :         StoreValueTo(getPropIC->output()).generate(this);
     194          23 :         restoreLiveIgnore(lir, StoreValueTo(getPropIC->output()).clobbered());
     195             : 
     196          23 :         masm.jump(ool->rejoin());
     197          23 :         return;
     198             :       }
     199             :       case CacheKind::SetProp:
     200             :       case CacheKind::SetElem: {
     201           6 :         IonSetPropertyIC* setPropIC = ic->asSetPropertyIC();
     202             : 
     203           6 :         saveLive(lir);
     204             : 
     205           6 :         pushArg(setPropIC->rhs());
     206           6 :         pushArg(setPropIC->id());
     207           6 :         pushArg(setPropIC->object());
     208           6 :         icInfo_[cacheInfoIndex].icOffsetForPush = pushArgWithPatch(ImmWord(-1));
     209           6 :         pushArg(ImmGCPtr(gen->info().script()));
     210             : 
     211           6 :         callVM(IonSetPropertyICInfo, lir);
     212             : 
     213           6 :         restoreLive(lir);
     214             : 
     215           6 :         masm.jump(ool->rejoin());
     216           6 :         return;
     217             :       }
     218             :       case CacheKind::GetName: {
     219           4 :         IonGetNameIC* getNameIC = ic->asGetNameIC();
     220             : 
     221           4 :         saveLive(lir);
     222             : 
     223           4 :         pushArg(getNameIC->environment());
     224           4 :         icInfo_[cacheInfoIndex].icOffsetForPush = pushArgWithPatch(ImmWord(-1));
     225           4 :         pushArg(ImmGCPtr(gen->info().script()));
     226             : 
     227           4 :         callVM(IonGetNameICInfo, lir);
     228             : 
     229           4 :         StoreValueTo(getNameIC->output()).generate(this);
     230           4 :         restoreLiveIgnore(lir, StoreValueTo(getNameIC->output()).clobbered());
     231             : 
     232           4 :         masm.jump(ool->rejoin());
     233           4 :         return;
     234             :       }
     235             :       case CacheKind::BindName: {
     236           0 :         IonBindNameIC* bindNameIC = ic->asBindNameIC();
     237             : 
     238           0 :         saveLive(lir);
     239             : 
     240           0 :         pushArg(bindNameIC->environment());
     241           0 :         icInfo_[cacheInfoIndex].icOffsetForPush = pushArgWithPatch(ImmWord(-1));
     242           0 :         pushArg(ImmGCPtr(gen->info().script()));
     243             : 
     244           0 :         callVM(IonBindNameICInfo, lir);
     245             : 
     246           0 :         StoreRegisterTo(bindNameIC->output()).generate(this);
     247           0 :         restoreLiveIgnore(lir, StoreRegisterTo(bindNameIC->output()).clobbered());
     248             : 
     249           0 :         masm.jump(ool->rejoin());
     250           0 :         return;
     251             :       }
     252             :       case CacheKind::In: {
     253           2 :         IonInIC* inIC = ic->asInIC();
     254             : 
     255           2 :         saveLive(lir);
     256             : 
     257           2 :         pushArg(inIC->object());
     258           2 :         pushArg(inIC->key());
     259           2 :         icInfo_[cacheInfoIndex].icOffsetForPush = pushArgWithPatch(ImmWord(-1));
     260           2 :         pushArg(ImmGCPtr(gen->info().script()));
     261             : 
     262           2 :         callVM(IonInICInfo, lir);
     263             : 
     264           2 :         StoreRegisterTo(inIC->output()).generate(this);
     265           2 :         restoreLiveIgnore(lir, StoreRegisterTo(inIC->output()).clobbered());
     266             : 
     267           2 :         masm.jump(ool->rejoin());
     268           2 :         return;
     269             :       }
     270             :       case CacheKind::HasOwn: {
     271           0 :         IonHasOwnIC* hasOwnIC = ic->asHasOwnIC();
     272             : 
     273           0 :         saveLive(lir);
     274             : 
     275           0 :         pushArg(hasOwnIC->id());
     276           0 :         pushArg(hasOwnIC->value());
     277           0 :         icInfo_[cacheInfoIndex].icOffsetForPush = pushArgWithPatch(ImmWord(-1));
     278           0 :         pushArg(ImmGCPtr(gen->info().script()));
     279             : 
     280           0 :         callVM(IonHasOwnICInfo, lir);
     281             : 
     282           0 :         StoreRegisterTo(hasOwnIC->output()).generate(this);
     283           0 :         restoreLiveIgnore(lir, StoreRegisterTo(hasOwnIC->output()).clobbered());
     284             : 
     285           0 :         masm.jump(ool->rejoin());
     286           0 :         return;
     287             :       }
     288             :       case CacheKind::Call:
     289             :       case CacheKind::Compare:
     290             :       case CacheKind::TypeOf:
     291             :       case CacheKind::GetPropSuper:
     292             :       case CacheKind::GetElemSuper:
     293           0 :         MOZ_CRASH("Unsupported IC");
     294             :     }
     295           0 :     MOZ_CRASH();
     296             : }
     297             : 
     298             : StringObject*
     299           0 : MNewStringObject::templateObj() const
     300             : {
     301           0 :     return &templateObj_->as<StringObject>();
     302             : }
     303             : 
     304           8 : CodeGenerator::CodeGenerator(MIRGenerator* gen, LIRGraph* graph, MacroAssembler* masm)
     305             :   : CodeGeneratorSpecific(gen, graph, masm)
     306             :   , ionScriptLabels_(gen->alloc())
     307             :   , scriptCounts_(nullptr)
     308           8 :   , simdRefreshTemplatesDuringLink_(0)
     309             : {
     310           8 : }
     311             : 
     312          16 : CodeGenerator::~CodeGenerator()
     313             : {
     314           8 :     MOZ_ASSERT_IF(!gen->compilingWasm(), masm.numSymbolicAccesses() == 0);
     315           8 :     js_delete(scriptCounts_);
     316           8 : }
     317             : 
     318             : typedef bool (*StringToNumberFn)(JSContext*, JSString*, double*);
     319           3 : static const VMFunction StringToNumberInfo =
     320           6 :     FunctionInfo<StringToNumberFn>(StringToNumber, "StringToNumber");
     321             : 
     322             : void
     323           2 : CodeGenerator::visitValueToInt32(LValueToInt32* lir)
     324             : {
     325           2 :     ValueOperand operand = ToValue(lir, LValueToInt32::Input);
     326           2 :     Register output = ToRegister(lir->output());
     327           2 :     FloatRegister temp = ToFloatRegister(lir->tempFloat());
     328             : 
     329             :     MDefinition* input;
     330           2 :     if (lir->mode() == LValueToInt32::NORMAL)
     331           1 :         input = lir->mirNormal()->input();
     332             :     else
     333           1 :         input = lir->mirTruncate()->input();
     334             : 
     335           4 :     Label fails;
     336           2 :     if (lir->mode() == LValueToInt32::TRUNCATE) {
     337           1 :         OutOfLineCode* oolDouble = oolTruncateDouble(temp, output, lir->mir());
     338             : 
     339             :         // We can only handle strings in truncation contexts, like bitwise
     340             :         // operations.
     341             :         Label* stringEntry;
     342             :         Label* stringRejoin;
     343           1 :         Register stringReg;
     344           1 :         if (input->mightBeType(MIRType::String)) {
     345           0 :             stringReg = ToRegister(lir->temp());
     346           0 :             OutOfLineCode* oolString = oolCallVM(StringToNumberInfo, lir, ArgList(stringReg),
     347           0 :                                                  StoreFloatRegisterTo(temp));
     348           0 :             stringEntry = oolString->entry();
     349           0 :             stringRejoin = oolString->rejoin();
     350             :         } else {
     351           1 :             stringReg = InvalidReg;
     352           1 :             stringEntry = nullptr;
     353           1 :             stringRejoin = nullptr;
     354             :         }
     355             : 
     356           1 :         masm.truncateValueToInt32(operand, input, stringEntry, stringRejoin, oolDouble->entry(),
     357           1 :                                   stringReg, temp, output, &fails);
     358           1 :         masm.bind(oolDouble->rejoin());
     359             :     } else {
     360           2 :         masm.convertValueToInt32(operand, input, temp, output, &fails,
     361           1 :                                  lir->mirNormal()->canBeNegativeZero(),
     362           1 :                                  lir->mirNormal()->conversion());
     363             :     }
     364             : 
     365           2 :     bailoutFrom(&fails, lir->snapshot());
     366           2 : }
     367             : 
     368             : void
     369           0 : CodeGenerator::visitValueToDouble(LValueToDouble* lir)
     370             : {
     371           0 :     MToDouble* mir = lir->mir();
     372           0 :     ValueOperand operand = ToValue(lir, LValueToDouble::Input);
     373           0 :     FloatRegister output = ToFloatRegister(lir->output());
     374             : 
     375           0 :     Register tag = masm.splitTagForTest(operand);
     376             : 
     377           0 :     Label isDouble, isInt32, isBool, isNull, isUndefined, done;
     378           0 :     bool hasBoolean = false, hasNull = false, hasUndefined = false;
     379             : 
     380           0 :     masm.branchTestDouble(Assembler::Equal, tag, &isDouble);
     381           0 :     masm.branchTestInt32(Assembler::Equal, tag, &isInt32);
     382             : 
     383           0 :     if (mir->conversion() != MToFPInstruction::NumbersOnly) {
     384           0 :         masm.branchTestBoolean(Assembler::Equal, tag, &isBool);
     385           0 :         masm.branchTestUndefined(Assembler::Equal, tag, &isUndefined);
     386           0 :         hasBoolean = true;
     387           0 :         hasUndefined = true;
     388           0 :         if (mir->conversion() != MToFPInstruction::NonNullNonStringPrimitives) {
     389           0 :             masm.branchTestNull(Assembler::Equal, tag, &isNull);
     390           0 :             hasNull = true;
     391             :         }
     392             :     }
     393             : 
     394           0 :     bailout(lir->snapshot());
     395             : 
     396           0 :     if (hasNull) {
     397           0 :         masm.bind(&isNull);
     398           0 :         masm.loadConstantDouble(0.0, output);
     399           0 :         masm.jump(&done);
     400             :     }
     401             : 
     402           0 :     if (hasUndefined) {
     403           0 :         masm.bind(&isUndefined);
     404           0 :         masm.loadConstantDouble(GenericNaN(), output);
     405           0 :         masm.jump(&done);
     406             :     }
     407             : 
     408           0 :     if (hasBoolean) {
     409           0 :         masm.bind(&isBool);
     410           0 :         masm.boolValueToDouble(operand, output);
     411           0 :         masm.jump(&done);
     412             :     }
     413             : 
     414           0 :     masm.bind(&isInt32);
     415           0 :     masm.int32ValueToDouble(operand, output);
     416           0 :     masm.jump(&done);
     417             : 
     418           0 :     masm.bind(&isDouble);
     419           0 :     masm.unboxDouble(operand, output);
     420           0 :     masm.bind(&done);
     421           0 : }
     422             : 
     423             : void
     424           0 : CodeGenerator::visitValueToFloat32(LValueToFloat32* lir)
     425             : {
     426           0 :     MToFloat32* mir = lir->mir();
     427           0 :     ValueOperand operand = ToValue(lir, LValueToFloat32::Input);
     428           0 :     FloatRegister output = ToFloatRegister(lir->output());
     429             : 
     430           0 :     Register tag = masm.splitTagForTest(operand);
     431             : 
     432           0 :     Label isDouble, isInt32, isBool, isNull, isUndefined, done;
     433           0 :     bool hasBoolean = false, hasNull = false, hasUndefined = false;
     434             : 
     435           0 :     masm.branchTestDouble(Assembler::Equal, tag, &isDouble);
     436           0 :     masm.branchTestInt32(Assembler::Equal, tag, &isInt32);
     437             : 
     438           0 :     if (mir->conversion() != MToFPInstruction::NumbersOnly) {
     439           0 :         masm.branchTestBoolean(Assembler::Equal, tag, &isBool);
     440           0 :         masm.branchTestUndefined(Assembler::Equal, tag, &isUndefined);
     441           0 :         hasBoolean = true;
     442           0 :         hasUndefined = true;
     443           0 :         if (mir->conversion() != MToFPInstruction::NonNullNonStringPrimitives) {
     444           0 :             masm.branchTestNull(Assembler::Equal, tag, &isNull);
     445           0 :             hasNull = true;
     446             :         }
     447             :     }
     448             : 
     449           0 :     bailout(lir->snapshot());
     450             : 
     451           0 :     if (hasNull) {
     452           0 :         masm.bind(&isNull);
     453           0 :         masm.loadConstantFloat32(0.0f, output);
     454           0 :         masm.jump(&done);
     455             :     }
     456             : 
     457           0 :     if (hasUndefined) {
     458           0 :         masm.bind(&isUndefined);
     459           0 :         masm.loadConstantFloat32(float(GenericNaN()), output);
     460           0 :         masm.jump(&done);
     461             :     }
     462             : 
     463           0 :     if (hasBoolean) {
     464           0 :         masm.bind(&isBool);
     465           0 :         masm.boolValueToFloat32(operand, output);
     466           0 :         masm.jump(&done);
     467             :     }
     468             : 
     469           0 :     masm.bind(&isInt32);
     470           0 :     masm.int32ValueToFloat32(operand, output);
     471           0 :     masm.jump(&done);
     472             : 
     473           0 :     masm.bind(&isDouble);
     474             :     // ARM and MIPS may not have a double register available if we've
     475             :     // allocated output as a float32.
     476             : #if defined(JS_CODEGEN_ARM) || defined(JS_CODEGEN_MIPS32)
     477             :     masm.unboxDouble(operand, ScratchDoubleReg);
     478             :     masm.convertDoubleToFloat32(ScratchDoubleReg, output);
     479             : #else
     480           0 :     masm.unboxDouble(operand, output);
     481           0 :     masm.convertDoubleToFloat32(output, output);
     482             : #endif
     483           0 :     masm.bind(&done);
     484           0 : }
     485             : 
     486             : void
     487           0 : CodeGenerator::visitInt32ToDouble(LInt32ToDouble* lir)
     488             : {
     489           0 :     masm.convertInt32ToDouble(ToRegister(lir->input()), ToFloatRegister(lir->output()));
     490           0 : }
     491             : 
     492             : void
     493           0 : CodeGenerator::visitFloat32ToDouble(LFloat32ToDouble* lir)
     494             : {
     495           0 :     masm.convertFloat32ToDouble(ToFloatRegister(lir->input()), ToFloatRegister(lir->output()));
     496           0 : }
     497             : 
     498             : void
     499           0 : CodeGenerator::visitDoubleToFloat32(LDoubleToFloat32* lir)
     500             : {
     501           0 :     masm.convertDoubleToFloat32(ToFloatRegister(lir->input()), ToFloatRegister(lir->output()));
     502           0 : }
     503             : 
     504             : void
     505           0 : CodeGenerator::visitInt32ToFloat32(LInt32ToFloat32* lir)
     506             : {
     507           0 :     masm.convertInt32ToFloat32(ToRegister(lir->input()), ToFloatRegister(lir->output()));
     508           0 : }
     509             : 
     510             : void
     511           0 : CodeGenerator::visitDoubleToInt32(LDoubleToInt32* lir)
     512             : {
     513           0 :     Label fail;
     514           0 :     FloatRegister input = ToFloatRegister(lir->input());
     515           0 :     Register output = ToRegister(lir->output());
     516           0 :     masm.convertDoubleToInt32(input, output, &fail, lir->mir()->canBeNegativeZero());
     517           0 :     bailoutFrom(&fail, lir->snapshot());
     518           0 : }
     519             : 
     520             : void
     521           0 : CodeGenerator::visitFloat32ToInt32(LFloat32ToInt32* lir)
     522             : {
     523           0 :     Label fail;
     524           0 :     FloatRegister input = ToFloatRegister(lir->input());
     525           0 :     Register output = ToRegister(lir->output());
     526           0 :     masm.convertFloat32ToInt32(input, output, &fail, lir->mir()->canBeNegativeZero());
     527           0 :     bailoutFrom(&fail, lir->snapshot());
     528           0 : }
     529             : 
     530             : void
     531           0 : CodeGenerator::emitOOLTestObject(Register objreg,
     532             :                                  Label* ifEmulatesUndefined,
     533             :                                  Label* ifDoesntEmulateUndefined,
     534             :                                  Register scratch)
     535             : {
     536           0 :     saveVolatile(scratch);
     537           0 :     masm.setupUnalignedABICall(scratch);
     538           0 :     masm.passABIArg(objreg);
     539           0 :     masm.callWithABI(JS_FUNC_TO_DATA_PTR(void*, js::EmulatesUndefined));
     540           0 :     masm.storeCallBoolResult(scratch);
     541           0 :     restoreVolatile(scratch);
     542             : 
     543           0 :     masm.branchIfTrueBool(scratch, ifEmulatesUndefined);
     544           0 :     masm.jump(ifDoesntEmulateUndefined);
     545           0 : }
     546             : 
     547             : // Base out-of-line code generator for all tests of the truthiness of an
     548             : // object, where the object might not be truthy.  (Recall that per spec all
     549             : // objects are truthy, but we implement the JSCLASS_EMULATES_UNDEFINED class
     550             : // flag to permit objects to look like |undefined| in certain contexts,
     551             : // including in object truthiness testing.)  We check truthiness inline except
     552             : // when we're testing it on a proxy (or if TI guarantees us that the specified
     553             : // object will never emulate |undefined|), in which case out-of-line code will
     554             : // call EmulatesUndefined for a conclusive answer.
     555             : class OutOfLineTestObject : public OutOfLineCodeBase<CodeGenerator>
     556             : {
     557             :     Register objreg_;
     558             :     Register scratch_;
     559             : 
     560             :     Label* ifEmulatesUndefined_;
     561             :     Label* ifDoesntEmulateUndefined_;
     562             : 
     563             : #ifdef DEBUG
     564           0 :     bool initialized() { return ifEmulatesUndefined_ != nullptr; }
     565             : #endif
     566             : 
     567             :   public:
     568           0 :     OutOfLineTestObject()
     569             : #ifdef DEBUG
     570           0 :       : ifEmulatesUndefined_(nullptr), ifDoesntEmulateUndefined_(nullptr)
     571             : #endif
     572           0 :     { }
     573             : 
     574           0 :     void accept(CodeGenerator* codegen) final override {
     575           0 :         MOZ_ASSERT(initialized());
     576           0 :         codegen->emitOOLTestObject(objreg_, ifEmulatesUndefined_, ifDoesntEmulateUndefined_,
     577           0 :                                    scratch_);
     578           0 :     }
     579             : 
     580             :     // Specify the register where the object to be tested is found, labels to
     581             :     // jump to if the object is truthy or falsy, and a scratch register for
     582             :     // use in the out-of-line path.
     583           0 :     void setInputAndTargets(Register objreg, Label* ifEmulatesUndefined, Label* ifDoesntEmulateUndefined,
     584             :                             Register scratch)
     585             :     {
     586           0 :         MOZ_ASSERT(!initialized());
     587           0 :         MOZ_ASSERT(ifEmulatesUndefined);
     588           0 :         objreg_ = objreg;
     589           0 :         scratch_ = scratch;
     590           0 :         ifEmulatesUndefined_ = ifEmulatesUndefined;
     591           0 :         ifDoesntEmulateUndefined_ = ifDoesntEmulateUndefined;
     592           0 :     }
     593             : };
     594             : 
     595             : // A subclass of OutOfLineTestObject containing two extra labels, for use when
     596             : // the ifTruthy/ifFalsy labels are needed in inline code as well as out-of-line
     597             : // code.  The user should bind these labels in inline code, and specify them as
     598             : // targets via setInputAndTargets, as appropriate.
     599             : class OutOfLineTestObjectWithLabels : public OutOfLineTestObject
     600             : {
     601             :     Label label1_;
     602             :     Label label2_;
     603             : 
     604             :   public:
     605           0 :     OutOfLineTestObjectWithLabels() { }
     606             : 
     607           0 :     Label* label1() { return &label1_; }
     608           0 :     Label* label2() { return &label2_; }
     609             : };
     610             : 
     611             : void
     612           0 : CodeGenerator::testObjectEmulatesUndefinedKernel(Register objreg,
     613             :                                                  Label* ifEmulatesUndefined,
     614             :                                                  Label* ifDoesntEmulateUndefined,
     615             :                                                  Register scratch, OutOfLineTestObject* ool)
     616             : {
     617           0 :     ool->setInputAndTargets(objreg, ifEmulatesUndefined, ifDoesntEmulateUndefined, scratch);
     618             : 
     619             :     // Perform a fast-path check of the object's class flags if the object's
     620             :     // not a proxy.  Let out-of-line code handle the slow cases that require
     621             :     // saving registers, making a function call, and restoring registers.
     622           0 :     masm.branchIfObjectEmulatesUndefined(objreg, scratch, ool->entry(), ifEmulatesUndefined);
     623           0 : }
     624             : 
     625             : void
     626           0 : CodeGenerator::branchTestObjectEmulatesUndefined(Register objreg,
     627             :                                                  Label* ifEmulatesUndefined,
     628             :                                                  Label* ifDoesntEmulateUndefined,
     629             :                                                  Register scratch, OutOfLineTestObject* ool)
     630             : {
     631           0 :     MOZ_ASSERT(!ifDoesntEmulateUndefined->bound(),
     632             :                "ifDoesntEmulateUndefined will be bound to the fallthrough path");
     633             : 
     634             :     testObjectEmulatesUndefinedKernel(objreg, ifEmulatesUndefined, ifDoesntEmulateUndefined,
     635           0 :                                       scratch, ool);
     636           0 :     masm.bind(ifDoesntEmulateUndefined);
     637           0 : }
     638             : 
     639             : void
     640           0 : CodeGenerator::testObjectEmulatesUndefined(Register objreg,
     641             :                                            Label* ifEmulatesUndefined,
     642             :                                            Label* ifDoesntEmulateUndefined,
     643             :                                            Register scratch, OutOfLineTestObject* ool)
     644             : {
     645             :     testObjectEmulatesUndefinedKernel(objreg, ifEmulatesUndefined, ifDoesntEmulateUndefined,
     646           0 :                                       scratch, ool);
     647           0 :     masm.jump(ifDoesntEmulateUndefined);
     648           0 : }
     649             : 
     650             : void
     651          32 : CodeGenerator::testValueTruthyKernel(const ValueOperand& value,
     652             :                                      const LDefinition* scratch1, const LDefinition* scratch2,
     653             :                                      FloatRegister fr,
     654             :                                      Label* ifTruthy, Label* ifFalsy,
     655             :                                      OutOfLineTestObject* ool,
     656             :                                      MDefinition* valueMIR)
     657             : {
     658             :     // Count the number of possible type tags we might have, so we'll know when
     659             :     // we've checked them all and hence can avoid emitting a tag check for the
     660             :     // last one.  In particular, whenever tagCount is 1 that means we've tried
     661             :     // all but one of them already so we know exactly what's left based on the
     662             :     // mightBe* booleans.
     663          32 :     bool mightBeUndefined = valueMIR->mightBeType(MIRType::Undefined);
     664          32 :     bool mightBeNull = valueMIR->mightBeType(MIRType::Null);
     665          32 :     bool mightBeBoolean = valueMIR->mightBeType(MIRType::Boolean);
     666          32 :     bool mightBeInt32 = valueMIR->mightBeType(MIRType::Int32);
     667          32 :     bool mightBeObject = valueMIR->mightBeType(MIRType::Object);
     668          32 :     bool mightBeString = valueMIR->mightBeType(MIRType::String);
     669          32 :     bool mightBeSymbol = valueMIR->mightBeType(MIRType::Symbol);
     670          32 :     bool mightBeDouble = valueMIR->mightBeType(MIRType::Double);
     671          32 :     int tagCount = int(mightBeUndefined) + int(mightBeNull) +
     672          32 :         int(mightBeBoolean) + int(mightBeInt32) + int(mightBeObject) +
     673          32 :         int(mightBeString) + int(mightBeSymbol) + int(mightBeDouble);
     674             : 
     675          32 :     MOZ_ASSERT_IF(!valueMIR->emptyResultTypeSet(), tagCount > 0);
     676             : 
     677             :     // If we know we're null or undefined, we're definitely falsy, no
     678             :     // need to even check the tag.
     679          32 :     if (int(mightBeNull) + int(mightBeUndefined) == tagCount) {
     680           1 :         masm.jump(ifFalsy);
     681           1 :         return;
     682             :     }
     683             : 
     684          31 :     Register tag = masm.splitTagForTest(value);
     685             : 
     686          31 :     if (mightBeUndefined) {
     687          31 :         MOZ_ASSERT(tagCount > 1);
     688          31 :         masm.branchTestUndefined(Assembler::Equal, tag, ifFalsy);
     689          31 :         --tagCount;
     690             :     }
     691             : 
     692          31 :     if (mightBeNull) {
     693           0 :         MOZ_ASSERT(tagCount > 1);
     694           0 :         masm.branchTestNull(Assembler::Equal, tag, ifFalsy);
     695           0 :         --tagCount;
     696             :     }
     697             : 
     698          31 :     if (mightBeBoolean) {
     699          31 :         MOZ_ASSERT(tagCount != 0);
     700          62 :         Label notBoolean;
     701          31 :         if (tagCount != 1)
     702           3 :             masm.branchTestBoolean(Assembler::NotEqual, tag, &notBoolean);
     703          31 :         masm.branchTestBooleanTruthy(false, value, ifFalsy);
     704          31 :         if (tagCount != 1)
     705           3 :             masm.jump(ifTruthy);
     706             :         // Else just fall through to truthiness.
     707          31 :         masm.bind(&notBoolean);
     708          31 :         --tagCount;
     709             :     }
     710             : 
     711          31 :     if (mightBeInt32) {
     712           0 :         MOZ_ASSERT(tagCount != 0);
     713           0 :         Label notInt32;
     714           0 :         if (tagCount != 1)
     715           0 :             masm.branchTestInt32(Assembler::NotEqual, tag, &notInt32);
     716           0 :         masm.branchTestInt32Truthy(false, value, ifFalsy);
     717           0 :         if (tagCount != 1)
     718           0 :             masm.jump(ifTruthy);
     719             :         // Else just fall through to truthiness.
     720           0 :         masm.bind(&notInt32);
     721           0 :         --tagCount;
     722             :     }
     723             : 
     724          31 :     if (mightBeObject) {
     725           0 :         MOZ_ASSERT(tagCount != 0);
     726           0 :         if (ool) {
     727           0 :             Label notObject;
     728             : 
     729           0 :             if (tagCount != 1)
     730           0 :                 masm.branchTestObject(Assembler::NotEqual, tag, &notObject);
     731             : 
     732           0 :             Register objreg = masm.extractObject(value, ToRegister(scratch1));
     733           0 :             testObjectEmulatesUndefined(objreg, ifFalsy, ifTruthy, ToRegister(scratch2), ool);
     734             : 
     735           0 :             masm.bind(&notObject);
     736             :         } else {
     737           0 :             if (tagCount != 1)
     738           0 :                 masm.branchTestObject(Assembler::Equal, tag, ifTruthy);
     739             :             // Else just fall through to truthiness.
     740             :         }
     741           0 :         --tagCount;
     742             :     } else {
     743          31 :         MOZ_ASSERT(!ool,
     744             :                    "We better not have an unused OOL path, since the code generator will try to "
     745             :                    "generate code for it but we never set up its labels, which will cause null "
     746             :                    "derefs of those labels.");
     747             :     }
     748             : 
     749          31 :     if (mightBeString) {
     750             :         // Test if a string is non-empty.
     751           3 :         MOZ_ASSERT(tagCount != 0);
     752           6 :         Label notString;
     753           3 :         if (tagCount != 1)
     754           0 :             masm.branchTestString(Assembler::NotEqual, tag, &notString);
     755           3 :         masm.branchTestStringTruthy(false, value, ifFalsy);
     756           3 :         if (tagCount != 1)
     757           0 :             masm.jump(ifTruthy);
     758             :         // Else just fall through to truthiness.
     759           3 :         masm.bind(&notString);
     760           3 :         --tagCount;
     761             :     }
     762             : 
     763          31 :     if (mightBeSymbol) {
     764             :         // All symbols are truthy.
     765           0 :         MOZ_ASSERT(tagCount != 0);
     766           0 :         if (tagCount != 1)
     767           0 :             masm.branchTestSymbol(Assembler::Equal, tag, ifTruthy);
     768             :         // Else fall through to ifTruthy.
     769           0 :         --tagCount;
     770             :     }
     771             : 
     772          31 :     if (mightBeDouble) {
     773           0 :         MOZ_ASSERT(tagCount == 1);
     774             :         // If we reach here the value is a double.
     775           0 :         masm.unboxDouble(value, fr);
     776           0 :         masm.branchTestDoubleTruthy(false, fr, ifFalsy);
     777           0 :         --tagCount;
     778             :     }
     779             : 
     780          31 :     MOZ_ASSERT(tagCount == 0);
     781             : 
     782             :     // Fall through for truthy.
     783             : }
     784             : 
     785             : void
     786          30 : CodeGenerator::testValueTruthy(const ValueOperand& value,
     787             :                                const LDefinition* scratch1, const LDefinition* scratch2,
     788             :                                FloatRegister fr,
     789             :                                Label* ifTruthy, Label* ifFalsy,
     790             :                                OutOfLineTestObject* ool,
     791             :                                MDefinition* valueMIR)
     792             : {
     793          30 :     testValueTruthyKernel(value, scratch1, scratch2, fr, ifTruthy, ifFalsy, ool, valueMIR);
     794          30 :     masm.jump(ifTruthy);
     795          30 : }
     796             : 
     797             : void
     798           0 : CodeGenerator::visitTestOAndBranch(LTestOAndBranch* lir)
     799             : {
     800           0 :     MIRType inputType = lir->mir()->input()->type();
     801           0 :     MOZ_ASSERT(inputType == MIRType::ObjectOrNull || lir->mir()->operandMightEmulateUndefined(),
     802             :                "If the object couldn't emulate undefined, this should have been folded.");
     803             : 
     804           0 :     Label* truthy = getJumpLabelForBranch(lir->ifTruthy());
     805           0 :     Label* falsy = getJumpLabelForBranch(lir->ifFalsy());
     806           0 :     Register input = ToRegister(lir->input());
     807             : 
     808           0 :     if (lir->mir()->operandMightEmulateUndefined()) {
     809           0 :         if (inputType == MIRType::ObjectOrNull)
     810           0 :             masm.branchTestPtr(Assembler::Zero, input, input, falsy);
     811             : 
     812           0 :         OutOfLineTestObject* ool = new(alloc()) OutOfLineTestObject();
     813           0 :         addOutOfLineCode(ool, lir->mir());
     814             : 
     815           0 :         testObjectEmulatesUndefined(input, falsy, truthy, ToRegister(lir->temp()), ool);
     816             :     } else {
     817           0 :         MOZ_ASSERT(inputType == MIRType::ObjectOrNull);
     818           0 :         testZeroEmitBranch(Assembler::NotEqual, input, lir->ifTruthy(), lir->ifFalsy());
     819             :     }
     820           0 : }
     821             : 
     822             : void
     823          30 : CodeGenerator::visitTestVAndBranch(LTestVAndBranch* lir)
     824             : {
     825          30 :     OutOfLineTestObject* ool = nullptr;
     826          30 :     MDefinition* input = lir->mir()->input();
     827             :     // Unfortunately, it's possible that someone (e.g. phi elimination) switched
     828             :     // out our input after we did cacheOperandMightEmulateUndefined.  So we
     829             :     // might think it can emulate undefined _and_ know that it can't be an
     830             :     // object.
     831          30 :     if (lir->mir()->operandMightEmulateUndefined() && input->mightBeType(MIRType::Object)) {
     832           0 :         ool = new(alloc()) OutOfLineTestObject();
     833           0 :         addOutOfLineCode(ool, lir->mir());
     834             :     }
     835             : 
     836          30 :     Label* truthy = getJumpLabelForBranch(lir->ifTruthy());
     837          30 :     Label* falsy = getJumpLabelForBranch(lir->ifFalsy());
     838             : 
     839          60 :     testValueTruthy(ToValue(lir, LTestVAndBranch::Input),
     840             :                     lir->temp1(), lir->temp2(),
     841             :                     ToFloatRegister(lir->tempFloat()),
     842          30 :                     truthy, falsy, ool, input);
     843          30 : }
     844             : 
     845             : void
     846           3 : CodeGenerator::visitFunctionDispatch(LFunctionDispatch* lir)
     847             : {
     848           3 :     MFunctionDispatch* mir = lir->mir();
     849           3 :     Register input = ToRegister(lir->input());
     850             :     Label* lastLabel;
     851             :     size_t casesWithFallback;
     852             : 
     853             :     // Determine if the last case is fallback or an ordinary case.
     854           3 :     if (!mir->hasFallback()) {
     855           0 :         MOZ_ASSERT(mir->numCases() > 0);
     856           0 :         casesWithFallback = mir->numCases();
     857           0 :         lastLabel = skipTrivialBlocks(mir->getCaseBlock(mir->numCases() - 1))->lir()->label();
     858             :     } else {
     859           3 :         casesWithFallback = mir->numCases() + 1;
     860           3 :         lastLabel = skipTrivialBlocks(mir->getFallback())->lir()->label();
     861             :     }
     862             : 
     863             :     // Compare function pointers, except for the last case.
     864           6 :     for (size_t i = 0; i < casesWithFallback - 1; i++) {
     865           3 :         MOZ_ASSERT(i < mir->numCases());
     866           3 :         LBlock* target = skipTrivialBlocks(mir->getCaseBlock(i))->lir();
     867           3 :         if (ObjectGroup* funcGroup = mir->getCaseObjectGroup(i)) {
     868           6 :             masm.branchPtr(Assembler::Equal, Address(input, JSObject::offsetOfGroup()),
     869           3 :                            ImmGCPtr(funcGroup), target->label());
     870             :         } else {
     871           0 :             JSFunction* func = mir->getCase(i);
     872           0 :             masm.branchPtr(Assembler::Equal, input, ImmGCPtr(func), target->label());
     873             :         }
     874             :     }
     875             : 
     876             :     // Jump to the last case.
     877           3 :     masm.jump(lastLabel);
     878           3 : }
     879             : 
     880             : void
     881           0 : CodeGenerator::visitObjectGroupDispatch(LObjectGroupDispatch* lir)
     882             : {
     883           0 :     MObjectGroupDispatch* mir = lir->mir();
     884           0 :     Register input = ToRegister(lir->input());
     885           0 :     Register temp = ToRegister(lir->temp());
     886             : 
     887             :     // Load the incoming ObjectGroup in temp.
     888           0 :     masm.loadPtr(Address(input, JSObject::offsetOfGroup()), temp);
     889             : 
     890             :     // Compare ObjectGroups.
     891           0 :     MacroAssembler::BranchGCPtr lastBranch;
     892           0 :     LBlock* lastBlock = nullptr;
     893           0 :     InlinePropertyTable* propTable = mir->propTable();
     894           0 :     for (size_t i = 0; i < mir->numCases(); i++) {
     895           0 :         JSFunction* func = mir->getCase(i);
     896           0 :         LBlock* target = skipTrivialBlocks(mir->getCaseBlock(i))->lir();
     897             : 
     898           0 :         DebugOnly<bool> found = false;
     899           0 :         for (size_t j = 0; j < propTable->numEntries(); j++) {
     900           0 :             if (propTable->getFunction(j) != func)
     901           0 :                 continue;
     902             : 
     903           0 :             if (lastBranch.isInitialized())
     904           0 :                 lastBranch.emit(masm);
     905             : 
     906           0 :             ObjectGroup* group = propTable->getObjectGroup(j);
     907           0 :             lastBranch = MacroAssembler::BranchGCPtr(Assembler::Equal, temp, ImmGCPtr(group),
     908           0 :                                                      target->label());
     909           0 :             lastBlock = target;
     910           0 :             found = true;
     911             :         }
     912           0 :         MOZ_ASSERT(found);
     913             :     }
     914             : 
     915             :     // Jump to fallback block if we have an unknown ObjectGroup. If there's no
     916             :     // fallback block, we should have handled all cases.
     917             : 
     918           0 :     if (!mir->hasFallback()) {
     919           0 :         MOZ_ASSERT(lastBranch.isInitialized());
     920             : #ifdef DEBUG
     921           0 :         Label ok;
     922           0 :         lastBranch.relink(&ok);
     923           0 :         lastBranch.emit(masm);
     924           0 :         masm.assumeUnreachable("Unexpected ObjectGroup");
     925           0 :         masm.bind(&ok);
     926             : #endif
     927           0 :         if (!isNextBlock(lastBlock))
     928           0 :             masm.jump(lastBlock->label());
     929           0 :         return;
     930             :     }
     931             : 
     932           0 :     LBlock* fallback = skipTrivialBlocks(mir->getFallback())->lir();
     933           0 :     if (!lastBranch.isInitialized()) {
     934           0 :         if (!isNextBlock(fallback))
     935           0 :             masm.jump(fallback->label());
     936           0 :         return;
     937             :     }
     938             : 
     939           0 :     lastBranch.invertCondition();
     940           0 :     lastBranch.relink(fallback->label());
     941           0 :     lastBranch.emit(masm);
     942             : 
     943           0 :     if (!isNextBlock(lastBlock))
     944           0 :         masm.jump(lastBlock->label());
     945             : }
     946             : 
     947             : void
     948           0 : CodeGenerator::visitBooleanToString(LBooleanToString* lir)
     949             : {
     950           0 :     Register input = ToRegister(lir->input());
     951           0 :     Register output = ToRegister(lir->output());
     952           0 :     const JSAtomState& names = GetJitContext()->runtime->names();
     953           0 :     Label true_, done;
     954             : 
     955           0 :     masm.branchTest32(Assembler::NonZero, input, input, &true_);
     956           0 :     masm.movePtr(ImmGCPtr(names.false_), output);
     957           0 :     masm.jump(&done);
     958             : 
     959           0 :     masm.bind(&true_);
     960           0 :     masm.movePtr(ImmGCPtr(names.true_), output);
     961             : 
     962           0 :     masm.bind(&done);
     963           0 : }
     964             : 
     965             : void
     966           0 : CodeGenerator::emitIntToString(Register input, Register output, Label* ool)
     967             : {
     968           0 :     masm.branch32(Assembler::AboveOrEqual, input, Imm32(StaticStrings::INT_STATIC_LIMIT), ool);
     969             : 
     970             :     // Fast path for small integers.
     971           0 :     masm.movePtr(ImmPtr(&GetJitContext()->runtime->staticStrings().intStaticTable), output);
     972           0 :     masm.loadPtr(BaseIndex(output, input, ScalePointer), output);
     973           0 : }
     974             : 
     975             : typedef JSFlatString* (*IntToStringFn)(JSContext*, int);
     976           3 : static const VMFunction IntToStringInfo =
     977           6 :     FunctionInfo<IntToStringFn>(Int32ToString<CanGC>, "Int32ToString");
     978             : 
     979             : void
     980           0 : CodeGenerator::visitIntToString(LIntToString* lir)
     981             : {
     982           0 :     Register input = ToRegister(lir->input());
     983           0 :     Register output = ToRegister(lir->output());
     984             : 
     985           0 :     OutOfLineCode* ool = oolCallVM(IntToStringInfo, lir, ArgList(input),
     986           0 :                                    StoreRegisterTo(output));
     987             : 
     988           0 :     emitIntToString(input, output, ool->entry());
     989             : 
     990           0 :     masm.bind(ool->rejoin());
     991           0 : }
     992             : 
     993             : typedef JSString* (*DoubleToStringFn)(JSContext*, double);
     994           3 : static const VMFunction DoubleToStringInfo =
     995           6 :     FunctionInfo<DoubleToStringFn>(NumberToString<CanGC>, "NumberToString");
     996             : 
     997             : void
     998           0 : CodeGenerator::visitDoubleToString(LDoubleToString* lir)
     999             : {
    1000           0 :     FloatRegister input = ToFloatRegister(lir->input());
    1001           0 :     Register temp = ToRegister(lir->tempInt());
    1002           0 :     Register output = ToRegister(lir->output());
    1003             : 
    1004           0 :     OutOfLineCode* ool = oolCallVM(DoubleToStringInfo, lir, ArgList(input),
    1005           0 :                                    StoreRegisterTo(output));
    1006             : 
    1007             :     // Try double to integer conversion and run integer to string code.
    1008           0 :     masm.convertDoubleToInt32(input, temp, ool->entry(), true);
    1009           0 :     emitIntToString(temp, output, ool->entry());
    1010             : 
    1011           0 :     masm.bind(ool->rejoin());
    1012           0 : }
    1013             : 
    1014             : typedef JSString* (*PrimitiveToStringFn)(JSContext*, HandleValue);
    1015           3 : static const VMFunction PrimitiveToStringInfo =
    1016           6 :     FunctionInfo<PrimitiveToStringFn>(ToStringSlow, "ToStringSlow");
    1017             : 
    1018             : void
    1019           4 : CodeGenerator::visitValueToString(LValueToString* lir)
    1020             : {
    1021           4 :     ValueOperand input = ToValue(lir, LValueToString::Input);
    1022           4 :     Register output = ToRegister(lir->output());
    1023             : 
    1024           8 :     OutOfLineCode* ool = oolCallVM(PrimitiveToStringInfo, lir, ArgList(input),
    1025          12 :                                    StoreRegisterTo(output));
    1026             : 
    1027           8 :     Label done;
    1028           4 :     Register tag = masm.splitTagForTest(input);
    1029           4 :     const JSAtomState& names = GetJitContext()->runtime->names();
    1030             : 
    1031             :     // String
    1032           4 :     if (lir->mir()->input()->mightBeType(MIRType::String)) {
    1033           8 :         Label notString;
    1034           4 :         masm.branchTestString(Assembler::NotEqual, tag, &notString);
    1035           4 :         masm.unboxString(input, output);
    1036           4 :         masm.jump(&done);
    1037           4 :         masm.bind(&notString);
    1038             :     }
    1039             : 
    1040             :     // Integer
    1041           4 :     if (lir->mir()->input()->mightBeType(MIRType::Int32)) {
    1042           0 :         Label notInteger;
    1043           0 :         masm.branchTestInt32(Assembler::NotEqual, tag, &notInteger);
    1044           0 :         Register unboxed = ToTempUnboxRegister(lir->tempToUnbox());
    1045           0 :         unboxed = masm.extractInt32(input, unboxed);
    1046           0 :         emitIntToString(unboxed, output, ool->entry());
    1047           0 :         masm.jump(&done);
    1048           0 :         masm.bind(&notInteger);
    1049             :     }
    1050             : 
    1051             :     // Double
    1052           4 :     if (lir->mir()->input()->mightBeType(MIRType::Double)) {
    1053             :         // Note: no fastpath. Need two extra registers and can only convert doubles
    1054             :         // that fit integers and are smaller than StaticStrings::INT_STATIC_LIMIT.
    1055           0 :         masm.branchTestDouble(Assembler::Equal, tag, ool->entry());
    1056             :     }
    1057             : 
    1058             :     // Undefined
    1059           4 :     if (lir->mir()->input()->mightBeType(MIRType::Undefined)) {
    1060           8 :         Label notUndefined;
    1061           4 :         masm.branchTestUndefined(Assembler::NotEqual, tag, &notUndefined);
    1062           4 :         masm.movePtr(ImmGCPtr(names.undefined), output);
    1063           4 :         masm.jump(&done);
    1064           4 :         masm.bind(&notUndefined);
    1065             :     }
    1066             : 
    1067             :     // Null
    1068           4 :     if (lir->mir()->input()->mightBeType(MIRType::Null)) {
    1069           0 :         Label notNull;
    1070           0 :         masm.branchTestNull(Assembler::NotEqual, tag, &notNull);
    1071           0 :         masm.movePtr(ImmGCPtr(names.null), output);
    1072           0 :         masm.jump(&done);
    1073           0 :         masm.bind(&notNull);
    1074             :     }
    1075             : 
    1076             :     // Boolean
    1077           4 :     if (lir->mir()->input()->mightBeType(MIRType::Boolean)) {
    1078           0 :         Label notBoolean, true_;
    1079           0 :         masm.branchTestBoolean(Assembler::NotEqual, tag, &notBoolean);
    1080           0 :         masm.branchTestBooleanTruthy(true, input, &true_);
    1081           0 :         masm.movePtr(ImmGCPtr(names.false_), output);
    1082           0 :         masm.jump(&done);
    1083           0 :         masm.bind(&true_);
    1084           0 :         masm.movePtr(ImmGCPtr(names.true_), output);
    1085           0 :         masm.jump(&done);
    1086           0 :         masm.bind(&notBoolean);
    1087             :     }
    1088             : 
    1089             :     // Object
    1090           4 :     if (lir->mir()->input()->mightBeType(MIRType::Object)) {
    1091             :         // Bail.
    1092           0 :         MOZ_ASSERT(lir->mir()->fallible());
    1093           0 :         Label bail;
    1094           0 :         masm.branchTestObject(Assembler::Equal, tag, &bail);
    1095           0 :         bailoutFrom(&bail, lir->snapshot());
    1096             :     }
    1097             : 
    1098             :     // Symbol
    1099           4 :     if (lir->mir()->input()->mightBeType(MIRType::Symbol)) {
    1100             :         // Bail.
    1101           0 :         MOZ_ASSERT(lir->mir()->fallible());
    1102           0 :         Label bail;
    1103           0 :         masm.branchTestSymbol(Assembler::Equal, tag, &bail);
    1104           0 :         bailoutFrom(&bail, lir->snapshot());
    1105             :     }
    1106             : 
    1107             : #ifdef DEBUG
    1108           4 :     masm.assumeUnreachable("Unexpected type for MValueToString.");
    1109             : #endif
    1110             : 
    1111           4 :     masm.bind(&done);
    1112           4 :     masm.bind(ool->rejoin());
    1113           4 : }
    1114             : 
    1115             : typedef JSObject* (*ToObjectFn)(JSContext*, HandleValue, bool);
    1116           3 : static const VMFunction ToObjectInfo =
    1117           6 :     FunctionInfo<ToObjectFn>(ToObjectSlow, "ToObjectSlow");
    1118             : 
    1119             : void
    1120           0 : CodeGenerator::visitValueToObjectOrNull(LValueToObjectOrNull* lir)
    1121             : {
    1122           0 :     ValueOperand input = ToValue(lir, LValueToObjectOrNull::Input);
    1123           0 :     Register output = ToRegister(lir->output());
    1124             : 
    1125           0 :     OutOfLineCode* ool = oolCallVM(ToObjectInfo, lir, ArgList(input, Imm32(0)),
    1126           0 :                                    StoreRegisterTo(output));
    1127             : 
    1128           0 :     Label done;
    1129           0 :     masm.branchTestObject(Assembler::Equal, input, &done);
    1130           0 :     masm.branchTestNull(Assembler::NotEqual, input, ool->entry());
    1131             : 
    1132           0 :     masm.bind(&done);
    1133           0 :     masm.unboxNonDouble(input, output);
    1134             : 
    1135           0 :     masm.bind(ool->rejoin());
    1136           0 : }
    1137             : 
    1138             : typedef JSObject* (*CloneRegExpObjectFn)(JSContext*, Handle<RegExpObject*>);
    1139           3 : static const VMFunction CloneRegExpObjectInfo =
    1140           6 :     FunctionInfo<CloneRegExpObjectFn>(CloneRegExpObject, "CloneRegExpObject");
    1141             : 
    1142             : void
    1143           0 : CodeGenerator::visitRegExp(LRegExp* lir)
    1144             : {
    1145           0 :     Register output = ToRegister(lir->output());
    1146           0 :     Register temp = ToRegister(lir->temp());
    1147           0 :     JSObject* templateObject = lir->mir()->source();
    1148             : 
    1149           0 :     OutOfLineCode *ool = oolCallVM(CloneRegExpObjectInfo, lir, ArgList(ImmGCPtr(lir->mir()->source())),
    1150           0 :                                    StoreRegisterTo(output));
    1151           0 :     if (lir->mir()->hasShared())
    1152           0 :         masm.createGCObject(output, temp, templateObject, gc::DefaultHeap, ool->entry());
    1153             :     else
    1154           0 :         masm.jump(ool->entry());
    1155           0 :     masm.bind(ool->rejoin());
    1156           0 : }
    1157             : 
    1158             : // Amount of space to reserve on the stack when executing RegExps inline.
    1159             : static const size_t RegExpReservedStack = sizeof(irregexp::InputOutputData)
    1160             :                                         + sizeof(MatchPairs)
    1161             :                                         + RegExpObject::MaxPairCount * sizeof(MatchPair);
    1162             : 
    1163             : static size_t
    1164           0 : RegExpPairsVectorStartOffset(size_t inputOutputDataStartOffset)
    1165             : {
    1166           0 :     return inputOutputDataStartOffset + sizeof(irregexp::InputOutputData) + sizeof(MatchPairs);
    1167             : }
    1168             : 
    1169             : static Address
    1170           0 : RegExpPairCountAddress(MacroAssembler& masm, size_t inputOutputDataStartOffset)
    1171             : {
    1172           0 :     return Address(masm.getStackPointer(), inputOutputDataStartOffset
    1173             :                                            + sizeof(irregexp::InputOutputData)
    1174           0 :                                            + MatchPairs::offsetOfPairCount());
    1175             : }
    1176             : 
    1177             : // Prepare an InputOutputData and optional MatchPairs which space has been
    1178             : // allocated for on the stack, and try to execute a RegExp on a string input.
    1179             : // If the RegExp was successfully executed and matched the input, fallthrough,
    1180             : // otherwise jump to notFound or failure.
    1181             : static bool
    1182           0 : PrepareAndExecuteRegExp(JSContext* cx, MacroAssembler& masm, Register regexp, Register input,
    1183             :                         Register lastIndex,
    1184             :                         Register temp1, Register temp2, Register temp3,
    1185             :                         size_t inputOutputDataStartOffset,
    1186             :                         RegExpShared::CompilationMode mode,
    1187             :                         Label* notFound, Label* failure)
    1188             : {
    1189           0 :     size_t matchPairsStartOffset = inputOutputDataStartOffset + sizeof(irregexp::InputOutputData);
    1190           0 :     size_t pairsVectorStartOffset = RegExpPairsVectorStartOffset(inputOutputDataStartOffset);
    1191             : 
    1192             :     Address inputStartAddress(masm.getStackPointer(),
    1193           0 :         inputOutputDataStartOffset + offsetof(irregexp::InputOutputData, inputStart));
    1194             :     Address inputEndAddress(masm.getStackPointer(),
    1195           0 :         inputOutputDataStartOffset + offsetof(irregexp::InputOutputData, inputEnd));
    1196             :     Address matchesPointerAddress(masm.getStackPointer(),
    1197           0 :         inputOutputDataStartOffset + offsetof(irregexp::InputOutputData, matches));
    1198             :     Address startIndexAddress(masm.getStackPointer(),
    1199           0 :         inputOutputDataStartOffset + offsetof(irregexp::InputOutputData, startIndex));
    1200             :     Address endIndexAddress(masm.getStackPointer(),
    1201           0 :         inputOutputDataStartOffset + offsetof(irregexp::InputOutputData, endIndex));
    1202             :     Address matchResultAddress(masm.getStackPointer(),
    1203           0 :         inputOutputDataStartOffset + offsetof(irregexp::InputOutputData, result));
    1204             : 
    1205           0 :     Address pairCountAddress = RegExpPairCountAddress(masm, inputOutputDataStartOffset);
    1206             :     Address pairsPointerAddress(masm.getStackPointer(),
    1207           0 :         matchPairsStartOffset + MatchPairs::offsetOfPairs());
    1208             : 
    1209           0 :     Address pairsVectorAddress(masm.getStackPointer(), pairsVectorStartOffset);
    1210             : 
    1211           0 :     RegExpStatics* res = GlobalObject::getRegExpStatics(cx, cx->global());
    1212           0 :     if (!res)
    1213           0 :         return false;
    1214             : #ifdef JS_USE_LINK_REGISTER
    1215             :     if (mode != RegExpShared::MatchOnly)
    1216             :         masm.pushReturnAddress();
    1217             : #endif
    1218           0 :     if (mode == RegExpShared::Normal) {
    1219             :         // First, fill in a skeletal MatchPairs instance on the stack. This will be
    1220             :         // passed to the OOL stub in the caller if we aren't able to execute the
    1221             :         // RegExp inline, and that stub needs to be able to determine whether the
    1222             :         // execution finished successfully.
    1223           0 :         masm.store32(Imm32(1), pairCountAddress);
    1224           0 :         masm.store32(Imm32(-1), pairsVectorAddress);
    1225           0 :         masm.computeEffectiveAddress(pairsVectorAddress, temp1);
    1226           0 :         masm.storePtr(temp1, pairsPointerAddress);
    1227             :     }
    1228             : 
    1229             :     // Check for a linear input string.
    1230           0 :     masm.branchIfRopeOrExternal(input, temp1, failure);
    1231             : 
    1232             :     // Get the RegExpShared for the RegExp.
    1233           0 :     masm.loadPtr(Address(regexp, NativeObject::getFixedSlotOffset(RegExpObject::PRIVATE_SLOT)), temp1);
    1234           0 :     masm.branchPtr(Assembler::Equal, temp1, ImmWord(0), failure);
    1235             : 
    1236             :     // ES6 21.2.2.2 step 2.
    1237             :     // See RegExp.cpp ExecuteRegExp for more detail.
    1238             :     {
    1239           0 :         Label done;
    1240             : 
    1241           0 :         masm.branchTest32(Assembler::Zero, Address(temp1, RegExpShared::offsetOfFlags()),
    1242           0 :                           Imm32(UnicodeFlag), &done);
    1243             : 
    1244             :         // If input is latin1, there should not be surrogate pair.
    1245           0 :         masm.branchLatin1String(input, &done);
    1246             : 
    1247             :         // Check if |lastIndex > 0 && lastIndex < input->length()|.
    1248             :         // lastIndex should already have no sign here.
    1249           0 :         masm.branchTest32(Assembler::Zero, lastIndex, lastIndex, &done);
    1250           0 :         masm.loadStringLength(input, temp2);
    1251           0 :         masm.branch32(Assembler::AboveOrEqual, lastIndex, temp2, &done);
    1252             : 
    1253             :         // Check if input[lastIndex] is trail surrogate.
    1254           0 :         masm.loadStringChars(input, temp2);
    1255           0 :         masm.computeEffectiveAddress(BaseIndex(temp2, lastIndex, TimesTwo), temp3);
    1256           0 :         masm.load16ZeroExtend(Address(temp3, 0), temp3);
    1257             : 
    1258           0 :         masm.branch32(Assembler::Below, temp3, Imm32(unicode::TrailSurrogateMin), &done);
    1259           0 :         masm.branch32(Assembler::Above, temp3, Imm32(unicode::TrailSurrogateMax), &done);
    1260             : 
    1261             :         // Check if input[lastIndex-1] is lead surrogate.
    1262           0 :         masm.move32(lastIndex, temp3);
    1263           0 :         masm.sub32(Imm32(1), temp3);
    1264           0 :         masm.computeEffectiveAddress(BaseIndex(temp2, temp3, TimesTwo), temp3);
    1265           0 :         masm.load16ZeroExtend(Address(temp3, 0), temp3);
    1266             : 
    1267           0 :         masm.branch32(Assembler::Below, temp3, Imm32(unicode::LeadSurrogateMin), &done);
    1268           0 :         masm.branch32(Assembler::Above, temp3, Imm32(unicode::LeadSurrogateMax), &done);
    1269             : 
    1270             :         // Move lastIndex to lead surrogate.
    1271           0 :         masm.subPtr(Imm32(1), lastIndex);
    1272             : 
    1273           0 :         masm.bind(&done);
    1274             :     }
    1275             : 
    1276           0 :     if (mode == RegExpShared::Normal) {
    1277             :         // Don't handle RegExps with excessive parens.
    1278           0 :         masm.load32(Address(temp1, RegExpShared::offsetOfParenCount()), temp2);
    1279           0 :         masm.branch32(Assembler::AboveOrEqual, temp2, Imm32(RegExpObject::MaxPairCount), failure);
    1280             : 
    1281             :         // Fill in the paren count in the MatchPairs on the stack.
    1282           0 :         masm.add32(Imm32(1), temp2);
    1283           0 :         masm.store32(temp2, pairCountAddress);
    1284             :     }
    1285             : 
    1286             :     // Load the code pointer for the type of input string we have, and compute
    1287             :     // the input start/end pointers in the InputOutputData.
    1288           0 :     Register codePointer = temp1;
    1289             :     {
    1290           0 :         masm.loadStringChars(input, temp2);
    1291           0 :         masm.storePtr(temp2, inputStartAddress);
    1292           0 :         masm.loadStringLength(input, temp3);
    1293             : 
    1294           0 :         Label isLatin1, done;
    1295           0 :         masm.branchLatin1String(input, &isLatin1);
    1296             :         {
    1297           0 :             masm.lshiftPtr(Imm32(1), temp3);
    1298           0 :             masm.loadPtr(Address(temp1, RegExpShared::offsetOfTwoByteJitCode(mode)),
    1299           0 :                          codePointer);
    1300             :         }
    1301           0 :         masm.jump(&done);
    1302             :         {
    1303           0 :             masm.bind(&isLatin1);
    1304           0 :             masm.loadPtr(Address(temp1, RegExpShared::offsetOfLatin1JitCode(mode)),
    1305           0 :                          codePointer);
    1306             :         }
    1307           0 :         masm.bind(&done);
    1308             : 
    1309           0 :         masm.addPtr(temp3, temp2);
    1310           0 :         masm.storePtr(temp2, inputEndAddress);
    1311             :     }
    1312             : 
    1313             :     // Check the RegExpShared has been compiled for this type of input.
    1314           0 :     masm.branchPtr(Assembler::Equal, codePointer, ImmWord(0), failure);
    1315           0 :     masm.loadPtr(Address(codePointer, JitCode::offsetOfCode()), codePointer);
    1316             : 
    1317             :     // Finish filling in the InputOutputData instance on the stack.
    1318           0 :     if (mode == RegExpShared::Normal) {
    1319           0 :         masm.computeEffectiveAddress(Address(masm.getStackPointer(), matchPairsStartOffset), temp2);
    1320           0 :         masm.storePtr(temp2, matchesPointerAddress);
    1321             :     } else {
    1322             :         // Use InputOutputData.endIndex itself for output.
    1323           0 :         masm.computeEffectiveAddress(endIndexAddress, temp2);
    1324           0 :         masm.storePtr(temp2, endIndexAddress);
    1325             :     }
    1326           0 :     masm.storePtr(lastIndex, startIndexAddress);
    1327           0 :     masm.store32(Imm32(0), matchResultAddress);
    1328             : 
    1329             :     // Save any volatile inputs.
    1330           0 :     LiveGeneralRegisterSet volatileRegs;
    1331           0 :     if (lastIndex.volatile_())
    1332           0 :         volatileRegs.add(lastIndex);
    1333           0 :     if (input.volatile_())
    1334           0 :         volatileRegs.add(input);
    1335           0 :     if (regexp.volatile_())
    1336           0 :         volatileRegs.add(regexp);
    1337             : 
    1338             : #ifdef JS_TRACE_LOGGING
    1339           0 :     if (TraceLogTextIdEnabled(TraceLogger_IrregexpExecute)) {
    1340           0 :         masm.push(temp1);
    1341           0 :         masm.loadTraceLogger(temp1);
    1342           0 :         masm.tracelogStartId(temp1, TraceLogger_IrregexpExecute);
    1343           0 :         masm.pop(temp1);
    1344             :     }
    1345             : #endif
    1346             : 
    1347             :     // Execute the RegExp.
    1348           0 :     masm.computeEffectiveAddress(Address(masm.getStackPointer(), inputOutputDataStartOffset), temp2);
    1349           0 :     masm.PushRegsInMask(volatileRegs);
    1350           0 :     masm.setupUnalignedABICall(temp3);
    1351           0 :     masm.passABIArg(temp2);
    1352           0 :     masm.callWithABI(codePointer);
    1353           0 :     masm.PopRegsInMask(volatileRegs);
    1354             : 
    1355             : #ifdef JS_TRACE_LOGGING
    1356           0 :     if (TraceLogTextIdEnabled(TraceLogger_IrregexpExecute)) {
    1357           0 :         masm.loadTraceLogger(temp1);
    1358           0 :         masm.tracelogStopId(temp1, TraceLogger_IrregexpExecute);
    1359             :     }
    1360             : #endif
    1361             : 
    1362           0 :     Label success;
    1363           0 :     masm.branch32(Assembler::Equal, matchResultAddress,
    1364           0 :                   Imm32(RegExpRunStatus_Success_NotFound), notFound);
    1365           0 :     masm.branch32(Assembler::Equal, matchResultAddress,
    1366           0 :                   Imm32(RegExpRunStatus_Error), failure);
    1367             : 
    1368             :     // Lazily update the RegExpStatics.
    1369           0 :     masm.movePtr(ImmPtr(res), temp1);
    1370             : 
    1371           0 :     Address pendingInputAddress(temp1, RegExpStatics::offsetOfPendingInput());
    1372           0 :     Address matchesInputAddress(temp1, RegExpStatics::offsetOfMatchesInput());
    1373           0 :     Address lazySourceAddress(temp1, RegExpStatics::offsetOfLazySource());
    1374           0 :     Address lazyIndexAddress(temp1, RegExpStatics::offsetOfLazyIndex());
    1375             : 
    1376           0 :     masm.guardedCallPreBarrier(pendingInputAddress, MIRType::String);
    1377           0 :     masm.guardedCallPreBarrier(matchesInputAddress, MIRType::String);
    1378           0 :     masm.guardedCallPreBarrier(lazySourceAddress, MIRType::String);
    1379             : 
    1380           0 :     masm.storePtr(input, pendingInputAddress);
    1381           0 :     masm.storePtr(input, matchesInputAddress);
    1382           0 :     masm.storePtr(lastIndex, Address(temp1, RegExpStatics::offsetOfLazyIndex()));
    1383           0 :     masm.store32(Imm32(1), Address(temp1, RegExpStatics::offsetOfPendingLazyEvaluation()));
    1384             : 
    1385           0 :     masm.loadPtr(Address(regexp, NativeObject::getFixedSlotOffset(RegExpObject::PRIVATE_SLOT)), temp2);
    1386           0 :     masm.loadPtr(Address(temp2, RegExpShared::offsetOfSource()), temp3);
    1387           0 :     masm.storePtr(temp3, lazySourceAddress);
    1388           0 :     masm.load32(Address(temp2, RegExpShared::offsetOfFlags()), temp3);
    1389           0 :     masm.store32(temp3, Address(temp1, RegExpStatics::offsetOfLazyFlags()));
    1390             : 
    1391           0 :     if (mode == RegExpShared::MatchOnly) {
    1392             :         // endIndex is passed via temp3.
    1393           0 :         masm.load32(endIndexAddress, temp3);
    1394             :     }
    1395             : 
    1396           0 :     return true;
    1397             : }
    1398             : 
    1399             : static void
    1400             : CopyStringChars(MacroAssembler& masm, Register to, Register from, Register len,
    1401             :                 Register byteOpScratch, size_t fromWidth, size_t toWidth);
    1402             : 
    1403           0 : class CreateDependentString
    1404             : {
    1405             :     Register string_;
    1406             :     Register temp_;
    1407             :     Label* failure_;
    1408             :     enum class FallbackKind : uint8_t {
    1409             :         InlineString,
    1410             :         FatInlineString,
    1411             :         NotInlineString,
    1412             :         Count
    1413             :     };
    1414             :     mozilla::EnumeratedArray<FallbackKind, FallbackKind::Count, Label> fallbacks_, joins_;
    1415             : 
    1416             : public:
    1417             :     // Generate code that creates DependentString.
    1418             :     // Caller should call generateFallback after masm.ret(), to generate
    1419             :     // fallback path.
    1420             :     void generate(MacroAssembler& masm, const JSAtomState& names,
    1421             :                   bool latin1, Register string,
    1422             :                   Register base, Register temp1, Register temp2,
    1423             :                   BaseIndex startIndexAddress, BaseIndex limitIndexAddress,
    1424             :                   Label* failure);
    1425             : 
    1426             :     // Generate fallback path for creating DependentString.
    1427             :     void generateFallback(MacroAssembler& masm, LiveRegisterSet regsToSave);
    1428             : };
    1429             : 
    1430             : void
    1431           0 : CreateDependentString::generate(MacroAssembler& masm, const JSAtomState& names,
    1432             :                                 bool latin1, Register string,
    1433             :                                 Register base, Register temp1, Register temp2,
    1434             :                                 BaseIndex startIndexAddress, BaseIndex limitIndexAddress,
    1435             :                                 Label* failure)
    1436             : {
    1437           0 :     string_ = string;
    1438           0 :     temp_ = temp2;
    1439           0 :     failure_ = failure;
    1440             : 
    1441             :     // Compute the string length.
    1442           0 :     masm.load32(startIndexAddress, temp2);
    1443           0 :     masm.load32(limitIndexAddress, temp1);
    1444           0 :     masm.sub32(temp2, temp1);
    1445             : 
    1446           0 :     Label done, nonEmpty;
    1447             : 
    1448             :     // Zero length matches use the empty string.
    1449           0 :     masm.branchTest32(Assembler::NonZero, temp1, temp1, &nonEmpty);
    1450           0 :     masm.movePtr(ImmGCPtr(names.empty), string);
    1451           0 :     masm.jump(&done);
    1452             : 
    1453           0 :     masm.bind(&nonEmpty);
    1454             : 
    1455           0 :     Label notInline;
    1456             : 
    1457             :     int32_t maxInlineLength = latin1
    1458           0 :                               ? (int32_t) JSFatInlineString::MAX_LENGTH_LATIN1
    1459           0 :                               : (int32_t) JSFatInlineString::MAX_LENGTH_TWO_BYTE;
    1460           0 :     masm.branch32(Assembler::Above, temp1, Imm32(maxInlineLength), &notInline);
    1461             : 
    1462             :     {
    1463             :         // Make a thin or fat inline string.
    1464           0 :         Label stringAllocated, fatInline;
    1465             : 
    1466             :         int32_t maxThinInlineLength = latin1
    1467           0 :                                       ? (int32_t) JSThinInlineString::MAX_LENGTH_LATIN1
    1468           0 :                                       : (int32_t) JSThinInlineString::MAX_LENGTH_TWO_BYTE;
    1469           0 :         masm.branch32(Assembler::Above, temp1, Imm32(maxThinInlineLength), &fatInline);
    1470             : 
    1471           0 :         int32_t thinFlags = (latin1 ? JSString::LATIN1_CHARS_BIT : 0) | JSString::INIT_THIN_INLINE_FLAGS;
    1472           0 :         masm.newGCString(string, temp2, &fallbacks_[FallbackKind::InlineString]);
    1473           0 :         masm.bind(&joins_[FallbackKind::InlineString]);
    1474           0 :         masm.store32(Imm32(thinFlags), Address(string, JSString::offsetOfFlags()));
    1475           0 :         masm.jump(&stringAllocated);
    1476             : 
    1477           0 :         masm.bind(&fatInline);
    1478             : 
    1479           0 :         int32_t fatFlags = (latin1 ? JSString::LATIN1_CHARS_BIT : 0) | JSString::INIT_FAT_INLINE_FLAGS;
    1480           0 :         masm.newGCFatInlineString(string, temp2, &fallbacks_[FallbackKind::FatInlineString]);
    1481           0 :         masm.bind(&joins_[FallbackKind::FatInlineString]);
    1482           0 :         masm.store32(Imm32(fatFlags), Address(string, JSString::offsetOfFlags()));
    1483             : 
    1484           0 :         masm.bind(&stringAllocated);
    1485           0 :         masm.store32(temp1, Address(string, JSString::offsetOfLength()));
    1486             : 
    1487           0 :         masm.push(string);
    1488           0 :         masm.push(base);
    1489             : 
    1490             :         // Adjust the start index address for the above pushes.
    1491           0 :         MOZ_ASSERT(startIndexAddress.base == masm.getStackPointer());
    1492           0 :         BaseIndex newStartIndexAddress = startIndexAddress;
    1493           0 :         newStartIndexAddress.offset += 2 * sizeof(void*);
    1494             : 
    1495             :         // Load chars pointer for the new string.
    1496           0 :         masm.addPtr(ImmWord(JSInlineString::offsetOfInlineStorage()), string);
    1497             : 
    1498             :         // Load the source characters pointer.
    1499           0 :         masm.loadStringChars(base, base);
    1500           0 :         masm.load32(newStartIndexAddress, temp2);
    1501           0 :         if (latin1)
    1502           0 :             masm.addPtr(temp2, base);
    1503             :         else
    1504           0 :             masm.computeEffectiveAddress(BaseIndex(base, temp2, TimesTwo), base);
    1505             : 
    1506           0 :         CopyStringChars(masm, string, base, temp1, temp2, latin1 ? 1 : 2, latin1 ? 1 : 2);
    1507             : 
    1508             :         // Null-terminate.
    1509           0 :         if (latin1)
    1510           0 :             masm.store8(Imm32(0), Address(string, 0));
    1511             :         else
    1512           0 :             masm.store16(Imm32(0), Address(string, 0));
    1513             : 
    1514           0 :         masm.pop(base);
    1515           0 :         masm.pop(string);
    1516             :     }
    1517             : 
    1518           0 :     masm.jump(&done);
    1519           0 :     masm.bind(&notInline);
    1520             : 
    1521             :     {
    1522             :         // Make a dependent string.
    1523           0 :         int32_t flags = (latin1 ? JSString::LATIN1_CHARS_BIT : 0) | JSString::DEPENDENT_FLAGS;
    1524             : 
    1525           0 :         masm.newGCString(string, temp2, &fallbacks_[FallbackKind::NotInlineString]);
    1526           0 :         masm.bind(&joins_[FallbackKind::NotInlineString]);
    1527           0 :         masm.store32(Imm32(flags), Address(string, JSString::offsetOfFlags()));
    1528           0 :         masm.store32(temp1, Address(string, JSString::offsetOfLength()));
    1529             : 
    1530           0 :         masm.loadPtr(Address(base, JSString::offsetOfNonInlineChars()), temp1);
    1531           0 :         masm.load32(startIndexAddress, temp2);
    1532           0 :         if (latin1)
    1533           0 :             masm.addPtr(temp2, temp1);
    1534             :         else
    1535           0 :             masm.computeEffectiveAddress(BaseIndex(temp1, temp2, TimesTwo), temp1);
    1536           0 :         masm.storePtr(temp1, Address(string, JSString::offsetOfNonInlineChars()));
    1537           0 :         masm.storePtr(base, Address(string, JSDependentString::offsetOfBase()));
    1538             : 
    1539             :         // Follow any base pointer if the input is itself a dependent string.
    1540             :         // Watch for undepended strings, which have a base pointer but don't
    1541             :         // actually share their characters with it.
    1542           0 :         Label noBase;
    1543           0 :         masm.branchTest32(Assembler::Zero, Address(base, JSString::offsetOfFlags()),
    1544           0 :                           Imm32(JSString::HAS_BASE_BIT), &noBase);
    1545           0 :         masm.branchTest32(Assembler::NonZero, Address(base, JSString::offsetOfFlags()),
    1546           0 :                           Imm32(JSString::FLAT_BIT), &noBase);
    1547           0 :         masm.loadPtr(Address(base, JSDependentString::offsetOfBase()), temp1);
    1548           0 :         masm.storePtr(temp1, Address(string, JSDependentString::offsetOfBase()));
    1549           0 :         masm.bind(&noBase);
    1550             :     }
    1551             : 
    1552           0 :     masm.bind(&done);
    1553           0 : }
    1554             : 
    1555             : static void*
    1556           0 : AllocateString(JSContext* cx)
    1557             : {
    1558           0 :     return js::Allocate<JSString, NoGC>(cx);
    1559             : }
    1560             : 
    1561             : static void*
    1562           0 : AllocateFatInlineString(JSContext* cx)
    1563             : {
    1564           0 :     return js::Allocate<JSFatInlineString, NoGC>(cx);
    1565             : }
    1566             : 
    1567             : void
    1568           0 : CreateDependentString::generateFallback(MacroAssembler& masm, LiveRegisterSet regsToSave)
    1569             : {
    1570           0 :     regsToSave.take(string_);
    1571           0 :     regsToSave.take(temp_);
    1572           0 :     for (FallbackKind kind : mozilla::MakeEnumeratedRange(FallbackKind::Count)) {
    1573           0 :         masm.bind(&fallbacks_[kind]);
    1574             : 
    1575           0 :         masm.PushRegsInMask(regsToSave);
    1576             : 
    1577           0 :         masm.setupUnalignedABICall(string_);
    1578           0 :         masm.loadJSContext(string_);
    1579           0 :         masm.passABIArg(string_);
    1580             :         masm.callWithABI(kind == FallbackKind::FatInlineString
    1581           0 :                          ? JS_FUNC_TO_DATA_PTR(void*, AllocateFatInlineString)
    1582           0 :                          : JS_FUNC_TO_DATA_PTR(void*, AllocateString));
    1583           0 :         masm.storeCallWordResult(string_);
    1584             : 
    1585           0 :         masm.PopRegsInMask(regsToSave);
    1586             : 
    1587           0 :         masm.branchPtr(Assembler::Equal, string_, ImmWord(0), failure_);
    1588             : 
    1589           0 :         masm.jump(&joins_[kind]);
    1590             :     }
    1591           0 : }
    1592             : 
    1593             : static void*
    1594           0 : CreateMatchResultFallbackFunc(JSContext* cx, gc::AllocKind kind, size_t nDynamicSlots)
    1595             : {
    1596             :     return js::Allocate<JSObject, NoGC>(cx, kind, nDynamicSlots, gc::DefaultHeap,
    1597           0 :                                         &ArrayObject::class_);
    1598             : }
    1599             : 
    1600             : static void
    1601           0 : CreateMatchResultFallback(MacroAssembler& masm, LiveRegisterSet regsToSave,
    1602             :                           Register object, Register temp2, Register temp5,
    1603             :                           ArrayObject* templateObj, Label* fail)
    1604             : {
    1605           0 :     MOZ_ASSERT(templateObj->group()->clasp() == &ArrayObject::class_);
    1606             : 
    1607           0 :     regsToSave.take(object);
    1608           0 :     regsToSave.take(temp2);
    1609           0 :     regsToSave.take(temp5);
    1610           0 :     masm.PushRegsInMask(regsToSave);
    1611             : 
    1612           0 :     masm.setupUnalignedABICall(object);
    1613             : 
    1614           0 :     masm.loadJSContext(object);
    1615           0 :     masm.passABIArg(object);
    1616           0 :     masm.move32(Imm32(int32_t(templateObj->asTenured().getAllocKind())), temp2);
    1617           0 :     masm.passABIArg(temp2);
    1618           0 :     masm.move32(Imm32(int32_t(templateObj->as<NativeObject>().numDynamicSlots())), temp5);
    1619           0 :     masm.passABIArg(temp5);
    1620           0 :     masm.callWithABI(JS_FUNC_TO_DATA_PTR(void*, CreateMatchResultFallbackFunc));
    1621           0 :     masm.storeCallWordResult(object);
    1622             : 
    1623           0 :     masm.PopRegsInMask(regsToSave);
    1624             : 
    1625           0 :     masm.branchPtr(Assembler::Equal, object, ImmWord(0), fail);
    1626             : 
    1627           0 :     masm.initGCThing(object, temp2, templateObj, true, false);
    1628           0 : }
    1629             : 
    1630             : JitCode*
    1631           0 : JitCompartment::generateRegExpMatcherStub(JSContext* cx)
    1632             : {
    1633           0 :     Register regexp = RegExpMatcherRegExpReg;
    1634           0 :     Register input = RegExpMatcherStringReg;
    1635           0 :     Register lastIndex = RegExpMatcherLastIndexReg;
    1636           0 :     ValueOperand result = JSReturnOperand;
    1637             : 
    1638             :     // We are free to clobber all registers, as LRegExpMatcher is a call instruction.
    1639           0 :     AllocatableGeneralRegisterSet regs(GeneralRegisterSet::All());
    1640           0 :     regs.take(input);
    1641           0 :     regs.take(regexp);
    1642           0 :     regs.take(lastIndex);
    1643             : 
    1644             :     // temp5 is used in single byte instructions when creating dependent
    1645             :     // strings, and has restrictions on which register it can be on some
    1646             :     // platforms.
    1647           0 :     Register temp5;
    1648             :     {
    1649           0 :         AllocatableGeneralRegisterSet oregs = regs;
    1650           0 :         do {
    1651           0 :             temp5 = oregs.takeAny();
    1652           0 :         } while (!MacroAssembler::canUseInSingleByteInstruction(temp5));
    1653           0 :         regs.take(temp5);
    1654             :     }
    1655             : 
    1656           0 :     Register temp1 = regs.takeAny();
    1657           0 :     Register temp2 = regs.takeAny();
    1658           0 :     Register temp3 = regs.takeAny();
    1659             : 
    1660           0 :     Register maybeTemp4 = InvalidReg;
    1661           0 :     if (!regs.empty()) {
    1662             :         // There are not enough registers on x86.
    1663           0 :         maybeTemp4 = regs.takeAny();
    1664             :     }
    1665             : 
    1666           0 :     ArrayObject* templateObject = cx->compartment()->regExps.getOrCreateMatchResultTemplateObject(cx);
    1667           0 :     if (!templateObject)
    1668           0 :         return nullptr;
    1669             : 
    1670             :     // The template object should have enough space for the maximum number of
    1671             :     // pairs this stub can handle.
    1672           0 :     MOZ_ASSERT(ObjectElements::VALUES_PER_HEADER + RegExpObject::MaxPairCount ==
    1673             :                gc::GetGCKindSlots(templateObject->asTenured().getAllocKind()));
    1674             : 
    1675           0 :     MacroAssembler masm(cx);
    1676             : 
    1677             :     // The InputOutputData is placed above the return address on the stack.
    1678           0 :     size_t inputOutputDataStartOffset = sizeof(void*);
    1679             : 
    1680           0 :     Label notFound, oolEntry;
    1681           0 :     if (!PrepareAndExecuteRegExp(cx, masm, regexp, input, lastIndex,
    1682             :                                  temp1, temp2, temp5, inputOutputDataStartOffset,
    1683             :                                  RegExpShared::Normal, &notFound, &oolEntry))
    1684             :     {
    1685           0 :         return nullptr;
    1686             :     }
    1687             : 
    1688             :     // Construct the result.
    1689           0 :     Register object = temp1;
    1690           0 :     Label matchResultFallback, matchResultJoin;
    1691           0 :     masm.createGCObject(object, temp2, templateObject, gc::DefaultHeap, &matchResultFallback);
    1692           0 :     masm.bind(&matchResultJoin);
    1693             : 
    1694             :     // Initialize slots of result object.
    1695           0 :     masm.loadPtr(Address(object, NativeObject::offsetOfSlots()), temp2);
    1696           0 :     masm.storeValue(templateObject->getSlot(0), Address(temp2, 0));
    1697           0 :     masm.storeValue(templateObject->getSlot(1), Address(temp2, sizeof(Value)));
    1698             : 
    1699           0 :     size_t elementsOffset = NativeObject::offsetOfFixedElements();
    1700             : 
    1701             : #ifdef DEBUG
    1702             :     // Assert the initial value of initializedLength and length to make sure
    1703             :     // restoration on failure case works.
    1704             :     {
    1705           0 :         Label initLengthOK, lengthOK;
    1706           0 :         masm.branch32(Assembler::Equal,
    1707           0 :                       Address(object, elementsOffset + ObjectElements::offsetOfInitializedLength()),
    1708           0 :                       Imm32(templateObject->getDenseInitializedLength()),
    1709           0 :                       &initLengthOK);
    1710           0 :         masm.assumeUnreachable("Initial value of the match object's initializedLength does not match to restoration.");
    1711           0 :         masm.bind(&initLengthOK);
    1712             : 
    1713           0 :         masm.branch32(Assembler::Equal,
    1714           0 :                       Address(object, elementsOffset + ObjectElements::offsetOfLength()),
    1715           0 :                       Imm32(templateObject->length()),
    1716           0 :                       &lengthOK);
    1717           0 :         masm.assumeUnreachable("Initial value of The match object's length does not match to restoration.");
    1718           0 :         masm.bind(&lengthOK);
    1719             :     }
    1720             : #endif
    1721             : 
    1722           0 :     Register matchIndex = temp2;
    1723           0 :     masm.move32(Imm32(0), matchIndex);
    1724             : 
    1725           0 :     size_t pairsVectorStartOffset = RegExpPairsVectorStartOffset(inputOutputDataStartOffset);
    1726           0 :     Address pairsVectorAddress(masm.getStackPointer(), pairsVectorStartOffset);
    1727           0 :     Address pairCountAddress = RegExpPairCountAddress(masm, inputOutputDataStartOffset);
    1728             : 
    1729           0 :     BaseIndex stringAddress(object, matchIndex, TimesEight, elementsOffset);
    1730             : 
    1731             :     JS_STATIC_ASSERT(sizeof(MatchPair) == 8);
    1732             :     BaseIndex stringIndexAddress(masm.getStackPointer(), matchIndex, TimesEight,
    1733           0 :                                  pairsVectorStartOffset + offsetof(MatchPair, start));
    1734             :     BaseIndex stringLimitAddress(masm.getStackPointer(), matchIndex, TimesEight,
    1735           0 :                                  pairsVectorStartOffset + offsetof(MatchPair, limit));
    1736             : 
    1737             :     // Loop to construct the match strings. There are two different loops,
    1738             :     // depending on whether the input is latin1.
    1739           0 :     CreateDependentString depStr[2];
    1740             :     {
    1741           0 :         Label isLatin1, done;
    1742           0 :         masm.branchLatin1String(input, &isLatin1);
    1743             : 
    1744           0 :         Label* failure = &oolEntry;
    1745           0 :         Register temp4 = (maybeTemp4 == InvalidReg) ? lastIndex : maybeTemp4;
    1746             : 
    1747           0 :         Label failureRestore;
    1748           0 :         if (maybeTemp4 == InvalidReg) {
    1749           0 :             failure = &failureRestore;
    1750             : 
    1751             :             // Save lastIndex value to temporary space.
    1752           0 :             masm.store32(lastIndex, Address(object, elementsOffset + ObjectElements::offsetOfLength()));
    1753             :         }
    1754             : 
    1755           0 :         for (int isLatin = 0; isLatin <= 1; isLatin++) {
    1756           0 :             if (isLatin)
    1757           0 :                 masm.bind(&isLatin1);
    1758             : 
    1759           0 :             Label matchLoop;
    1760           0 :             masm.bind(&matchLoop);
    1761             : 
    1762           0 :             Label isUndefined, storeDone;
    1763           0 :             masm.branch32(Assembler::LessThan, stringIndexAddress, Imm32(0), &isUndefined);
    1764             : 
    1765           0 :             depStr[isLatin].generate(masm, cx->names(), isLatin, temp3, input, temp4, temp5,
    1766           0 :                                      stringIndexAddress, stringLimitAddress, failure);
    1767             : 
    1768           0 :             masm.storeValue(JSVAL_TYPE_STRING, temp3, stringAddress);
    1769             : 
    1770           0 :             masm.jump(&storeDone);
    1771           0 :             masm.bind(&isUndefined);
    1772             : 
    1773           0 :             masm.storeValue(UndefinedValue(), stringAddress);
    1774           0 :             masm.bind(&storeDone);
    1775             : 
    1776           0 :             masm.add32(Imm32(1), matchIndex);
    1777           0 :             masm.branch32(Assembler::LessThanOrEqual, pairCountAddress, matchIndex, &done);
    1778           0 :             masm.jump(&matchLoop);
    1779             :         }
    1780             : 
    1781           0 :         if (maybeTemp4 == InvalidReg) {
    1782             :             // Restore lastIndex value from temporary space, both for success
    1783             :             // and failure cases.
    1784             : 
    1785           0 :             masm.load32(Address(object, elementsOffset + ObjectElements::offsetOfLength()), lastIndex);
    1786           0 :             masm.jump(&done);
    1787             : 
    1788           0 :             masm.bind(&failureRestore);
    1789           0 :             masm.load32(Address(object, elementsOffset + ObjectElements::offsetOfLength()), lastIndex);
    1790             : 
    1791             :             // Restore the match object for failure case.
    1792           0 :             masm.store32(Imm32(templateObject->getDenseInitializedLength()),
    1793           0 :                          Address(object, elementsOffset + ObjectElements::offsetOfInitializedLength()));
    1794           0 :             masm.store32(Imm32(templateObject->length()),
    1795           0 :                          Address(object, elementsOffset + ObjectElements::offsetOfLength()));
    1796           0 :             masm.jump(&oolEntry);
    1797             :         }
    1798             : 
    1799           0 :         masm.bind(&done);
    1800             :     }
    1801             : 
    1802             :     // Fill in the rest of the output object.
    1803           0 :     masm.store32(matchIndex, Address(object, elementsOffset + ObjectElements::offsetOfInitializedLength()));
    1804           0 :     masm.store32(matchIndex, Address(object, elementsOffset + ObjectElements::offsetOfLength()));
    1805             : 
    1806           0 :     masm.loadPtr(Address(object, NativeObject::offsetOfSlots()), temp2);
    1807             : 
    1808           0 :     MOZ_ASSERT(templateObject->numFixedSlots() == 0);
    1809           0 :     MOZ_ASSERT(templateObject->lookupPure(cx->names().index)->slot() == 0);
    1810           0 :     MOZ_ASSERT(templateObject->lookupPure(cx->names().input)->slot() == 1);
    1811             : 
    1812           0 :     masm.load32(pairsVectorAddress, temp3);
    1813           0 :     masm.storeValue(JSVAL_TYPE_INT32, temp3, Address(temp2, 0));
    1814           0 :     masm.storeValue(JSVAL_TYPE_STRING, input, Address(temp2, sizeof(Value)));
    1815             : 
    1816             :     // All done!
    1817           0 :     masm.tagValue(JSVAL_TYPE_OBJECT, object, result);
    1818           0 :     masm.ret();
    1819             : 
    1820           0 :     masm.bind(&notFound);
    1821           0 :     masm.moveValue(NullValue(), result);
    1822           0 :     masm.ret();
    1823             : 
    1824             :     // Fallback paths for CreateDependentString and createGCObject.
    1825             :     // Need to save all registers in use when they were called.
    1826           0 :     LiveRegisterSet regsToSave(RegisterSet::Volatile());
    1827           0 :     regsToSave.addUnchecked(regexp);
    1828           0 :     regsToSave.addUnchecked(input);
    1829           0 :     regsToSave.addUnchecked(lastIndex);
    1830           0 :     regsToSave.addUnchecked(temp1);
    1831           0 :     regsToSave.addUnchecked(temp2);
    1832           0 :     regsToSave.addUnchecked(temp3);
    1833           0 :     if (maybeTemp4 != InvalidReg)
    1834           0 :         regsToSave.addUnchecked(maybeTemp4);
    1835           0 :     regsToSave.addUnchecked(temp5);
    1836             : 
    1837           0 :     for (int isLatin = 0; isLatin <= 1; isLatin++)
    1838           0 :         depStr[isLatin].generateFallback(masm, regsToSave);
    1839             : 
    1840           0 :     masm.bind(&matchResultFallback);
    1841           0 :     CreateMatchResultFallback(masm, regsToSave, object, temp2, temp5, templateObject, &oolEntry);
    1842           0 :     masm.jump(&matchResultJoin);
    1843             : 
    1844             :     // Use an undefined value to signal to the caller that the OOL stub needs to be called.
    1845           0 :     masm.bind(&oolEntry);
    1846           0 :     masm.moveValue(UndefinedValue(), result);
    1847           0 :     masm.ret();
    1848             : 
    1849           0 :     Linker linker(masm);
    1850           0 :     AutoFlushICache afc("RegExpMatcherStub");
    1851           0 :     JitCode* code = linker.newCode<CanGC>(cx, OTHER_CODE);
    1852           0 :     if (!code)
    1853           0 :         return nullptr;
    1854             : 
    1855             : #ifdef JS_ION_PERF
    1856             :     writePerfSpewerJitCodeProfile(code, "RegExpMatcherStub");
    1857             : #endif
    1858             : #ifdef MOZ_VTUNE
    1859           0 :     vtune::MarkStub(code, "RegExpMatcherStub");
    1860             : #endif
    1861             : 
    1862           0 :     return code;
    1863             : }
    1864             : 
    1865             : class OutOfLineRegExpMatcher : public OutOfLineCodeBase<CodeGenerator>
    1866             : {
    1867             :     LRegExpMatcher* lir_;
    1868             : 
    1869             :   public:
    1870           0 :     explicit OutOfLineRegExpMatcher(LRegExpMatcher* lir)
    1871           0 :       : lir_(lir)
    1872           0 :     { }
    1873             : 
    1874           0 :     void accept(CodeGenerator* codegen) {
    1875           0 :         codegen->visitOutOfLineRegExpMatcher(this);
    1876           0 :     }
    1877             : 
    1878           0 :     LRegExpMatcher* lir() const {
    1879           0 :         return lir_;
    1880             :     }
    1881             : };
    1882             : 
    1883             : typedef bool (*RegExpMatcherRawFn)(JSContext* cx, HandleObject regexp, HandleString input,
    1884             :                                    int32_t lastIndex,
    1885             :                                    MatchPairs* pairs, MutableHandleValue output);
    1886           3 : static const VMFunction RegExpMatcherRawInfo =
    1887           6 :     FunctionInfo<RegExpMatcherRawFn>(RegExpMatcherRaw, "RegExpMatcherRaw");
    1888             : 
    1889             : void
    1890           0 : CodeGenerator::visitOutOfLineRegExpMatcher(OutOfLineRegExpMatcher* ool)
    1891             : {
    1892           0 :     LRegExpMatcher* lir = ool->lir();
    1893           0 :     Register lastIndex = ToRegister(lir->lastIndex());
    1894           0 :     Register input = ToRegister(lir->string());
    1895           0 :     Register regexp = ToRegister(lir->regexp());
    1896             : 
    1897           0 :     AllocatableGeneralRegisterSet regs(GeneralRegisterSet::All());
    1898           0 :     regs.take(lastIndex);
    1899           0 :     regs.take(input);
    1900           0 :     regs.take(regexp);
    1901           0 :     Register temp = regs.takeAny();
    1902             : 
    1903           0 :     masm.computeEffectiveAddress(Address(masm.getStackPointer(),
    1904           0 :         sizeof(irregexp::InputOutputData)), temp);
    1905             : 
    1906           0 :     pushArg(temp);
    1907           0 :     pushArg(lastIndex);
    1908           0 :     pushArg(input);
    1909           0 :     pushArg(regexp);
    1910             : 
    1911             :     // We are not using oolCallVM because we are in a Call, and that live
    1912             :     // registers are already saved by the the register allocator.
    1913           0 :     callVM(RegExpMatcherRawInfo, lir);
    1914             : 
    1915           0 :     masm.jump(ool->rejoin());
    1916           0 : }
    1917             : 
    1918             : void
    1919           0 : CodeGenerator::visitRegExpMatcher(LRegExpMatcher* lir)
    1920             : {
    1921           0 :     MOZ_ASSERT(ToRegister(lir->regexp()) == RegExpMatcherRegExpReg);
    1922           0 :     MOZ_ASSERT(ToRegister(lir->string()) == RegExpMatcherStringReg);
    1923           0 :     MOZ_ASSERT(ToRegister(lir->lastIndex()) == RegExpMatcherLastIndexReg);
    1924           0 :     MOZ_ASSERT(GetValueOutput(lir) == JSReturnOperand);
    1925             : 
    1926             : #if defined(JS_NUNBOX32)
    1927             :     MOZ_ASSERT(RegExpMatcherRegExpReg != JSReturnReg_Type);
    1928             :     MOZ_ASSERT(RegExpMatcherRegExpReg != JSReturnReg_Data);
    1929             :     MOZ_ASSERT(RegExpMatcherStringReg != JSReturnReg_Type);
    1930             :     MOZ_ASSERT(RegExpMatcherStringReg != JSReturnReg_Data);
    1931             :     MOZ_ASSERT(RegExpMatcherLastIndexReg != JSReturnReg_Type);
    1932             :     MOZ_ASSERT(RegExpMatcherLastIndexReg != JSReturnReg_Data);
    1933             : #elif defined(JS_PUNBOX64)
    1934           0 :     MOZ_ASSERT(RegExpMatcherRegExpReg != JSReturnReg);
    1935           0 :     MOZ_ASSERT(RegExpMatcherStringReg != JSReturnReg);
    1936           0 :     MOZ_ASSERT(RegExpMatcherLastIndexReg != JSReturnReg);
    1937             : #endif
    1938             : 
    1939           0 :     masm.reserveStack(RegExpReservedStack);
    1940             : 
    1941           0 :     OutOfLineRegExpMatcher* ool = new(alloc()) OutOfLineRegExpMatcher(lir);
    1942           0 :     addOutOfLineCode(ool, lir->mir());
    1943             : 
    1944           0 :     JitCode* regExpMatcherStub = gen->compartment->jitCompartment()->regExpMatcherStubNoBarrier();
    1945           0 :     masm.call(regExpMatcherStub);
    1946           0 :     masm.branchTestUndefined(Assembler::Equal, JSReturnOperand, ool->entry());
    1947           0 :     masm.bind(ool->rejoin());
    1948             : 
    1949           0 :     masm.freeStack(RegExpReservedStack);
    1950           0 : }
    1951             : 
    1952             : static const int32_t RegExpSearcherResultNotFound = -1;
    1953             : static const int32_t RegExpSearcherResultFailed = -2;
    1954             : 
    1955             : JitCode*
    1956           0 : JitCompartment::generateRegExpSearcherStub(JSContext* cx)
    1957             : {
    1958           0 :     Register regexp = RegExpTesterRegExpReg;
    1959           0 :     Register input = RegExpTesterStringReg;
    1960           0 :     Register lastIndex = RegExpTesterLastIndexReg;
    1961           0 :     Register result = ReturnReg;
    1962             : 
    1963             :     // We are free to clobber all registers, as LRegExpSearcher is a call instruction.
    1964           0 :     AllocatableGeneralRegisterSet regs(GeneralRegisterSet::All());
    1965           0 :     regs.take(input);
    1966           0 :     regs.take(regexp);
    1967           0 :     regs.take(lastIndex);
    1968             : 
    1969           0 :     Register temp1 = regs.takeAny();
    1970           0 :     Register temp2 = regs.takeAny();
    1971           0 :     Register temp3 = regs.takeAny();
    1972             : 
    1973           0 :     MacroAssembler masm(cx);
    1974             : 
    1975             :     // The InputOutputData is placed above the return address on the stack.
    1976           0 :     size_t inputOutputDataStartOffset = sizeof(void*);
    1977             : 
    1978           0 :     Label notFound, oolEntry;
    1979           0 :     if (!PrepareAndExecuteRegExp(cx, masm, regexp, input, lastIndex,
    1980             :                                  temp1, temp2, temp3, inputOutputDataStartOffset,
    1981             :                                  RegExpShared::Normal, &notFound, &oolEntry))
    1982             :     {
    1983           0 :         return nullptr;
    1984             :     }
    1985             : 
    1986           0 :     size_t pairsVectorStartOffset = RegExpPairsVectorStartOffset(inputOutputDataStartOffset);
    1987             :     Address stringIndexAddress(masm.getStackPointer(),
    1988           0 :                                pairsVectorStartOffset + offsetof(MatchPair, start));
    1989             :     Address stringLimitAddress(masm.getStackPointer(),
    1990           0 :                                pairsVectorStartOffset + offsetof(MatchPair, limit));
    1991             : 
    1992           0 :     masm.load32(stringIndexAddress, result);
    1993           0 :     masm.load32(stringLimitAddress, input);
    1994           0 :     masm.lshiftPtr(Imm32(15), input);
    1995           0 :     masm.or32(input, result);
    1996           0 :     masm.ret();
    1997             : 
    1998           0 :     masm.bind(&notFound);
    1999           0 :     masm.move32(Imm32(RegExpSearcherResultNotFound), result);
    2000           0 :     masm.ret();
    2001             : 
    2002           0 :     masm.bind(&oolEntry);
    2003           0 :     masm.move32(Imm32(RegExpSearcherResultFailed), result);
    2004           0 :     masm.ret();
    2005             : 
    2006           0 :     Linker linker(masm);
    2007           0 :     AutoFlushICache afc("RegExpSearcherStub");
    2008           0 :     JitCode* code = linker.newCode<CanGC>(cx, OTHER_CODE);
    2009           0 :     if (!code)
    2010           0 :         return nullptr;
    2011             : 
    2012             : #ifdef JS_ION_PERF
    2013             :     writePerfSpewerJitCodeProfile(code, "RegExpSearcherStub");
    2014             : #endif
    2015             : #ifdef MOZ_VTUNE
    2016           0 :     vtune::MarkStub(code, "RegExpSearcherStub");
    2017             : #endif
    2018             : 
    2019           0 :     return code;
    2020             : }
    2021             : 
    2022             : class OutOfLineRegExpSearcher : public OutOfLineCodeBase<CodeGenerator>
    2023             : {
    2024             :     LRegExpSearcher* lir_;
    2025             : 
    2026             :   public:
    2027           0 :     explicit OutOfLineRegExpSearcher(LRegExpSearcher* lir)
    2028           0 :       : lir_(lir)
    2029           0 :     { }
    2030             : 
    2031           0 :     void accept(CodeGenerator* codegen) {
    2032           0 :         codegen->visitOutOfLineRegExpSearcher(this);
    2033           0 :     }
    2034             : 
    2035           0 :     LRegExpSearcher* lir() const {
    2036           0 :         return lir_;
    2037             :     }
    2038             : };
    2039             : 
    2040             : typedef bool (*RegExpSearcherRawFn)(JSContext* cx, HandleObject regexp, HandleString input,
    2041             :                                     int32_t lastIndex,
    2042             :                                     MatchPairs* pairs, int32_t* result);
    2043           3 : static const VMFunction RegExpSearcherRawInfo =
    2044           6 :     FunctionInfo<RegExpSearcherRawFn>(RegExpSearcherRaw, "RegExpSearcherRaw");
    2045             : 
    2046             : void
    2047           0 : CodeGenerator::visitOutOfLineRegExpSearcher(OutOfLineRegExpSearcher* ool)
    2048             : {
    2049           0 :     LRegExpSearcher* lir = ool->lir();
    2050           0 :     Register lastIndex = ToRegister(lir->lastIndex());
    2051           0 :     Register input = ToRegister(lir->string());
    2052           0 :     Register regexp = ToRegister(lir->regexp());
    2053             : 
    2054           0 :     AllocatableGeneralRegisterSet regs(GeneralRegisterSet::All());
    2055           0 :     regs.take(lastIndex);
    2056           0 :     regs.take(input);
    2057           0 :     regs.take(regexp);
    2058           0 :     Register temp = regs.takeAny();
    2059             : 
    2060           0 :     masm.computeEffectiveAddress(Address(masm.getStackPointer(),
    2061           0 :         sizeof(irregexp::InputOutputData)), temp);
    2062             : 
    2063           0 :     pushArg(temp);
    2064           0 :     pushArg(lastIndex);
    2065           0 :     pushArg(input);
    2066           0 :     pushArg(regexp);
    2067             : 
    2068             :     // We are not using oolCallVM because we are in a Call, and that live
    2069             :     // registers are already saved by the the register allocator.
    2070           0 :     callVM(RegExpSearcherRawInfo, lir);
    2071             : 
    2072           0 :     masm.jump(ool->rejoin());
    2073           0 : }
    2074             : 
    2075             : void
    2076           0 : CodeGenerator::visitRegExpSearcher(LRegExpSearcher* lir)
    2077             : {
    2078           0 :     MOZ_ASSERT(ToRegister(lir->regexp()) == RegExpTesterRegExpReg);
    2079           0 :     MOZ_ASSERT(ToRegister(lir->string()) == RegExpTesterStringReg);
    2080           0 :     MOZ_ASSERT(ToRegister(lir->lastIndex()) == RegExpTesterLastIndexReg);
    2081           0 :     MOZ_ASSERT(ToRegister(lir->output()) == ReturnReg);
    2082             : 
    2083           0 :     MOZ_ASSERT(RegExpTesterRegExpReg != ReturnReg);
    2084           0 :     MOZ_ASSERT(RegExpTesterStringReg != ReturnReg);
    2085           0 :     MOZ_ASSERT(RegExpTesterLastIndexReg != ReturnReg);
    2086             : 
    2087           0 :     masm.reserveStack(RegExpReservedStack);
    2088             : 
    2089           0 :     OutOfLineRegExpSearcher* ool = new(alloc()) OutOfLineRegExpSearcher(lir);
    2090           0 :     addOutOfLineCode(ool, lir->mir());
    2091             : 
    2092           0 :     JitCode* regExpSearcherStub = gen->compartment->jitCompartment()->regExpSearcherStubNoBarrier();
    2093           0 :     masm.call(regExpSearcherStub);
    2094           0 :     masm.branch32(Assembler::Equal, ReturnReg, Imm32(RegExpSearcherResultFailed), ool->entry());
    2095           0 :     masm.bind(ool->rejoin());
    2096             : 
    2097           0 :     masm.freeStack(RegExpReservedStack);
    2098           0 : }
    2099             : 
    2100             : static const int32_t RegExpTesterResultNotFound = -1;
    2101             : static const int32_t RegExpTesterResultFailed = -2;
    2102             : 
    2103             : JitCode*
    2104           0 : JitCompartment::generateRegExpTesterStub(JSContext* cx)
    2105             : {
    2106           0 :     Register regexp = RegExpTesterRegExpReg;
    2107           0 :     Register input = RegExpTesterStringReg;
    2108           0 :     Register lastIndex = RegExpTesterLastIndexReg;
    2109           0 :     Register result = ReturnReg;
    2110             : 
    2111           0 :     MacroAssembler masm(cx);
    2112             : 
    2113             : #ifdef JS_USE_LINK_REGISTER
    2114             :     masm.pushReturnAddress();
    2115             : #endif
    2116             : 
    2117             :     // We are free to clobber all registers, as LRegExpTester is a call instruction.
    2118           0 :     AllocatableGeneralRegisterSet regs(GeneralRegisterSet::All());
    2119           0 :     regs.take(input);
    2120           0 :     regs.take(regexp);
    2121           0 :     regs.take(lastIndex);
    2122             : 
    2123           0 :     Register temp1 = regs.takeAny();
    2124           0 :     Register temp2 = regs.takeAny();
    2125           0 :     Register temp3 = regs.takeAny();
    2126             : 
    2127           0 :     masm.reserveStack(sizeof(irregexp::InputOutputData));
    2128             : 
    2129           0 :     Label notFound, oolEntry;
    2130           0 :     if (!PrepareAndExecuteRegExp(cx, masm, regexp, input, lastIndex,
    2131             :                                  temp1, temp2, temp3, 0,
    2132             :                                  RegExpShared::MatchOnly, &notFound, &oolEntry))
    2133             :     {
    2134           0 :         return nullptr;
    2135             :     }
    2136             : 
    2137           0 :     Label done;
    2138             : 
    2139             :     // temp3 contains endIndex.
    2140           0 :     masm.move32(temp3, result);
    2141           0 :     masm.jump(&done);
    2142             : 
    2143           0 :     masm.bind(&notFound);
    2144           0 :     masm.move32(Imm32(RegExpTesterResultNotFound), result);
    2145           0 :     masm.jump(&done);
    2146             : 
    2147           0 :     masm.bind(&oolEntry);
    2148           0 :     masm.move32(Imm32(RegExpTesterResultFailed), result);
    2149             : 
    2150           0 :     masm.bind(&done);
    2151           0 :     masm.freeStack(sizeof(irregexp::InputOutputData));
    2152           0 :     masm.ret();
    2153             : 
    2154           0 :     Linker linker(masm);
    2155           0 :     AutoFlushICache afc("RegExpTesterStub");
    2156           0 :     JitCode* code = linker.newCode<CanGC>(cx, OTHER_CODE);
    2157           0 :     if (!code)
    2158           0 :         return nullptr;
    2159             : 
    2160             : #ifdef JS_ION_PERF
    2161             :     writePerfSpewerJitCodeProfile(code, "RegExpTesterStub");
    2162             : #endif
    2163             : #ifdef MOZ_VTUNE
    2164           0 :     vtune::MarkStub(code, "RegExpTesterStub");
    2165             : #endif
    2166             : 
    2167           0 :     return code;
    2168             : }
    2169             : 
    2170             : class OutOfLineRegExpTester : public OutOfLineCodeBase<CodeGenerator>
    2171             : {
    2172             :     LRegExpTester* lir_;
    2173             : 
    2174             :   public:
    2175           0 :     explicit OutOfLineRegExpTester(LRegExpTester* lir)
    2176           0 :       : lir_(lir)
    2177           0 :     { }
    2178             : 
    2179           0 :     void accept(CodeGenerator* codegen) {
    2180           0 :         codegen->visitOutOfLineRegExpTester(this);
    2181           0 :     }
    2182             : 
    2183           0 :     LRegExpTester* lir() const {
    2184           0 :         return lir_;
    2185             :     }
    2186             : };
    2187             : 
    2188             : typedef bool (*RegExpTesterRawFn)(JSContext* cx, HandleObject regexp, HandleString input,
    2189             :                                   int32_t lastIndex, int32_t* result);
    2190           3 : static const VMFunction RegExpTesterRawInfo =
    2191           6 :     FunctionInfo<RegExpTesterRawFn>(RegExpTesterRaw, "RegExpTesterRaw");
    2192             : 
    2193             : void
    2194           0 : CodeGenerator::visitOutOfLineRegExpTester(OutOfLineRegExpTester* ool)
    2195             : {
    2196           0 :     LRegExpTester* lir = ool->lir();
    2197           0 :     Register lastIndex = ToRegister(lir->lastIndex());
    2198           0 :     Register input = ToRegister(lir->string());
    2199           0 :     Register regexp = ToRegister(lir->regexp());
    2200             : 
    2201           0 :     pushArg(lastIndex);
    2202           0 :     pushArg(input);
    2203           0 :     pushArg(regexp);
    2204             : 
    2205             :     // We are not using oolCallVM because we are in a Call, and that live
    2206             :     // registers are already saved by the the register allocator.
    2207           0 :     callVM(RegExpTesterRawInfo, lir);
    2208             : 
    2209           0 :     masm.jump(ool->rejoin());
    2210           0 : }
    2211             : 
    2212             : void
    2213           0 : CodeGenerator::visitRegExpTester(LRegExpTester* lir)
    2214             : {
    2215           0 :     MOZ_ASSERT(ToRegister(lir->regexp()) == RegExpTesterRegExpReg);
    2216           0 :     MOZ_ASSERT(ToRegister(lir->string()) == RegExpTesterStringReg);
    2217           0 :     MOZ_ASSERT(ToRegister(lir->lastIndex()) == RegExpTesterLastIndexReg);
    2218           0 :     MOZ_ASSERT(ToRegister(lir->output()) == ReturnReg);
    2219             : 
    2220           0 :     MOZ_ASSERT(RegExpTesterRegExpReg != ReturnReg);
    2221           0 :     MOZ_ASSERT(RegExpTesterStringReg != ReturnReg);
    2222           0 :     MOZ_ASSERT(RegExpTesterLastIndexReg != ReturnReg);
    2223             : 
    2224           0 :     OutOfLineRegExpTester* ool = new(alloc()) OutOfLineRegExpTester(lir);
    2225           0 :     addOutOfLineCode(ool, lir->mir());
    2226             : 
    2227           0 :     JitCode* regExpTesterStub = gen->compartment->jitCompartment()->regExpTesterStubNoBarrier();
    2228           0 :     masm.call(regExpTesterStub);
    2229             : 
    2230           0 :     masm.branch32(Assembler::Equal, ReturnReg, Imm32(RegExpTesterResultFailed), ool->entry());
    2231           0 :     masm.bind(ool->rejoin());
    2232           0 : }
    2233             : 
    2234             : class OutOfLineRegExpPrototypeOptimizable : public OutOfLineCodeBase<CodeGenerator>
    2235             : {
    2236             :     LRegExpPrototypeOptimizable* ins_;
    2237             : 
    2238             :   public:
    2239           0 :     explicit OutOfLineRegExpPrototypeOptimizable(LRegExpPrototypeOptimizable* ins)
    2240           0 :       : ins_(ins)
    2241           0 :     { }
    2242             : 
    2243           0 :     void accept(CodeGenerator* codegen) {
    2244           0 :         codegen->visitOutOfLineRegExpPrototypeOptimizable(this);
    2245           0 :     }
    2246           0 :     LRegExpPrototypeOptimizable* ins() const {
    2247           0 :         return ins_;
    2248             :     }
    2249             : };
    2250             : 
    2251             : void
    2252           0 : CodeGenerator::visitRegExpPrototypeOptimizable(LRegExpPrototypeOptimizable* ins)
    2253             : {
    2254           0 :     Register object = ToRegister(ins->object());
    2255           0 :     Register output = ToRegister(ins->output());
    2256           0 :     Register temp = ToRegister(ins->temp());
    2257             : 
    2258           0 :     OutOfLineRegExpPrototypeOptimizable* ool = new(alloc()) OutOfLineRegExpPrototypeOptimizable(ins);
    2259           0 :     addOutOfLineCode(ool, ins->mir());
    2260             : 
    2261           0 :     masm.loadJSContext(temp);
    2262           0 :     masm.loadPtr(Address(temp, JSContext::offsetOfCompartment()), temp);
    2263           0 :     size_t offset = JSCompartment::offsetOfRegExps() +
    2264           0 :                     RegExpCompartment::offsetOfOptimizableRegExpPrototypeShape();
    2265           0 :     masm.loadPtr(Address(temp, offset), temp);
    2266             : 
    2267           0 :     masm.loadPtr(Address(object, ShapedObject::offsetOfShape()), output);
    2268           0 :     masm.branchPtr(Assembler::NotEqual, output, temp, ool->entry());
    2269           0 :     masm.move32(Imm32(0x1), output);
    2270             : 
    2271           0 :     masm.bind(ool->rejoin());
    2272           0 : }
    2273             : 
    2274             : void
    2275           0 : CodeGenerator::visitOutOfLineRegExpPrototypeOptimizable(OutOfLineRegExpPrototypeOptimizable* ool)
    2276             : {
    2277           0 :     LRegExpPrototypeOptimizable* ins = ool->ins();
    2278           0 :     Register object = ToRegister(ins->object());
    2279           0 :     Register output = ToRegister(ins->output());
    2280             : 
    2281           0 :     saveVolatile(output);
    2282             : 
    2283           0 :     masm.setupUnalignedABICall(output);
    2284           0 :     masm.loadJSContext(output);
    2285           0 :     masm.passABIArg(output);
    2286           0 :     masm.passABIArg(object);
    2287           0 :     masm.callWithABI(JS_FUNC_TO_DATA_PTR(void*, RegExpPrototypeOptimizableRaw));
    2288           0 :     masm.storeCallBoolResult(output);
    2289             : 
    2290           0 :     restoreVolatile(output);
    2291             : 
    2292           0 :     masm.jump(ool->rejoin());
    2293           0 : }
    2294             : 
    2295             : class OutOfLineRegExpInstanceOptimizable : public OutOfLineCodeBase<CodeGenerator>
    2296             : {
    2297             :     LRegExpInstanceOptimizable* ins_;
    2298             : 
    2299             :   public:
    2300           0 :     explicit OutOfLineRegExpInstanceOptimizable(LRegExpInstanceOptimizable* ins)
    2301           0 :       : ins_(ins)
    2302           0 :     { }
    2303             : 
    2304           0 :     void accept(CodeGenerator* codegen) {
    2305           0 :         codegen->visitOutOfLineRegExpInstanceOptimizable(this);
    2306           0 :     }
    2307           0 :     LRegExpInstanceOptimizable* ins() const {
    2308           0 :         return ins_;
    2309             :     }
    2310             : };
    2311             : 
    2312             : void
    2313           0 : CodeGenerator::visitRegExpInstanceOptimizable(LRegExpInstanceOptimizable* ins)
    2314             : {
    2315           0 :     Register object = ToRegister(ins->object());
    2316           0 :     Register output = ToRegister(ins->output());
    2317           0 :     Register temp = ToRegister(ins->temp());
    2318             : 
    2319           0 :     OutOfLineRegExpInstanceOptimizable* ool = new(alloc()) OutOfLineRegExpInstanceOptimizable(ins);
    2320           0 :     addOutOfLineCode(ool, ins->mir());
    2321             : 
    2322           0 :     masm.loadJSContext(temp);
    2323           0 :     masm.loadPtr(Address(temp, JSContext::offsetOfCompartment()), temp);
    2324           0 :     size_t offset = JSCompartment::offsetOfRegExps() +
    2325           0 :                     RegExpCompartment::offsetOfOptimizableRegExpInstanceShape();
    2326           0 :     masm.loadPtr(Address(temp, offset), temp);
    2327             : 
    2328           0 :     masm.loadPtr(Address(object, ShapedObject::offsetOfShape()), output);
    2329           0 :     masm.branchPtr(Assembler::NotEqual, output, temp, ool->entry());
    2330           0 :     masm.move32(Imm32(0x1), output);
    2331             : 
    2332           0 :     masm.bind(ool->rejoin());
    2333           0 : }
    2334             : 
    2335             : void
    2336           0 : CodeGenerator::visitOutOfLineRegExpInstanceOptimizable(OutOfLineRegExpInstanceOptimizable* ool)
    2337             : {
    2338           0 :     LRegExpInstanceOptimizable* ins = ool->ins();
    2339           0 :     Register object = ToRegister(ins->object());
    2340           0 :     Register proto = ToRegister(ins->proto());
    2341           0 :     Register output = ToRegister(ins->output());
    2342             : 
    2343           0 :     saveVolatile(output);
    2344             : 
    2345           0 :     masm.setupUnalignedABICall(output);
    2346           0 :     masm.loadJSContext(output);
    2347           0 :     masm.passABIArg(output);
    2348           0 :     masm.passABIArg(object);
    2349           0 :     masm.passABIArg(proto);
    2350           0 :     masm.callWithABI(JS_FUNC_TO_DATA_PTR(void*, RegExpInstanceOptimizableRaw));
    2351           0 :     masm.storeCallBoolResult(output);
    2352             : 
    2353           0 :     restoreVolatile(output);
    2354             : 
    2355           0 :     masm.jump(ool->rejoin());
    2356           0 : }
    2357             : 
    2358             : static void
    2359           0 : FindFirstDollarIndex(MacroAssembler& masm, Register str, Register len, Register chars,
    2360             :                      Register temp, Register output, bool isLatin1)
    2361             : {
    2362           0 :     masm.loadStringChars(str, chars);
    2363             : 
    2364           0 :     masm.move32(Imm32(0), output);
    2365             : 
    2366           0 :     Label start, done;
    2367           0 :     masm.bind(&start);
    2368           0 :     if (isLatin1)
    2369           0 :         masm.load8ZeroExtend(BaseIndex(chars, output, TimesOne), temp);
    2370             :     else
    2371           0 :         masm.load16ZeroExtend(BaseIndex(chars, output, TimesTwo), temp);
    2372             : 
    2373           0 :     masm.branch32(Assembler::Equal, temp, Imm32('$'), &done);
    2374             : 
    2375           0 :     masm.add32(Imm32(1), output);
    2376           0 :     masm.branch32(Assembler::NotEqual, output, len, &start);
    2377             : 
    2378           0 :     masm.move32(Imm32(-1), output);
    2379             : 
    2380           0 :     masm.bind(&done);
    2381           0 : }
    2382             : 
    2383             : typedef bool (*GetFirstDollarIndexRawFn)(JSContext*, HandleString, int32_t*);
    2384           3 : static const VMFunction GetFirstDollarIndexRawInfo =
    2385           6 :     FunctionInfo<GetFirstDollarIndexRawFn>(GetFirstDollarIndexRaw, "GetFirstDollarIndexRaw");
    2386             : 
    2387             : void
    2388           0 : CodeGenerator::visitGetFirstDollarIndex(LGetFirstDollarIndex* ins)
    2389             : {
    2390           0 :     Register str = ToRegister(ins->str());
    2391           0 :     Register output = ToRegister(ins->output());
    2392           0 :     Register temp0 = ToRegister(ins->temp0());
    2393           0 :     Register temp1 = ToRegister(ins->temp1());
    2394           0 :     Register len = ToRegister(ins->temp2());
    2395             : 
    2396           0 :     OutOfLineCode* ool = oolCallVM(GetFirstDollarIndexRawInfo, ins, ArgList(str),
    2397           0 :                                    StoreRegisterTo(output));
    2398             : 
    2399           0 :     masm.branchIfRope(str, ool->entry());
    2400           0 :     masm.loadStringLength(str, len);
    2401             : 
    2402           0 :     Label isLatin1, done;
    2403           0 :     masm.branchLatin1String(str, &isLatin1);
    2404             :     {
    2405           0 :         FindFirstDollarIndex(masm, str, len, temp0, temp1, output, /* isLatin1 = */ false);
    2406             :     }
    2407           0 :     masm.jump(&done);
    2408             :     {
    2409           0 :         masm.bind(&isLatin1);
    2410           0 :         FindFirstDollarIndex(masm, str, len, temp0, temp1, output, /* isLatin1 = */ true);
    2411             :     }
    2412           0 :     masm.bind(&done);
    2413           0 :     masm.bind(ool->rejoin());
    2414           0 : }
    2415             : 
    2416             : typedef JSString* (*StringReplaceFn)(JSContext*, HandleString, HandleString, HandleString);
    2417           3 : static const VMFunction StringFlatReplaceInfo =
    2418           6 :     FunctionInfo<StringReplaceFn>(js::str_flat_replace_string, "str_flat_replace_string");
    2419           3 : static const VMFunction StringReplaceInfo =
    2420           6 :     FunctionInfo<StringReplaceFn>(StringReplace, "StringReplace");
    2421             : 
    2422             : void
    2423           0 : CodeGenerator::visitStringReplace(LStringReplace* lir)
    2424             : {
    2425           0 :     if (lir->replacement()->isConstant())
    2426           0 :         pushArg(ImmGCPtr(lir->replacement()->toConstant()->toString()));
    2427             :     else
    2428           0 :         pushArg(ToRegister(lir->replacement()));
    2429             : 
    2430           0 :     if (lir->pattern()->isConstant())
    2431           0 :         pushArg(ImmGCPtr(lir->pattern()->toConstant()->toString()));
    2432             :     else
    2433           0 :         pushArg(ToRegister(lir->pattern()));
    2434             : 
    2435           0 :     if (lir->string()->isConstant())
    2436           0 :         pushArg(ImmGCPtr(lir->string()->toConstant()->toString()));
    2437             :     else
    2438           0 :         pushArg(ToRegister(lir->string()));
    2439             : 
    2440           0 :     if (lir->mir()->isFlatReplacement())
    2441           0 :         callVM(StringFlatReplaceInfo, lir);
    2442             :     else
    2443           0 :         callVM(StringReplaceInfo, lir);
    2444           0 : }
    2445             : 
    2446             : void
    2447           0 : CodeGenerator::emitSharedStub(ICStub::Kind kind, LInstruction* lir)
    2448             : {
    2449           0 :     JSScript* script = lir->mirRaw()->block()->info().script();
    2450           0 :     jsbytecode* pc = lir->mirRaw()->toInstruction()->resumePoint()->pc();
    2451             : 
    2452             : #ifdef JS_USE_LINK_REGISTER
    2453             :     // Some architectures don't push the return address on the stack but
    2454             :     // use the link register. In that case the stack isn't aligned. Push
    2455             :     // to make sure we are aligned.
    2456             :     masm.Push(Imm32(0));
    2457             : #endif
    2458             : 
    2459             :     // Create descriptor signifying end of Ion frame.
    2460           0 :     uint32_t descriptor = MakeFrameDescriptor(masm.framePushed(), JitFrame_IonJS,
    2461           0 :                                               JitStubFrameLayout::Size());
    2462           0 :     masm.Push(Imm32(descriptor));
    2463             : 
    2464             :     // Call into the stubcode.
    2465           0 :     CodeOffset patchOffset;
    2466           0 :     IonICEntry entry(script->pcToOffset(pc), ICEntry::Kind_Op, script);
    2467           0 :     EmitCallIC(&patchOffset, masm);
    2468           0 :     entry.setReturnOffset(CodeOffset(masm.currentOffset()));
    2469             : 
    2470           0 :     SharedStub sharedStub(kind, entry, patchOffset);
    2471           0 :     masm.propagateOOM(sharedStubs_.append(sharedStub));
    2472             : 
    2473             :     // Fix up upon return.
    2474           0 :     uint32_t callOffset = masm.currentOffset();
    2475             : #ifdef JS_USE_LINK_REGISTER
    2476             :     masm.freeStack(sizeof(intptr_t) * 2);
    2477             : #else
    2478           0 :     masm.freeStack(sizeof(intptr_t));
    2479             : #endif
    2480           0 :     markSafepointAt(callOffset, lir);
    2481           0 : }
    2482             : 
    2483             : void
    2484           0 : CodeGenerator::visitBinarySharedStub(LBinarySharedStub* lir)
    2485             : {
    2486           0 :     JSOp jsop = JSOp(*lir->mirRaw()->toInstruction()->resumePoint()->pc());
    2487           0 :     switch (jsop) {
    2488             :       case JSOP_ADD:
    2489             :       case JSOP_SUB:
    2490             :       case JSOP_MUL:
    2491             :       case JSOP_DIV:
    2492             :       case JSOP_MOD:
    2493             :       case JSOP_POW:
    2494           0 :         emitSharedStub(ICStub::Kind::BinaryArith_Fallback, lir);
    2495           0 :         break;
    2496             :       case JSOP_LT:
    2497             :       case JSOP_LE:
    2498             :       case JSOP_GT:
    2499             :       case JSOP_GE:
    2500             :       case JSOP_EQ:
    2501             :       case JSOP_NE:
    2502             :       case JSOP_STRICTEQ:
    2503             :       case JSOP_STRICTNE:
    2504           0 :         emitSharedStub(ICStub::Kind::Compare_Fallback, lir);
    2505           0 :         break;
    2506             :       default:
    2507           0 :         MOZ_CRASH("Unsupported jsop in shared stubs.");
    2508             :     }
    2509           0 : }
    2510             : 
    2511             : void
    2512           0 : CodeGenerator::visitUnarySharedStub(LUnarySharedStub* lir)
    2513             : {
    2514           0 :     JSOp jsop = JSOp(*lir->mir()->resumePoint()->pc());
    2515           0 :     switch (jsop) {
    2516             :       case JSOP_BITNOT:
    2517             :       case JSOP_NEG:
    2518           0 :         emitSharedStub(ICStub::Kind::UnaryArith_Fallback, lir);
    2519           0 :         break;
    2520             :       case JSOP_CALLPROP:
    2521             :       case JSOP_GETPROP:
    2522             :       case JSOP_LENGTH:
    2523           0 :         emitSharedStub(ICStub::Kind::GetProp_Fallback, lir);
    2524           0 :         break;
    2525             :       default:
    2526           0 :         MOZ_CRASH("Unsupported jsop in shared stubs.");
    2527             :     }
    2528           0 : }
    2529             : 
    2530             : void
    2531           0 : CodeGenerator::visitNullarySharedStub(LNullarySharedStub* lir)
    2532             : {
    2533           0 :     jsbytecode* pc = lir->mir()->resumePoint()->pc();
    2534           0 :     JSOp jsop = JSOp(*pc);
    2535           0 :     switch (jsop) {
    2536             :       case JSOP_NEWARRAY: {
    2537           0 :         uint32_t length = GET_UINT32(pc);
    2538           0 :         MOZ_ASSERT(length <= INT32_MAX,
    2539             :                    "the bytecode emitter must fail to compile code that would "
    2540             :                    "produce JSOP_NEWARRAY with a length exceeding int32_t range");
    2541             : 
    2542             :         // Pass length in R0.
    2543           0 :         masm.move32(Imm32(AssertedCast<int32_t>(length)), R0.scratchReg());
    2544           0 :         emitSharedStub(ICStub::Kind::NewArray_Fallback, lir);
    2545           0 :         break;
    2546             :       }
    2547             :       case JSOP_NEWOBJECT:
    2548           0 :         emitSharedStub(ICStub::Kind::NewObject_Fallback, lir);
    2549           0 :         break;
    2550             :       case JSOP_NEWINIT: {
    2551           0 :         JSProtoKey key = JSProtoKey(GET_UINT8(pc));
    2552           0 :         if (key == JSProto_Array) {
    2553           0 :             masm.move32(Imm32(0), R0.scratchReg());
    2554           0 :             emitSharedStub(ICStub::Kind::NewArray_Fallback, lir);
    2555             :         } else {
    2556           0 :             emitSharedStub(ICStub::Kind::NewObject_Fallback, lir);
    2557             :         }
    2558           0 :         break;
    2559             :       }
    2560             :       default:
    2561           0 :         MOZ_CRASH("Unsupported jsop in shared stubs.");
    2562             :     }
    2563           0 : }
    2564             : 
    2565             : typedef JSObject* (*LambdaFn)(JSContext*, HandleFunction, HandleObject);
    2566           3 : static const VMFunction LambdaInfo = FunctionInfo<LambdaFn>(js::Lambda, "Lambda");
    2567             : 
    2568             : void
    2569           0 : CodeGenerator::visitLambdaForSingleton(LLambdaForSingleton* lir)
    2570             : {
    2571           0 :     pushArg(ToRegister(lir->environmentChain()));
    2572           0 :     pushArg(ImmGCPtr(lir->mir()->info().fun));
    2573           0 :     callVM(LambdaInfo, lir);
    2574           0 : }
    2575             : 
    2576             : void
    2577          10 : CodeGenerator::visitLambda(LLambda* lir)
    2578             : {
    2579          10 :     Register envChain = ToRegister(lir->environmentChain());
    2580          10 :     Register output = ToRegister(lir->output());
    2581          10 :     Register tempReg = ToRegister(lir->temp());
    2582          10 :     const LambdaFunctionInfo& info = lir->mir()->info();
    2583             : 
    2584          20 :     OutOfLineCode* ool = oolCallVM(LambdaInfo, lir, ArgList(ImmGCPtr(info.fun), envChain),
    2585          30 :                                    StoreRegisterTo(output));
    2586             : 
    2587          10 :     MOZ_ASSERT(!info.singletonType);
    2588             : 
    2589          10 :     masm.createGCObject(output, tempReg, info.fun, gc::DefaultHeap, ool->entry());
    2590             : 
    2591          10 :     emitLambdaInit(output, envChain, info);
    2592             : 
    2593          10 :     if (info.flags & JSFunction::EXTENDED) {
    2594           0 :         MOZ_ASSERT(info.fun->allowSuperProperty() || info.fun->isSelfHostedBuiltin() ||
    2595             :                    info.fun->isAsync());
    2596             :         static_assert(FunctionExtended::NUM_EXTENDED_SLOTS == 2, "All slots must be initialized");
    2597           0 :         masm.storeValue(UndefinedValue(), Address(output, FunctionExtended::offsetOfExtendedSlot(0)));
    2598           0 :         masm.storeValue(UndefinedValue(), Address(output, FunctionExtended::offsetOfExtendedSlot(1)));
    2599             :     }
    2600             : 
    2601          10 :     masm.bind(ool->rejoin());
    2602          10 : }
    2603             : 
    2604             : class OutOfLineLambdaArrow : public OutOfLineCodeBase<CodeGenerator>
    2605             : {
    2606             :   public:
    2607             :     LLambdaArrow* lir;
    2608             :     Label entryNoPop_;
    2609             : 
    2610           0 :     explicit OutOfLineLambdaArrow(LLambdaArrow* lir)
    2611           0 :       : lir(lir)
    2612           0 :     { }
    2613             : 
    2614           0 :     void accept(CodeGenerator* codegen) {
    2615           0 :         codegen->visitOutOfLineLambdaArrow(this);
    2616           0 :     }
    2617             : 
    2618           0 :     Label* entryNoPop() {
    2619           0 :         return &entryNoPop_;
    2620             :     }
    2621             : };
    2622             : 
    2623             : typedef JSObject* (*LambdaArrowFn)(JSContext*, HandleFunction, HandleObject, HandleValue);
    2624           3 : static const VMFunction LambdaArrowInfo =
    2625           6 :     FunctionInfo<LambdaArrowFn>(js::LambdaArrow, "LambdaArrow");
    2626             : 
    2627             : void
    2628           0 : CodeGenerator::visitOutOfLineLambdaArrow(OutOfLineLambdaArrow* ool)
    2629             : {
    2630           0 :     Register envChain = ToRegister(ool->lir->environmentChain());
    2631           0 :     ValueOperand newTarget = ToValue(ool->lir, LLambdaArrow::NewTargetValue);
    2632           0 :     Register output = ToRegister(ool->lir->output());
    2633           0 :     const LambdaFunctionInfo& info = ool->lir->mir()->info();
    2634             : 
    2635             :     // When we get here, we may need to restore part of the newTarget,
    2636             :     // which has been conscripted into service as a temp register.
    2637           0 :     masm.pop(newTarget.scratchReg());
    2638             : 
    2639           0 :     masm.bind(ool->entryNoPop());
    2640             : 
    2641           0 :     saveLive(ool->lir);
    2642             : 
    2643           0 :     pushArg(newTarget);
    2644           0 :     pushArg(envChain);
    2645           0 :     pushArg(ImmGCPtr(info.fun));
    2646             : 
    2647           0 :     callVM(LambdaArrowInfo, ool->lir);
    2648           0 :     StoreRegisterTo(output).generate(this);
    2649             : 
    2650           0 :     restoreLiveIgnore(ool->lir, StoreRegisterTo(output).clobbered());
    2651             : 
    2652           0 :     masm.jump(ool->rejoin());
    2653           0 : }
    2654             : 
    2655             : void
    2656           0 : CodeGenerator::visitLambdaArrow(LLambdaArrow* lir)
    2657             : {
    2658           0 :     Register envChain = ToRegister(lir->environmentChain());
    2659           0 :     ValueOperand newTarget = ToValue(lir, LLambdaArrow::NewTargetValue);
    2660           0 :     Register output = ToRegister(lir->output());
    2661           0 :     const LambdaFunctionInfo& info = lir->mir()->info();
    2662             : 
    2663           0 :     OutOfLineLambdaArrow* ool = new (alloc()) OutOfLineLambdaArrow(lir);
    2664           0 :     addOutOfLineCode(ool, lir->mir());
    2665             : 
    2666           0 :     MOZ_ASSERT(!info.useSingletonForClone);
    2667             : 
    2668           0 :     if (info.singletonType) {
    2669             :         // If the function has a singleton type, this instruction will only be
    2670             :         // executed once so we don't bother inlining it.
    2671           0 :         masm.jump(ool->entryNoPop());
    2672           0 :         masm.bind(ool->rejoin());
    2673           0 :         return;
    2674             :     }
    2675             : 
    2676             :     // There's not enough registers on x86 with the profiler enabled to request
    2677             :     // a temp. Instead, spill part of one of the values, being prepared to
    2678             :     // restore it if necessary on the out of line path.
    2679           0 :     Register tempReg = newTarget.scratchReg();
    2680           0 :     masm.push(newTarget.scratchReg());
    2681             : 
    2682           0 :     masm.createGCObject(output, tempReg, info.fun, gc::DefaultHeap, ool->entry());
    2683             : 
    2684           0 :     masm.pop(newTarget.scratchReg());
    2685             : 
    2686           0 :     emitLambdaInit(output, envChain, info);
    2687             : 
    2688             :     // Initialize extended slots. Lexical |this| is stored in the first one.
    2689           0 :     MOZ_ASSERT(info.flags & JSFunction::EXTENDED);
    2690             :     static_assert(FunctionExtended::NUM_EXTENDED_SLOTS == 2, "All slots must be initialized");
    2691             :     static_assert(FunctionExtended::ARROW_NEWTARGET_SLOT == 0,
    2692             :                   "|new.target| must be stored in first slot");
    2693           0 :     masm.storeValue(newTarget, Address(output, FunctionExtended::offsetOfExtendedSlot(0)));
    2694           0 :     masm.storeValue(UndefinedValue(), Address(output, FunctionExtended::offsetOfExtendedSlot(1)));
    2695             : 
    2696           0 :     masm.bind(ool->rejoin());
    2697             : }
    2698             : 
    2699             : void
    2700          10 : CodeGenerator::emitLambdaInit(Register output, Register envChain,
    2701             :                               const LambdaFunctionInfo& info)
    2702             : {
    2703             :     // Initialize nargs and flags. We do this with a single uint32 to avoid
    2704             :     // 16-bit writes.
    2705             :     union {
    2706             :         struct S {
    2707             :             uint16_t nargs;
    2708             :             uint16_t flags;
    2709             :         } s;
    2710             :         uint32_t word;
    2711             :     } u;
    2712          10 :     u.s.nargs = info.nargs;
    2713          10 :     u.s.flags = info.flags;
    2714             : 
    2715          10 :     MOZ_ASSERT(JSFunction::offsetOfFlags() == JSFunction::offsetOfNargs() + 2);
    2716          10 :     masm.store32(Imm32(u.word), Address(output, JSFunction::offsetOfNargs()));
    2717          20 :     masm.storePtr(ImmGCPtr(info.scriptOrLazyScript),
    2718          20 :                   Address(output, JSFunction::offsetOfNativeOrScript()));
    2719          10 :     masm.storePtr(envChain, Address(output, JSFunction::offsetOfEnvironment()));
    2720          10 :     masm.storePtr(ImmGCPtr(info.fun->displayAtom()), Address(output, JSFunction::offsetOfAtom()));
    2721          10 : }
    2722             : 
    2723             : typedef bool (*SetFunNameFn)(JSContext*, HandleFunction, HandleValue, FunctionPrefixKind);
    2724           3 : static const VMFunction SetFunNameInfo =
    2725           6 :     FunctionInfo<SetFunNameFn>(js::SetFunctionNameIfNoOwnName, "SetFunName");
    2726             : 
    2727             : void
    2728           0 : CodeGenerator::visitSetFunName(LSetFunName* lir)
    2729             : {
    2730           0 :     pushArg(Imm32(lir->mir()->prefixKind()));
    2731           0 :     pushArg(ToValue(lir, LSetFunName::NameValue));
    2732           0 :     pushArg(ToRegister(lir->fun()));
    2733             : 
    2734           0 :     callVM(SetFunNameInfo, lir);
    2735           0 : }
    2736             : 
    2737             : void
    2738         134 : CodeGenerator::visitOsiPoint(LOsiPoint* lir)
    2739             : {
    2740             :     // Note: markOsiPoint ensures enough space exists between the last
    2741             :     // LOsiPoint and this one to patch adjacent call instructions.
    2742             : 
    2743         134 :     MOZ_ASSERT(masm.framePushed() == frameSize());
    2744             : 
    2745         134 :     uint32_t osiCallPointOffset = markOsiPoint(lir);
    2746             : 
    2747         134 :     LSafepoint* safepoint = lir->associatedSafepoint();
    2748         134 :     MOZ_ASSERT(!safepoint->osiCallPointOffset());
    2749         134 :     safepoint->setOsiCallPointOffset(osiCallPointOffset);
    2750             : 
    2751             : #ifdef DEBUG
    2752             :     // There should be no movegroups or other instructions between
    2753             :     // an instruction and its OsiPoint. This is necessary because
    2754             :     // we use the OsiPoint's snapshot from within VM calls.
    2755         268 :     for (LInstructionReverseIterator iter(current->rbegin(lir)); iter != current->rend(); iter++) {
    2756         268 :         if (*iter == lir)
    2757         134 :             continue;
    2758         134 :         MOZ_ASSERT(!iter->isMoveGroup());
    2759         134 :         MOZ_ASSERT(iter->safepoint() == safepoint);
    2760         134 :         break;
    2761             :     }
    2762             : #endif
    2763             : 
    2764             : #ifdef CHECK_OSIPOINT_REGISTERS
    2765         134 :     if (shouldVerifyOsiPointRegs(safepoint))
    2766           0 :         verifyOsiPointRegs(safepoint);
    2767             : #endif
    2768         134 : }
    2769             : 
    2770             : void
    2771         149 : CodeGenerator::visitGoto(LGoto* lir)
    2772             : {
    2773         149 :     jumpToBlock(lir->target());
    2774         149 : }
    2775             : 
    2776             : // Out-of-line path to execute any move groups between the start of a loop
    2777             : // header and its interrupt check, then invoke the interrupt handler.
    2778             : class OutOfLineInterruptCheckImplicit : public OutOfLineCodeBase<CodeGenerator>
    2779             : {
    2780             :   public:
    2781             :     LBlock* block;
    2782             :     LInterruptCheck* lir;
    2783             : 
    2784           0 :     OutOfLineInterruptCheckImplicit(LBlock* block, LInterruptCheck* lir)
    2785           0 :       : block(block), lir(lir)
    2786           0 :     { }
    2787             : 
    2788           0 :     void accept(CodeGenerator* codegen) {
    2789           0 :         codegen->visitOutOfLineInterruptCheckImplicit(this);
    2790           0 :     }
    2791             : };
    2792             : 
    2793             : typedef bool (*InterruptCheckFn)(JSContext*);
    2794           3 : static const VMFunction InterruptCheckInfo =
    2795           6 :     FunctionInfo<InterruptCheckFn>(InterruptCheck, "InterruptCheck");
    2796             : 
    2797             : void
    2798           0 : CodeGenerator::visitOutOfLineInterruptCheckImplicit(OutOfLineInterruptCheckImplicit* ool)
    2799             : {
    2800             : #ifdef CHECK_OSIPOINT_REGISTERS
    2801             :     // This is path is entered from the patched back-edge of the loop. This
    2802             :     // means that the JitAtivation flags used for checking the validity of the
    2803             :     // OSI points are not reseted by the path generated by generateBody, so we
    2804             :     // have to reset it here.
    2805           0 :     resetOsiPointRegs(ool->lir->safepoint());
    2806             : #endif
    2807             : 
    2808           0 :     LInstructionIterator iter = ool->block->begin();
    2809           0 :     for (; iter != ool->block->end(); iter++) {
    2810           0 :         if (iter->isMoveGroup()) {
    2811             :             // Replay this move group that preceds the interrupt check at the
    2812             :             // start of the loop header. Any incoming jumps here will be from
    2813             :             // the backedge and will skip over the move group emitted inline.
    2814           0 :             visitMoveGroup(iter->toMoveGroup());
    2815             :         } else {
    2816           0 :             break;
    2817             :         }
    2818             :     }
    2819           0 :     MOZ_ASSERT(*iter == ool->lir);
    2820             : 
    2821           0 :     saveLive(ool->lir);
    2822           0 :     callVM(InterruptCheckInfo, ool->lir);
    2823           0 :     restoreLive(ool->lir);
    2824           0 :     masm.jump(ool->rejoin());
    2825           0 : }
    2826             : 
    2827             : void
    2828           0 : CodeGenerator::visitTableSwitch(LTableSwitch* ins)
    2829             : {
    2830           0 :     MTableSwitch* mir = ins->mir();
    2831           0 :     Label* defaultcase = skipTrivialBlocks(mir->getDefault())->lir()->label();
    2832             :     const LAllocation* temp;
    2833             : 
    2834           0 :     if (mir->getOperand(0)->type() != MIRType::Int32) {
    2835           0 :         temp = ins->tempInt()->output();
    2836             : 
    2837             :         // The input is a double, so try and convert it to an integer.
    2838             :         // If it does not fit in an integer, take the default case.
    2839           0 :         masm.convertDoubleToInt32(ToFloatRegister(ins->index()), ToRegister(temp), defaultcase, false);
    2840             :     } else {
    2841           0 :         temp = ins->index();
    2842             :     }
    2843             : 
    2844           0 :     emitTableSwitchDispatch(mir, ToRegister(temp), ToRegisterOrInvalid(ins->tempPointer()));
    2845           0 : }
    2846             : 
    2847             : void
    2848           0 : CodeGenerator::visitTableSwitchV(LTableSwitchV* ins)
    2849             : {
    2850           0 :     MTableSwitch* mir = ins->mir();
    2851           0 :     Label* defaultcase = skipTrivialBlocks(mir->getDefault())->lir()->label();
    2852             : 
    2853           0 :     Register index = ToRegister(ins->tempInt());
    2854           0 :     ValueOperand value = ToValue(ins, LTableSwitchV::InputValue);
    2855           0 :     Register tag = masm.extractTag(value, index);
    2856           0 :     masm.branchTestNumber(Assembler::NotEqual, tag, defaultcase);
    2857             : 
    2858           0 :     Label unboxInt, isInt;
    2859           0 :     masm.branchTestInt32(Assembler::Equal, tag, &unboxInt);
    2860             :     {
    2861           0 :         FloatRegister floatIndex = ToFloatRegister(ins->tempFloat());
    2862           0 :         masm.unboxDouble(value, floatIndex);
    2863           0 :         masm.convertDoubleToInt32(floatIndex, index, defaultcase, false);
    2864           0 :         masm.jump(&isInt);
    2865             :     }
    2866             : 
    2867           0 :     masm.bind(&unboxInt);
    2868           0 :     masm.unboxInt32(value, index);
    2869             : 
    2870           0 :     masm.bind(&isInt);
    2871             : 
    2872           0 :     emitTableSwitchDispatch(mir, index, ToRegisterOrInvalid(ins->tempPointer()));
    2873           0 : }
    2874             : 
    2875             : typedef JSObject* (*DeepCloneObjectLiteralFn)(JSContext*, HandleObject, NewObjectKind);
    2876           3 : static const VMFunction DeepCloneObjectLiteralInfo =
    2877           6 :     FunctionInfo<DeepCloneObjectLiteralFn>(DeepCloneObjectLiteral, "DeepCloneObjectLiteral");
    2878             : 
    2879             : void
    2880           0 : CodeGenerator::visitCloneLiteral(LCloneLiteral* lir)
    2881             : {
    2882           0 :     pushArg(ImmWord(TenuredObject));
    2883           0 :     pushArg(ToRegister(lir->getObjectLiteral()));
    2884           0 :     callVM(DeepCloneObjectLiteralInfo, lir);
    2885           0 : }
    2886             : 
    2887             : void
    2888          36 : CodeGenerator::visitParameter(LParameter* lir)
    2889             : {
    2890          36 : }
    2891             : 
    2892             : void
    2893           3 : CodeGenerator::visitCallee(LCallee* lir)
    2894             : {
    2895           3 :     Register callee = ToRegister(lir->output());
    2896           3 :     Address ptr(masm.getStackPointer(), frameSize() + JitFrameLayout::offsetOfCalleeToken());
    2897             : 
    2898           3 :     masm.loadFunctionFromCalleeToken(ptr, callee);
    2899           3 : }
    2900             : 
    2901             : void
    2902           0 : CodeGenerator::visitIsConstructing(LIsConstructing* lir)
    2903             : {
    2904           0 :     Register output = ToRegister(lir->output());
    2905           0 :     Address calleeToken(masm.getStackPointer(), frameSize() + JitFrameLayout::offsetOfCalleeToken());
    2906           0 :     masm.loadPtr(calleeToken, output);
    2907             : 
    2908             :     // We must be inside a function.
    2909           0 :     MOZ_ASSERT(current->mir()->info().script()->functionNonDelazifying());
    2910             : 
    2911             :     // The low bit indicates whether this call is constructing, just clear the
    2912             :     // other bits.
    2913             :     static_assert(CalleeToken_Function == 0x0, "CalleeTokenTag value should match");
    2914             :     static_assert(CalleeToken_FunctionConstructing == 0x1, "CalleeTokenTag value should match");
    2915           0 :     masm.andPtr(Imm32(0x1), output);
    2916           0 : }
    2917             : 
    2918             : void
    2919          11 : CodeGenerator::visitStart(LStart* lir)
    2920             : {
    2921          11 : }
    2922             : 
    2923             : void
    2924          17 : CodeGenerator::visitReturn(LReturn* lir)
    2925             : {
    2926             : #if defined(JS_NUNBOX32)
    2927             :     DebugOnly<LAllocation*> type    = lir->getOperand(TYPE_INDEX);
    2928             :     DebugOnly<LAllocation*> payload = lir->getOperand(PAYLOAD_INDEX);
    2929             :     MOZ_ASSERT(ToRegister(type)    == JSReturnReg_Type);
    2930             :     MOZ_ASSERT(ToRegister(payload) == JSReturnReg_Data);
    2931             : #elif defined(JS_PUNBOX64)
    2932          34 :     DebugOnly<LAllocation*> result = lir->getOperand(0);
    2933          17 :     MOZ_ASSERT(ToRegister(result) == JSReturnReg);
    2934             : #endif
    2935             :     // Don't emit a jump to the return label if this is the last block.
    2936          17 :     if (current->mir() != *gen->graph().poBegin())
    2937          11 :         masm.jump(&returnLabel_);
    2938          17 : }
    2939             : 
    2940             : void
    2941           3 : CodeGenerator::visitOsrEntry(LOsrEntry* lir)
    2942             : {
    2943           3 :     Register temp = ToRegister(lir->temp());
    2944             : 
    2945             :     // Remember the OSR entry offset into the code buffer.
    2946           3 :     masm.flushBuffer();
    2947           3 :     setOsrEntryOffset(masm.size());
    2948             : 
    2949             : #ifdef JS_TRACE_LOGGING
    2950           3 :     emitTracelogStopEvent(TraceLogger_Baseline);
    2951           3 :     emitTracelogStartEvent(TraceLogger_IonMonkey);
    2952             : #endif
    2953             : 
    2954             :     // If profiling, save the current frame pointer to a per-thread global field.
    2955           3 :     if (isProfilerInstrumentationEnabled())
    2956           0 :         masm.profilerEnterFrame(masm.getStackPointer(), temp);
    2957             : 
    2958             :     // Allocate the full frame for this function
    2959             :     // Note we have a new entry here. So we reset MacroAssembler::framePushed()
    2960             :     // to 0, before reserving the stack.
    2961           3 :     MOZ_ASSERT(masm.framePushed() == frameSize());
    2962           3 :     masm.setFramePushed(0);
    2963             : 
    2964             :     // Ensure that the Ion frames is properly aligned.
    2965           3 :     masm.assertStackAlignment(JitStackAlignment, 0);
    2966             : 
    2967           3 :     masm.reserveStack(frameSize());
    2968           3 : }
    2969             : 
    2970             : void
    2971           2 : CodeGenerator::visitOsrEnvironmentChain(LOsrEnvironmentChain* lir)
    2972             : {
    2973           2 :     const LAllocation* frame   = lir->getOperand(0);
    2974           2 :     const LDefinition* object  = lir->getDef(0);
    2975             : 
    2976           2 :     const ptrdiff_t frameOffset = BaselineFrame::reverseOffsetOfEnvironmentChain();
    2977             : 
    2978           2 :     masm.loadPtr(Address(ToRegister(frame), frameOffset), ToRegister(object));
    2979           2 : }
    2980             : 
    2981             : void
    2982           0 : CodeGenerator::visitOsrArgumentsObject(LOsrArgumentsObject* lir)
    2983             : {
    2984           0 :     const LAllocation* frame   = lir->getOperand(0);
    2985           0 :     const LDefinition* object  = lir->getDef(0);
    2986             : 
    2987           0 :     const ptrdiff_t frameOffset = BaselineFrame::reverseOffsetOfArgsObj();
    2988             : 
    2989           0 :     masm.loadPtr(Address(ToRegister(frame), frameOffset), ToRegister(object));
    2990           0 : }
    2991             : 
    2992             : void
    2993          42 : CodeGenerator::visitOsrValue(LOsrValue* value)
    2994             : {
    2995          42 :     const LAllocation* frame   = value->getOperand(0);
    2996          42 :     const ValueOperand out     = ToOutValue(value);
    2997             : 
    2998          42 :     const ptrdiff_t frameOffset = value->mir()->frameOffset();
    2999             : 
    3000          42 :     masm.loadValue(Address(ToRegister(frame), frameOffset), out);
    3001          42 : }
    3002             : 
    3003             : void
    3004           3 : CodeGenerator::visitOsrReturnValue(LOsrReturnValue* lir)
    3005             : {
    3006           3 :     const LAllocation* frame   = lir->getOperand(0);
    3007           3 :     const ValueOperand out     = ToOutValue(lir);
    3008             : 
    3009           3 :     Address flags = Address(ToRegister(frame), BaselineFrame::reverseOffsetOfFlags());
    3010           3 :     Address retval = Address(ToRegister(frame), BaselineFrame::reverseOffsetOfReturnValue());
    3011             : 
    3012           3 :     masm.moveValue(UndefinedValue(), out);
    3013             : 
    3014           6 :     Label done;
    3015           3 :     masm.branchTest32(Assembler::Zero, flags, Imm32(BaselineFrame::HAS_RVAL), &done);
    3016           3 :     masm.loadValue(retval, out);
    3017           3 :     masm.bind(&done);
    3018           3 : }
    3019             : 
    3020             : void
    3021          62 : CodeGenerator::visitStackArgT(LStackArgT* lir)
    3022             : {
    3023          62 :     const LAllocation* arg = lir->getArgument();
    3024          62 :     MIRType argType = lir->type();
    3025          62 :     uint32_t argslot = lir->argslot();
    3026          62 :     MOZ_ASSERT(argslot - 1u < graph.argumentSlotCount());
    3027             : 
    3028          62 :     int32_t stack_offset = StackOffsetOfPassedArg(argslot);
    3029          62 :     Address dest(masm.getStackPointer(), stack_offset);
    3030             : 
    3031          62 :     if (arg->isFloatReg())
    3032           0 :         masm.storeDouble(ToFloatRegister(arg), dest);
    3033          62 :     else if (arg->isRegister())
    3034          42 :         masm.storeValue(ValueTypeFromMIRType(argType), ToRegister(arg), dest);
    3035             :     else
    3036          20 :         masm.storeValue(arg->toConstant()->toJSValue(), dest);
    3037          62 : }
    3038             : 
    3039             : void
    3040           9 : CodeGenerator::visitStackArgV(LStackArgV* lir)
    3041             : {
    3042           9 :     ValueOperand val = ToValue(lir, 0);
    3043           9 :     uint32_t argslot = lir->argslot();
    3044           9 :     MOZ_ASSERT(argslot - 1u < graph.argumentSlotCount());
    3045             : 
    3046           9 :     int32_t stack_offset = StackOffsetOfPassedArg(argslot);
    3047             : 
    3048           9 :     masm.storeValue(val, Address(masm.getStackPointer(), stack_offset));
    3049           9 : }
    3050             : 
    3051             : void
    3052         429 : CodeGenerator::visitMoveGroup(LMoveGroup* group)
    3053             : {
    3054         429 :     if (!group->numMoves())
    3055           0 :         return;
    3056             : 
    3057         429 :     MoveResolver& resolver = masm.moveResolver();
    3058             : 
    3059         983 :     for (size_t i = 0; i < group->numMoves(); i++) {
    3060         554 :         const LMove& move = group->getMove(i);
    3061             : 
    3062         554 :         LAllocation from = move.from();
    3063         554 :         LAllocation to = move.to();
    3064         554 :         LDefinition::Type type = move.type();
    3065             : 
    3066             :         // No bogus moves.
    3067         554 :         MOZ_ASSERT(from != to);
    3068         554 :         MOZ_ASSERT(!from.isConstant());
    3069             :         MoveOp::Type moveType;
    3070         554 :         switch (type) {
    3071             :           case LDefinition::OBJECT:
    3072             :           case LDefinition::SLOTS:
    3073             : #ifdef JS_NUNBOX32
    3074             :           case LDefinition::TYPE:
    3075             :           case LDefinition::PAYLOAD:
    3076             : #else
    3077             :           case LDefinition::BOX:
    3078             : #endif
    3079         389 :           case LDefinition::GENERAL:      moveType = MoveOp::GENERAL;      break;
    3080         165 :           case LDefinition::INT32:        moveType = MoveOp::INT32;        break;
    3081           0 :           case LDefinition::FLOAT32:      moveType = MoveOp::FLOAT32;      break;
    3082           0 :           case LDefinition::DOUBLE:       moveType = MoveOp::DOUBLE;       break;
    3083           0 :           case LDefinition::SIMD128INT:   moveType = MoveOp::SIMD128INT;   break;
    3084           0 :           case LDefinition::SIMD128FLOAT: moveType = MoveOp::SIMD128FLOAT; break;
    3085           0 :           default: MOZ_CRASH("Unexpected move type");
    3086             :         }
    3087             : 
    3088         554 :         masm.propagateOOM(resolver.addMove(toMoveOperand(from), toMoveOperand(to), moveType));
    3089             :     }
    3090             : 
    3091         429 :     masm.propagateOOM(resolver.resolve());
    3092         429 :     if (masm.oom())
    3093           0 :         return;
    3094             : 
    3095         858 :     MoveEmitter emitter(masm);
    3096             : 
    3097             : #ifdef JS_CODEGEN_X86
    3098             :     if (group->maybeScratchRegister().isGeneralReg())
    3099             :         emitter.setScratchRegister(group->maybeScratchRegister().toGeneralReg()->reg());
    3100             :     else
    3101             :         resolver.sortMemoryToMemoryMoves();
    3102             : #endif
    3103             : 
    3104         429 :     emitter.emit(resolver);
    3105         429 :     emitter.finish();
    3106             : }
    3107             : 
    3108             : void
    3109          50 : CodeGenerator::visitInteger(LInteger* lir)
    3110             : {
    3111          50 :     masm.move32(Imm32(lir->getValue()), ToRegister(lir->output()));
    3112          50 : }
    3113             : 
    3114             : void
    3115           0 : CodeGenerator::visitInteger64(LInteger64* lir)
    3116             : {
    3117           0 :     masm.move64(Imm64(lir->getValue()), ToOutRegister64(lir));
    3118           0 : }
    3119             : 
    3120             : void
    3121          19 : CodeGenerator::visitPointer(LPointer* lir)
    3122             : {
    3123          19 :     if (lir->kind() == LPointer::GC_THING)
    3124          19 :         masm.movePtr(ImmGCPtr(lir->gcptr()), ToRegister(lir->output()));
    3125             :     else
    3126           0 :         masm.movePtr(ImmPtr(lir->ptr()), ToRegister(lir->output()));
    3127          19 : }
    3128             : 
    3129             : void
    3130           2 : CodeGenerator::visitKeepAliveObject(LKeepAliveObject* lir)
    3131             : {
    3132             :     // No-op.
    3133           2 : }
    3134             : 
    3135             : void
    3136           7 : CodeGenerator::visitSlots(LSlots* lir)
    3137             : {
    3138           7 :     Address slots(ToRegister(lir->object()), NativeObject::offsetOfSlots());
    3139           7 :     masm.loadPtr(slots, ToRegister(lir->output()));
    3140           7 : }
    3141             : 
    3142             : void
    3143           7 : CodeGenerator::visitLoadSlotT(LLoadSlotT* lir)
    3144             : {
    3145           7 :     Register base = ToRegister(lir->slots());
    3146           7 :     int32_t offset = lir->mir()->slot() * sizeof(js::Value);
    3147           7 :     AnyRegister result = ToAnyRegister(lir->output());
    3148             : 
    3149           7 :     masm.loadUnboxedValue(Address(base, offset), lir->mir()->type(), result);
    3150           7 : }
    3151             : 
    3152             : void
    3153           0 : CodeGenerator::visitLoadSlotV(LLoadSlotV* lir)
    3154             : {
    3155           0 :     ValueOperand dest = ToOutValue(lir);
    3156           0 :     Register base = ToRegister(lir->input());
    3157           0 :     int32_t offset = lir->mir()->slot() * sizeof(js::Value);
    3158             : 
    3159           0 :     masm.loadValue(Address(base, offset), dest);
    3160           0 : }
    3161             : 
    3162             : void
    3163           0 : CodeGenerator::visitStoreSlotT(LStoreSlotT* lir)
    3164             : {
    3165           0 :     Register base = ToRegister(lir->slots());
    3166           0 :     int32_t offset = lir->mir()->slot() * sizeof(js::Value);
    3167           0 :     Address dest(base, offset);
    3168             : 
    3169           0 :     if (lir->mir()->needsBarrier())
    3170           0 :         emitPreBarrier(dest);
    3171             : 
    3172           0 :     MIRType valueType = lir->mir()->value()->type();
    3173             : 
    3174           0 :     if (valueType == MIRType::ObjectOrNull) {
    3175           0 :         masm.storeObjectOrNull(ToRegister(lir->value()), dest);
    3176             :     } else {
    3177           0 :         ConstantOrRegister value;
    3178           0 :         if (lir->value()->isConstant())
    3179           0 :             value = ConstantOrRegister(lir->value()->toConstant()->toJSValue());
    3180             :         else
    3181           0 :             value = TypedOrValueRegister(valueType, ToAnyRegister(lir->value()));
    3182           0 :         masm.storeUnboxedValue(value, valueType, dest, lir->mir()->slotType());
    3183             :     }
    3184           0 : }
    3185             : 
    3186             : void
    3187           0 : CodeGenerator::visitStoreSlotV(LStoreSlotV* lir)
    3188             : {
    3189           0 :     Register base = ToRegister(lir->slots());
    3190           0 :     int32_t offset = lir->mir()->slot() * sizeof(Value);
    3191             : 
    3192           0 :     const ValueOperand value = ToValue(lir, LStoreSlotV::Value);
    3193             : 
    3194           0 :     if (lir->mir()->needsBarrier())
    3195           0 :        emitPreBarrier(Address(base, offset));
    3196             : 
    3197           0 :     masm.storeValue(value, Address(base, offset));
    3198           0 : }
    3199             : 
    3200             : static void
    3201           0 : GuardReceiver(MacroAssembler& masm, const ReceiverGuard& guard,
    3202             :               Register obj, Register scratch, Label* miss, bool checkNullExpando)
    3203             : {
    3204           0 :     if (guard.group) {
    3205           0 :         masm.branchTestObjGroup(Assembler::NotEqual, obj, guard.group, miss);
    3206             : 
    3207           0 :         Address expandoAddress(obj, UnboxedPlainObject::offsetOfExpando());
    3208           0 :         if (guard.shape) {
    3209           0 :             masm.loadPtr(expandoAddress, scratch);
    3210           0 :             masm.branchPtr(Assembler::Equal, scratch, ImmWord(0), miss);
    3211           0 :             masm.branchTestObjShape(Assembler::NotEqual, scratch, guard.shape, miss);
    3212           0 :         } else if (checkNullExpando) {
    3213           0 :             masm.branchPtr(Assembler::NotEqual, expandoAddress, ImmWord(0), miss);
    3214             :         }
    3215             :     } else {
    3216           0 :         masm.branchTestObjShape(Assembler::NotEqual, obj, guard.shape, miss);
    3217             :     }
    3218           0 : }
    3219             : 
    3220             : void
    3221           0 : CodeGenerator::emitGetPropertyPolymorphic(LInstruction* ins, Register obj, Register scratch,
    3222             :                                           const TypedOrValueRegister& output)
    3223             : {
    3224           0 :     MGetPropertyPolymorphic* mir = ins->mirRaw()->toGetPropertyPolymorphic();
    3225             : 
    3226           0 :     Label done;
    3227             : 
    3228           0 :     for (size_t i = 0; i < mir->numReceivers(); i++) {
    3229           0 :         ReceiverGuard receiver = mir->receiver(i);
    3230             : 
    3231           0 :         Label next;
    3232           0 :         masm.comment("GuardReceiver");
    3233           0 :         GuardReceiver(masm, receiver, obj, scratch, &next, /* checkNullExpando = */ false);
    3234             : 
    3235           0 :         if (receiver.shape) {
    3236           0 :             masm.comment("loadTypedOrValue");
    3237             :             // If this is an unboxed expando access, GuardReceiver loaded the
    3238             :             // expando object into scratch.
    3239           0 :             Register target = receiver.group ? scratch : obj;
    3240             : 
    3241           0 :             Shape* shape = mir->shape(i);
    3242           0 :             if (shape->slot() < shape->numFixedSlots()) {
    3243             :                 // Fixed slot.
    3244           0 :                 masm.loadTypedOrValue(Address(target, NativeObject::getFixedSlotOffset(shape->slot())),
    3245           0 :                                       output);
    3246             :             } else {
    3247             :                 // Dynamic slot.
    3248           0 :                 uint32_t offset = (shape->slot() - shape->numFixedSlots()) * sizeof(js::Value);
    3249           0 :                 masm.loadPtr(Address(target, NativeObject::offsetOfSlots()), scratch);
    3250           0 :                 masm.loadTypedOrValue(Address(scratch, offset), output);
    3251             :             }
    3252             :         } else {
    3253           0 :             masm.comment("loadUnboxedProperty");
    3254             :             const UnboxedLayout::Property* property =
    3255           0 :                 receiver.group->unboxedLayout().lookup(mir->name());
    3256           0 :             Address propertyAddr(obj, UnboxedPlainObject::offsetOfData() + property->offset);
    3257             : 
    3258           0 :             masm.loadUnboxedProperty(propertyAddr, property->type, output);
    3259             :         }
    3260             : 
    3261           0 :         if (i == mir->numReceivers() - 1) {
    3262           0 :             bailoutFrom(&next, ins->snapshot());
    3263             :         } else {
    3264           0 :             masm.jump(&done);
    3265           0 :             masm.bind(&next);
    3266             :         }
    3267             :     }
    3268             : 
    3269           0 :     masm.bind(&done);
    3270           0 : }
    3271             : 
    3272             : void
    3273           0 : CodeGenerator::visitGetPropertyPolymorphicV(LGetPropertyPolymorphicV* ins)
    3274             : {
    3275           0 :     Register obj = ToRegister(ins->obj());
    3276           0 :     ValueOperand output = GetValueOutput(ins);
    3277           0 :     emitGetPropertyPolymorphic(ins, obj, output.scratchReg(), output);
    3278           0 : }
    3279             : 
    3280             : void
    3281           0 : CodeGenerator::visitGetPropertyPolymorphicT(LGetPropertyPolymorphicT* ins)
    3282             : {
    3283           0 :     Register obj = ToRegister(ins->obj());
    3284           0 :     TypedOrValueRegister output(ins->mir()->type(), ToAnyRegister(ins->output()));
    3285           0 :     Register temp = (output.type() == MIRType::Double)
    3286           0 :                     ? ToRegister(ins->temp())
    3287           0 :                     : output.typedReg().gpr();
    3288           0 :     emitGetPropertyPolymorphic(ins, obj, temp, output);
    3289           0 : }
    3290             : 
    3291             : template <typename T>
    3292             : static void
    3293           0 : EmitUnboxedPreBarrier(MacroAssembler &masm, T address, JSValueType type)
    3294             : {
    3295           0 :     if (type == JSVAL_TYPE_OBJECT)
    3296           0 :         masm.guardedCallPreBarrier(address, MIRType::Object);
    3297           0 :     else if (type == JSVAL_TYPE_STRING)
    3298           0 :         masm.guardedCallPreBarrier(address, MIRType::String);
    3299             :     else
    3300           0 :         MOZ_ASSERT(!UnboxedTypeNeedsPreBarrier(type));
    3301           0 : }
    3302             : 
    3303             : void
    3304           0 : CodeGenerator::emitSetPropertyPolymorphic(LInstruction* ins, Register obj, Register scratch,
    3305             :                                           const ConstantOrRegister& value)
    3306             : {
    3307           0 :     MSetPropertyPolymorphic* mir = ins->mirRaw()->toSetPropertyPolymorphic();
    3308             : 
    3309           0 :     Label done;
    3310           0 :     for (size_t i = 0; i < mir->numReceivers(); i++) {
    3311           0 :         ReceiverGuard receiver = mir->receiver(i);
    3312             : 
    3313           0 :         Label next;
    3314           0 :         GuardReceiver(masm, receiver, obj, scratch, &next, /* checkNullExpando = */ false);
    3315             : 
    3316           0 :         if (receiver.shape) {
    3317             :             // If this is an unboxed expando access, GuardReceiver loaded the
    3318             :             // expando object into scratch.
    3319           0 :             Register target = receiver.group ? scratch : obj;
    3320             : 
    3321           0 :             Shape* shape = mir->shape(i);
    3322           0 :             if (shape->slot() < shape->numFixedSlots()) {
    3323             :                 // Fixed slot.
    3324           0 :                 Address addr(target, NativeObject::getFixedSlotOffset(shape->slot()));
    3325           0 :                 if (mir->needsBarrier())
    3326           0 :                     emitPreBarrier(addr);
    3327           0 :                 masm.storeConstantOrRegister(value, addr);
    3328             :             } else {
    3329             :                 // Dynamic slot.
    3330           0 :                 masm.loadPtr(Address(target, NativeObject::offsetOfSlots()), scratch);
    3331           0 :                 Address addr(scratch, (shape->slot() - shape->numFixedSlots()) * sizeof(js::Value));
    3332           0 :                 if (mir->needsBarrier())
    3333           0 :                     emitPreBarrier(addr);
    3334           0 :                 masm.storeConstantOrRegister(value, addr);
    3335             :             }
    3336             :         } else {
    3337             :             const UnboxedLayout::Property* property =
    3338           0 :                 receiver.group->unboxedLayout().lookup(mir->name());
    3339           0 :             Address propertyAddr(obj, UnboxedPlainObject::offsetOfData() + property->offset);
    3340             : 
    3341           0 :             EmitUnboxedPreBarrier(masm, propertyAddr, property->type);
    3342           0 :             masm.storeUnboxedProperty(propertyAddr, property->type, value, nullptr);
    3343             :         }
    3344             : 
    3345           0 :         if (i == mir->numReceivers() - 1) {
    3346           0 :             bailoutFrom(&next, ins->snapshot());
    3347             :         } else {
    3348           0 :             masm.jump(&done);
    3349           0 :             masm.bind(&next);
    3350             :         }
    3351             :     }
    3352             : 
    3353           0 :     masm.bind(&done);
    3354           0 : }
    3355             : 
    3356             : void
    3357           0 : CodeGenerator::visitSetPropertyPolymorphicV(LSetPropertyPolymorphicV* ins)
    3358             : {
    3359           0 :     Register obj = ToRegister(ins->obj());
    3360           0 :     Register temp = ToRegister(ins->temp());
    3361           0 :     ValueOperand value = ToValue(ins, LSetPropertyPolymorphicV::Value);
    3362           0 :     emitSetPropertyPolymorphic(ins, obj, temp, TypedOrValueRegister(value));
    3363           0 : }
    3364             : 
    3365             : void
    3366           0 : CodeGenerator::visitSetPropertyPolymorphicT(LSetPropertyPolymorphicT* ins)
    3367             : {
    3368           0 :     Register obj = ToRegister(ins->obj());
    3369           0 :     Register temp = ToRegister(ins->temp());
    3370             : 
    3371           0 :     ConstantOrRegister value;
    3372           0 :     if (ins->mir()->value()->isConstant())
    3373           0 :         value = ConstantOrRegister(ins->mir()->value()->toConstant()->toJSValue());
    3374             :     else
    3375           0 :         value = TypedOrValueRegister(ins->mir()->value()->type(), ToAnyRegister(ins->value()));
    3376             : 
    3377           0 :     emitSetPropertyPolymorphic(ins, obj, temp, value);
    3378           0 : }
    3379             : 
    3380             : void
    3381           7 : CodeGenerator::visitElements(LElements* lir)
    3382             : {
    3383             :     Address elements(ToRegister(lir->object()),
    3384           7 :                      lir->mir()->unboxed() ? UnboxedArrayObject::offsetOfElements()
    3385           7 :                                            : NativeObject::offsetOfElements());
    3386           7 :     masm.loadPtr(elements, ToRegister(lir->output()));
    3387           7 : }
    3388             : 
    3389             : typedef bool (*ConvertElementsToDoublesFn)(JSContext*, uintptr_t);
    3390           3 : static const VMFunction ConvertElementsToDoublesInfo =
    3391           6 :     FunctionInfo<ConvertElementsToDoublesFn>(ObjectElements::ConvertElementsToDoubles,
    3392             :                                              "ObjectElements::ConvertElementsToDoubles");
    3393             : 
    3394             : void
    3395           0 : CodeGenerator::visitConvertElementsToDoubles(LConvertElementsToDoubles* lir)
    3396             : {
    3397           0 :     Register elements = ToRegister(lir->elements());
    3398             : 
    3399           0 :     OutOfLineCode* ool = oolCallVM(ConvertElementsToDoublesInfo, lir,
    3400           0 :                                    ArgList(elements), StoreNothing());
    3401             : 
    3402           0 :     Address convertedAddress(elements, ObjectElements::offsetOfFlags());
    3403           0 :     Imm32 bit(ObjectElements::CONVERT_DOUBLE_ELEMENTS);
    3404           0 :     masm.branchTest32(Assembler::Zero, convertedAddress, bit, ool->entry());
    3405           0 :     masm.bind(ool->rejoin());
    3406           0 : }
    3407             : 
    3408             : void
    3409           0 : CodeGenerator::visitMaybeToDoubleElement(LMaybeToDoubleElement* lir)
    3410             : {
    3411           0 :     Register elements = ToRegister(lir->elements());
    3412           0 :     Register value = ToRegister(lir->value());
    3413           0 :     ValueOperand out = ToOutValue(lir);
    3414             : 
    3415           0 :     FloatRegister temp = ToFloatRegister(lir->tempFloat());
    3416           0 :     Label convert, done;
    3417             : 
    3418             :     // If the CONVERT_DOUBLE_ELEMENTS flag is set, convert the int32
    3419             :     // value to double. Else, just box it.
    3420           0 :     masm.branchTest32(Assembler::NonZero,
    3421           0 :                       Address(elements, ObjectElements::offsetOfFlags()),
    3422             :                       Imm32(ObjectElements::CONVERT_DOUBLE_ELEMENTS),
    3423           0 :                       &convert);
    3424             : 
    3425           0 :     masm.tagValue(JSVAL_TYPE_INT32, value, out);
    3426           0 :     masm.jump(&done);
    3427             : 
    3428           0 :     masm.bind(&convert);
    3429           0 :     masm.convertInt32ToDouble(value, temp);
    3430           0 :     masm.boxDouble(temp, out);
    3431             : 
    3432           0 :     masm.bind(&done);
    3433           0 : }
    3434             : 
    3435             : typedef bool (*CopyElementsForWriteFn)(JSContext*, NativeObject*);
    3436           3 : static const VMFunction CopyElementsForWriteInfo =
    3437           6 :     FunctionInfo<CopyElementsForWriteFn>(NativeObject::CopyElementsForWrite,
    3438             :                                          "NativeObject::CopyElementsForWrite");
    3439             : 
    3440             : void
    3441           0 : CodeGenerator::visitMaybeCopyElementsForWrite(LMaybeCopyElementsForWrite* lir)
    3442             : {
    3443           0 :     Register object = ToRegister(lir->object());
    3444           0 :     Register temp = ToRegister(lir->temp());
    3445             : 
    3446           0 :     OutOfLineCode* ool = oolCallVM(CopyElementsForWriteInfo, lir,
    3447           0 :                                    ArgList(object), StoreNothing());
    3448             : 
    3449           0 :     if (lir->mir()->checkNative()) {
    3450           0 :         masm.loadObjClass(object, temp);
    3451           0 :         masm.branchTest32(Assembler::NonZero, Address(temp, Class::offsetOfFlags()),
    3452           0 :                           Imm32(Class::NON_NATIVE), ool->rejoin());
    3453             :     }
    3454             : 
    3455           0 :     masm.loadPtr(Address(object, NativeObject::offsetOfElements()), temp);
    3456           0 :     masm.branchTest32(Assembler::NonZero,
    3457           0 :                       Address(temp, ObjectElements::offsetOfFlags()),
    3458             :                       Imm32(ObjectElements::COPY_ON_WRITE),
    3459           0 :                       ool->entry());
    3460           0 :     masm.bind(ool->rejoin());
    3461           0 : }
    3462             : 
    3463             : void
    3464           6 : CodeGenerator::visitFunctionEnvironment(LFunctionEnvironment* lir)
    3465             : {
    3466           6 :     Address environment(ToRegister(lir->function()), JSFunction::offsetOfEnvironment());
    3467           6 :     masm.loadPtr(environment, ToRegister(lir->output()));
    3468           6 : }
    3469             : 
    3470             : typedef LexicalEnvironmentObject* (*NewLexicalEnvironmentObjectFn)(JSContext*,
    3471             :                                                                    Handle<LexicalScope*>,
    3472             :                                                                    HandleObject, gc::InitialHeap);
    3473           3 : static const VMFunction NewLexicalEnvironmentObjectInfo =
    3474           6 :     FunctionInfo<NewLexicalEnvironmentObjectFn>(LexicalEnvironmentObject::create,
    3475             :                                                 "LexicalEnvironmentObject::create");
    3476             : 
    3477             : void
    3478           0 : CodeGenerator::visitNewLexicalEnvironmentObject(LNewLexicalEnvironmentObject* lir)
    3479             : {
    3480           0 :     pushArg(Imm32(gc::DefaultHeap));
    3481           0 :     pushArg(ToRegister(lir->enclosing()));
    3482           0 :     pushArg(ImmGCPtr(lir->mir()->scope()));
    3483           0 :     callVM(NewLexicalEnvironmentObjectInfo, lir);
    3484           0 : }
    3485             : 
    3486             : typedef JSObject* (*CopyLexicalEnvironmentObjectFn)(JSContext*, HandleObject, bool);
    3487           3 : static const VMFunction CopyLexicalEnvironmentObjectInfo =
    3488           6 :     FunctionInfo<CopyLexicalEnvironmentObjectFn>(js::jit::CopyLexicalEnvironmentObject,
    3489             :                                                 "js::jit::CopyLexicalEnvironmentObject");
    3490             : 
    3491             : void
    3492           0 : CodeGenerator::visitCopyLexicalEnvironmentObject(LCopyLexicalEnvironmentObject* lir)
    3493             : {
    3494           0 :     pushArg(Imm32(lir->mir()->copySlots()));
    3495           0 :     pushArg(ToRegister(lir->env()));
    3496           0 :     callVM(CopyLexicalEnvironmentObjectInfo, lir);
    3497           0 : }
    3498             : 
    3499             : void
    3500           0 : CodeGenerator::visitGuardObjectIdentity(LGuardObjectIdentity* guard)
    3501             : {
    3502           0 :     Register input = ToRegister(guard->input());
    3503           0 :     Register expected = ToRegister(guard->expected());
    3504             : 
    3505             :     Assembler::Condition cond =
    3506           0 :         guard->mir()->bailOnEquality() ? Assembler::Equal : Assembler::NotEqual;
    3507           0 :     bailoutCmpPtr(cond, input, expected, guard->snapshot());
    3508           0 : }
    3509             : 
    3510             : void
    3511           0 : CodeGenerator::visitGuardReceiverPolymorphic(LGuardReceiverPolymorphic* lir)
    3512             : {
    3513           0 :     const MGuardReceiverPolymorphic* mir = lir->mir();
    3514           0 :     Register obj = ToRegister(lir->object());
    3515           0 :     Register temp = ToRegister(lir->temp());
    3516             : 
    3517           0 :     Label done;
    3518             : 
    3519           0 :     for (size_t i = 0; i < mir->numReceivers(); i++) {
    3520           0 :         const ReceiverGuard& receiver = mir->receiver(i);
    3521             : 
    3522           0 :         Label next;
    3523           0 :         GuardReceiver(masm, receiver, obj, temp, &next, /* checkNullExpando = */ true);
    3524             : 
    3525           0 :         if (i == mir->numReceivers() - 1) {
    3526           0 :             bailoutFrom(&next, lir->snapshot());
    3527             :         } else {
    3528           0 :             masm.jump(&done);
    3529           0 :             masm.bind(&next);
    3530             :         }
    3531             :     }
    3532             : 
    3533           0 :     masm.bind(&done);
    3534           0 : }
    3535             : 
    3536             : void
    3537           0 : CodeGenerator::visitGuardUnboxedExpando(LGuardUnboxedExpando* lir)
    3538             : {
    3539           0 :     Label miss;
    3540             : 
    3541           0 :     Register obj = ToRegister(lir->object());
    3542           0 :     masm.branchPtr(lir->mir()->requireExpando() ? Assembler::Equal : Assembler::NotEqual,
    3543           0 :                    Address(obj, UnboxedPlainObject::offsetOfExpando()), ImmWord(0), &miss);
    3544             : 
    3545           0 :     bailoutFrom(&miss, lir->snapshot());
    3546           0 : }
    3547             : 
    3548             : void
    3549           0 : CodeGenerator::visitLoadUnboxedExpando(LLoadUnboxedExpando* lir)
    3550             : {
    3551           0 :     Register obj = ToRegister(lir->object());
    3552           0 :     Register result = ToRegister(lir->getDef(0));
    3553             : 
    3554           0 :     masm.loadPtr(Address(obj, UnboxedPlainObject::offsetOfExpando()), result);
    3555           0 : }
    3556             : 
    3557             : void
    3558          47 : CodeGenerator::visitTypeBarrierV(LTypeBarrierV* lir)
    3559             : {
    3560          47 :     ValueOperand operand = ToValue(lir, LTypeBarrierV::Input);
    3561          47 :     Register scratch = ToTempRegisterOrInvalid(lir->temp());
    3562             : 
    3563          94 :     Label miss;
    3564          47 :     masm.guardTypeSet(operand, lir->mir()->resultTypeSet(), lir->mir()->barrierKind(), scratch, &miss);
    3565          47 :     bailoutFrom(&miss, lir->snapshot());
    3566          47 : }
    3567             : 
    3568             : void
    3569          21 : CodeGenerator::visitTypeBarrierO(LTypeBarrierO* lir)
    3570             : {
    3571          21 :     Register obj = ToRegister(lir->object());
    3572          21 :     Register scratch = ToTempRegisterOrInvalid(lir->temp());
    3573          42 :     Label miss, ok;
    3574             : 
    3575          21 :     if (lir->mir()->type() == MIRType::ObjectOrNull) {
    3576           0 :         masm.comment("Object or Null");
    3577           0 :         Label* nullTarget = lir->mir()->resultTypeSet()->mightBeMIRType(MIRType::Null) ? &ok : &miss;
    3578           0 :         masm.branchTestPtr(Assembler::Zero, obj, obj, nullTarget);
    3579             :     } else {
    3580          21 :         MOZ_ASSERT(lir->mir()->type() == MIRType::Object);
    3581          21 :         MOZ_ASSERT(lir->mir()->barrierKind() != BarrierKind::TypeTagOnly);
    3582             :     }
    3583             : 
    3584          21 :     if (lir->mir()->barrierKind() != BarrierKind::TypeTagOnly) {
    3585          21 :         masm.comment("Type tag only");
    3586          21 :         masm.guardObjectType(obj, lir->mir()->resultTypeSet(), scratch, &miss);
    3587             :     }
    3588             : 
    3589          21 :     bailoutFrom(&miss, lir->snapshot());
    3590          21 :     masm.bind(&ok);
    3591          21 : }
    3592             : 
    3593             : void
    3594           0 : CodeGenerator::visitMonitorTypes(LMonitorTypes* lir)
    3595             : {
    3596           0 :     ValueOperand operand = ToValue(lir, LMonitorTypes::Input);
    3597           0 :     Register scratch = ToTempUnboxRegister(lir->temp());
    3598             : 
    3599           0 :     Label matched, miss;
    3600           0 :     masm.guardTypeSet(operand, lir->mir()->typeSet(), lir->mir()->barrierKind(), scratch, &miss);
    3601           0 :     bailoutFrom(&miss, lir->snapshot());
    3602           0 : }
    3603             : 
    3604             : // Out-of-line path to update the store buffer.
    3605             : class OutOfLineCallPostWriteBarrier : public OutOfLineCodeBase<CodeGenerator>
    3606             : {
    3607             :     LInstruction* lir_;
    3608             :     const LAllocation* object_;
    3609             : 
    3610             :   public:
    3611           2 :     OutOfLineCallPostWriteBarrier(LInstruction* lir, const LAllocation* object)
    3612           2 :       : lir_(lir), object_(object)
    3613           2 :     { }
    3614             : 
    3615           2 :     void accept(CodeGenerator* codegen) {
    3616           2 :         codegen->visitOutOfLineCallPostWriteBarrier(this);
    3617           2 :     }
    3618             : 
    3619           4 :     LInstruction* lir() const {
    3620           4 :         return lir_;
    3621             :     }
    3622           2 :     const LAllocation* object() const {
    3623           2 :         return object_;
    3624             :     }
    3625             : };
    3626             : 
    3627             : static void
    3628           0 : EmitStoreBufferCheckForConstant(MacroAssembler& masm, JSObject* object,
    3629             :                                 AllocatableGeneralRegisterSet& regs, Label* exit, Label* callVM)
    3630             : {
    3631           0 :     Register temp = regs.takeAny();
    3632             : 
    3633           0 :     const gc::TenuredCell* cell = &object->asTenured();
    3634           0 :     gc::Arena* arena = cell->arena();
    3635             : 
    3636           0 :     Register cells = temp;
    3637           0 :     masm.loadPtr(AbsoluteAddress(&arena->bufferedCells()), cells);
    3638             : 
    3639           0 :     size_t index = gc::ArenaCellSet::getCellIndex(cell);
    3640             :     size_t word;
    3641             :     uint32_t mask;
    3642           0 :     gc::ArenaCellSet::getWordIndexAndMask(index, &word, &mask);
    3643           0 :     size_t offset = gc::ArenaCellSet::offsetOfBits() + word * sizeof(uint32_t);
    3644             : 
    3645           0 :     masm.branchTest32(Assembler::NonZero, Address(cells, offset), Imm32(mask), exit);
    3646             : 
    3647             :     // Check whether this is the sentinel set and if so call the VM to allocate
    3648             :     // one for this arena.
    3649           0 :     masm.branchPtr(Assembler::Equal, Address(cells, gc::ArenaCellSet::offsetOfArena()),
    3650           0 :                    ImmPtr(nullptr), callVM);
    3651             : 
    3652             :     // Add the cell to the set.
    3653           0 :     masm.or32(Imm32(mask), Address(cells, offset));
    3654           0 :     masm.jump(exit);
    3655             : 
    3656           0 :     regs.add(temp);
    3657           0 : }
    3658             : 
    3659             : static void
    3660           2 : EmitPostWriteBarrier(MacroAssembler& masm, Register objreg, JSObject* maybeConstant, bool isGlobal,
    3661             :                      AllocatableGeneralRegisterSet& regs)
    3662             : {
    3663           2 :     MOZ_ASSERT_IF(isGlobal, maybeConstant);
    3664             : 
    3665           4 :     Label callVM;
    3666           4 :     Label exit;
    3667             : 
    3668             :     // We already have a fast path to check whether a global is in the store
    3669             :     // buffer.
    3670           2 :     if (!isGlobal && maybeConstant)
    3671           0 :         EmitStoreBufferCheckForConstant(masm, maybeConstant, regs, &exit, &callVM);
    3672             : 
    3673             :     // Call into the VM to barrier the write.
    3674           2 :     masm.bind(&callVM);
    3675             : 
    3676           2 :     Register runtimereg = regs.takeAny();
    3677           2 :     masm.mov(ImmPtr(GetJitContext()->runtime), runtimereg);
    3678             : 
    3679           2 :     void (*fun)(JSRuntime*, JSObject*) = isGlobal ? PostGlobalWriteBarrier : PostWriteBarrier;
    3680           2 :     masm.setupUnalignedABICall(regs.takeAny());
    3681           2 :     masm.passABIArg(runtimereg);
    3682           2 :     masm.passABIArg(objreg);
    3683           2 :     masm.callWithABI(JS_FUNC_TO_DATA_PTR(void*, fun));
    3684             : 
    3685           2 :     masm.bind(&exit);
    3686           2 : }
    3687             : 
    3688             : void
    3689           2 : CodeGenerator::emitPostWriteBarrier(const LAllocation* obj)
    3690             : {
    3691           2 :     AllocatableGeneralRegisterSet regs(GeneralRegisterSet::Volatile());
    3692             : 
    3693           2 :     Register objreg;
    3694           2 :     JSObject* object = nullptr;
    3695           2 :     bool isGlobal = false;
    3696           2 :     if (obj->isConstant()) {
    3697           0 :         object = &obj->toConstant()->toObject();
    3698           0 :         isGlobal = isGlobalObject(object);
    3699           0 :         objreg = regs.takeAny();
    3700           0 :         masm.movePtr(ImmGCPtr(object), objreg);
    3701             :     } else {
    3702           2 :         objreg = ToRegister(obj);
    3703           2 :         regs.takeUnchecked(objreg);
    3704             :     }
    3705             : 
    3706           2 :     EmitPostWriteBarrier(masm, objreg, object, isGlobal, regs);
    3707           2 : }
    3708             : 
    3709             : void
    3710           0 : CodeGenerator::emitPostWriteBarrier(Register objreg)
    3711             : {
    3712           0 :     AllocatableGeneralRegisterSet regs(GeneralRegisterSet::Volatile());
    3713           0 :     regs.takeUnchecked(objreg);
    3714           0 :     EmitPostWriteBarrier(masm, objreg, nullptr, false, regs);
    3715           0 : }
    3716             : 
    3717             : void
    3718           2 : CodeGenerator::visitOutOfLineCallPostWriteBarrier(OutOfLineCallPostWriteBarrier* ool)
    3719             : {
    3720           2 :     saveLiveVolatile(ool->lir());
    3721           2 :     const LAllocation* obj = ool->object();
    3722           2 :     emitPostWriteBarrier(obj);
    3723           2 :     restoreLiveVolatile(ool->lir());
    3724             : 
    3725           2 :     masm.jump(ool->rejoin());
    3726           2 : }
    3727             : 
    3728             : void
    3729           2 : CodeGenerator::maybeEmitGlobalBarrierCheck(const LAllocation* maybeGlobal, OutOfLineCode* ool)
    3730             : {
    3731             :     // Check whether an object is a global that we have already barriered before
    3732             :     // calling into the VM.
    3733             : 
    3734           2 :     if (!maybeGlobal->isConstant())
    3735           4 :         return;
    3736             : 
    3737           0 :     JSObject* obj = &maybeGlobal->toConstant()->toObject();
    3738           0 :     if (!isGlobalObject(obj))
    3739           0 :         return;
    3740             : 
    3741           0 :     JSCompartment* comp = obj->compartment();
    3742           0 :     auto addr = AbsoluteAddress(&comp->globalWriteBarriered);
    3743           0 :     masm.branch32(Assembler::NotEqual, addr, Imm32(0), ool->rejoin());
    3744             : }
    3745             : 
    3746             : template <class LPostBarrierType>
    3747             : void
    3748           1 : CodeGenerator::visitPostWriteBarrierCommonO(LPostBarrierType* lir, OutOfLineCode* ool)
    3749             : {
    3750           1 :     addOutOfLineCode(ool, lir->mir());
    3751             : 
    3752           1 :     Register temp = ToTempRegisterOrInvalid(lir->temp());
    3753             : 
    3754           1 :     if (lir->object()->isConstant()) {
    3755             :         // Constant nursery objects cannot appear here, see LIRGenerator::visitPostWriteElementBarrier.
    3756           0 :         MOZ_ASSERT(!IsInsideNursery(&lir->object()->toConstant()->toObject()));
    3757             :     } else {
    3758           1 :         masm.branchPtrInNurseryChunk(Assembler::Equal, ToRegister(lir->object()), temp,
    3759             :                                      ool->rejoin());
    3760             :     }
    3761             : 
    3762           1 :     maybeEmitGlobalBarrierCheck(lir->object(), ool);
    3763             : 
    3764           1 :     Register valueObj = ToRegister(lir->value());
    3765           1 :     if (lir->mir()->value()->type() == MIRType::ObjectOrNull)
    3766           0 :         masm.branchTestPtr(Assembler::Zero, valueObj, valueObj, ool->rejoin());
    3767             :     else
    3768           1 :         MOZ_ASSERT(lir->mir()->value()->type() == MIRType::Object);
    3769           1 :     masm.branchPtrInNurseryChunk(Assembler::Equal, valueObj, temp, ool->entry());
    3770             : 
    3771           1 :     masm.bind(ool->rejoin());
    3772           1 : }
    3773             : 
    3774             : template <class LPostBarrierType>
    3775             : void
    3776           1 : CodeGenerator::visitPostWriteBarrierCommonV(LPostBarrierType* lir, OutOfLineCode* ool)
    3777             : {
    3778           1 :     addOutOfLineCode(ool, lir->mir());
    3779             : 
    3780           1 :     Register temp = ToTempRegisterOrInvalid(lir->temp());
    3781             : 
    3782           1 :     if (lir->object()->isConstant()) {
    3783             :         // Constant nursery objects cannot appear here, see LIRGenerator::visitPostWriteElementBarrier.
    3784           0 :         MOZ_ASSERT(!IsInsideNursery(&lir->object()->toConstant()->toObject()));
    3785             :     } else {
    3786           1 :         masm.branchPtrInNurseryChunk(Assembler::Equal, ToRegister(lir->object()), temp,
    3787             :                                      ool->rejoin());
    3788             :     }
    3789             : 
    3790           1 :     maybeEmitGlobalBarrierCheck(lir->object(), ool);
    3791             : 
    3792           1 :     ValueOperand value = ToValue(lir, LPostBarrierType::Input);
    3793           1 :     masm.branchValueIsNurseryObject(Assembler::Equal, value, temp, ool->entry());
    3794             : 
    3795           1 :     masm.bind(ool->rejoin());
    3796           1 : }
    3797             : 
    3798             : void
    3799           1 : CodeGenerator::visitPostWriteBarrierO(LPostWriteBarrierO* lir)
    3800             : {
    3801           1 :     auto ool = new(alloc()) OutOfLineCallPostWriteBarrier(lir, lir->object());
    3802           1 :     visitPostWriteBarrierCommonO(lir, ool);
    3803           1 : }
    3804             : 
    3805             : void
    3806           1 : CodeGenerator::visitPostWriteBarrierV(LPostWriteBarrierV* lir)
    3807             : {
    3808           1 :     auto ool = new(alloc()) OutOfLineCallPostWriteBarrier(lir, lir->object());
    3809           1 :     visitPostWriteBarrierCommonV(lir, ool);
    3810           1 : }
    3811             : 
    3812             : // Out-of-line path to update the store buffer.
    3813             : class OutOfLineCallPostWriteElementBarrier : public OutOfLineCodeBase<CodeGenerator>
    3814             : {
    3815             :     LInstruction* lir_;
    3816             :     const LAllocation* object_;
    3817             :     const LAllocation* index_;
    3818             : 
    3819             :   public:
    3820           0 :     OutOfLineCallPostWriteElementBarrier(LInstruction* lir, const LAllocation* object,
    3821             :                                          const LAllocation* index)
    3822           0 :       : lir_(lir),
    3823             :         object_(object),
    3824           0 :         index_(index)
    3825           0 :     { }
    3826             : 
    3827           0 :     void accept(CodeGenerator* codegen) {
    3828           0 :         codegen->visitOutOfLineCallPostWriteElementBarrier(this);
    3829           0 :     }
    3830             : 
    3831           0 :     LInstruction* lir() const {
    3832           0 :         return lir_;
    3833             :     }
    3834             : 
    3835           0 :     const LAllocation* object() const {
    3836           0 :         return object_;
    3837             :     }
    3838             : 
    3839           0 :     const LAllocation* index() const {
    3840           0 :         return index_;
    3841             :     }
    3842             : };
    3843             : 
    3844             : void
    3845           0 : CodeGenerator::visitOutOfLineCallPostWriteElementBarrier(OutOfLineCallPostWriteElementBarrier* ool)
    3846             : {
    3847           0 :     saveLiveVolatile(ool->lir());
    3848             : 
    3849           0 :     const LAllocation* obj = ool->object();
    3850           0 :     const LAllocation* index = ool->index();
    3851             : 
    3852           0 :     Register objreg = obj->isConstant() ? InvalidReg : ToRegister(obj);
    3853           0 :     Register indexreg = ToRegister(index);
    3854             : 
    3855           0 :     AllocatableGeneralRegisterSet regs(GeneralRegisterSet::Volatile());
    3856           0 :     regs.takeUnchecked(indexreg);
    3857             : 
    3858           0 :     if (obj->isConstant()) {
    3859           0 :         objreg = regs.takeAny();
    3860           0 :         masm.movePtr(ImmGCPtr(&obj->toConstant()->toObject()), objreg);
    3861             :     } else {
    3862           0 :         regs.takeUnchecked(objreg);
    3863             :     }
    3864             : 
    3865           0 :     Register runtimereg = regs.takeAny();
    3866           0 :     masm.setupUnalignedABICall(runtimereg);
    3867           0 :     masm.mov(ImmPtr(GetJitContext()->runtime), runtimereg);
    3868           0 :     masm.passABIArg(runtimereg);
    3869           0 :     masm.passABIArg(objreg);
    3870           0 :     masm.passABIArg(indexreg);
    3871           0 :     masm.callWithABI(JS_FUNC_TO_DATA_PTR(void*, (PostWriteElementBarrier<IndexInBounds::Maybe>)));
    3872             : 
    3873           0 :     restoreLiveVolatile(ool->lir());
    3874             : 
    3875           0 :     masm.jump(ool->rejoin());
    3876           0 : }
    3877             : 
    3878             : void
    3879           0 : CodeGenerator::visitPostWriteElementBarrierO(LPostWriteElementBarrierO* lir)
    3880             : {
    3881           0 :     auto ool = new(alloc()) OutOfLineCallPostWriteElementBarrier(lir, lir->object(), lir->index());
    3882           0 :     visitPostWriteBarrierCommonO(lir, ool);
    3883           0 : }
    3884             : 
    3885             : void
    3886           0 : CodeGenerator::visitPostWriteElementBarrierV(LPostWriteElementBarrierV* lir)
    3887             : {
    3888           0 :     auto ool = new(alloc()) OutOfLineCallPostWriteElementBarrier(lir, lir->object(), lir->index());
    3889           0 :     visitPostWriteBarrierCommonV(lir, ool);
    3890           0 : }
    3891             : 
    3892             : void
    3893           9 : CodeGenerator::visitCallNative(LCallNative* call)
    3894             : {
    3895           9 :     WrappedFunction* target = call->getSingleTarget();
    3896           9 :     MOZ_ASSERT(target);
    3897           9 :     MOZ_ASSERT(target->isNative());
    3898             : 
    3899           9 :     int callargslot = call->argslot();
    3900           9 :     int unusedStack = StackOffsetOfPassedArg(callargslot);
    3901             : 
    3902             :     // Registers used for callWithABI() argument-passing.
    3903           9 :     const Register argContextReg   = ToRegister(call->getArgContextReg());
    3904           9 :     const Register argUintNReg     = ToRegister(call->getArgUintNReg());
    3905           9 :     const Register argVpReg        = ToRegister(call->getArgVpReg());
    3906             : 
    3907             :     // Misc. temporary registers.
    3908           9 :     const Register tempReg = ToRegister(call->getTempReg());
    3909             : 
    3910          18 :     DebugOnly<uint32_t> initialStack = masm.framePushed();
    3911             : 
    3912           9 :     masm.checkStackAlignment();
    3913             : 
    3914             :     // Native functions have the signature:
    3915             :     //  bool (*)(JSContext*, unsigned, Value* vp)
    3916             :     // Where vp[0] is space for an outparam, vp[1] is |this|, and vp[2] onward
    3917             :     // are the function arguments.
    3918             : 
    3919             :     // Allocate space for the outparam, moving the StackPointer to what will be &vp[1].
    3920           9 :     masm.adjustStack(unusedStack);
    3921             : 
    3922             :     // Push a Value containing the callee object: natives are allowed to access their callee before
    3923             :     // setitng the return value. The StackPointer is moved to &vp[0].
    3924           9 :     masm.Push(ObjectValue(*target->rawJSFunction()));
    3925             : 
    3926             :     // Preload arguments into registers.
    3927           9 :     masm.loadJSContext(argContextReg);
    3928           9 :     masm.move32(Imm32(call->numActualArgs()), argUintNReg);
    3929           9 :     masm.moveStackPtrTo(argVpReg);
    3930             : 
    3931           9 :     masm.Push(argUintNReg);
    3932             : 
    3933             :     // Construct native exit frame.
    3934           9 :     uint32_t safepointOffset = masm.buildFakeExitFrame(tempReg);
    3935           9 :     masm.enterFakeExitFrameForNative(argContextReg, tempReg, call->mir()->isConstructing());
    3936             : 
    3937           9 :     markSafepointAt(safepointOffset, call);
    3938             : 
    3939           9 :     emitTracelogStartEvent(TraceLogger_Call);
    3940             : 
    3941             :     // Construct and execute call.
    3942           9 :     masm.setupUnalignedABICall(tempReg);
    3943           9 :     masm.passABIArg(argContextReg);
    3944           9 :     masm.passABIArg(argUintNReg);
    3945           9 :     masm.passABIArg(argVpReg);
    3946           9 :     JSNative native = target->native();
    3947           9 :     if (call->ignoresReturnValue()) {
    3948           1 :         const JSJitInfo* jitInfo = target->jitInfo();
    3949           1 :         if (jitInfo && jitInfo->type() == JSJitInfo::IgnoresReturnValueNative)
    3950           0 :             native = jitInfo->ignoresReturnValueMethod;
    3951             :     }
    3952           9 :     masm.callWithABI(JS_FUNC_TO_DATA_PTR(void*, native));
    3953             : 
    3954           9 :     emitTracelogStopEvent(TraceLogger_Call);
    3955             : 
    3956             :     // Test for failure.
    3957           9 :     masm.branchIfFalseBool(ReturnReg, masm.failureLabel());
    3958             : 
    3959             :     // Load the outparam vp[0] into output register(s).
    3960           9 :     masm.loadValue(Address(masm.getStackPointer(), NativeExitFrameLayout::offsetOfResult()), JSReturnOperand);
    3961             : 
    3962             :     // The next instruction is removing the footer of the exit frame, so there
    3963             :     // is no need for leaveFakeExitFrame.
    3964             : 
    3965             :     // Move the StackPointer back to its original location, unwinding the native exit frame.
    3966           9 :     masm.adjustStack(NativeExitFrameLayout::Size() - unusedStack);
    3967           9 :     MOZ_ASSERT(masm.framePushed() == initialStack);
    3968           9 : }
    3969             : 
    3970             : static void
    3971           0 : LoadDOMPrivate(MacroAssembler& masm, Register obj, Register priv)
    3972             : {
    3973             :     // Load the value in DOM_OBJECT_SLOT for a native or proxy DOM object. This
    3974             :     // will be in the first slot but may be fixed or non-fixed.
    3975           0 :     MOZ_ASSERT(obj != priv);
    3976             : 
    3977             :     // Check shape->numFixedSlots != 0.
    3978           0 :     masm.loadPtr(Address(obj, ShapedObject::offsetOfShape()), priv);
    3979             : 
    3980           0 :     Label hasFixedSlots, done;
    3981           0 :     masm.branchTest32(Assembler::NonZero,
    3982           0 :                       Address(priv, Shape::offsetOfSlotInfo()),
    3983           0 :                       Imm32(Shape::fixedSlotsMask()),
    3984           0 :                       &hasFixedSlots);
    3985             : 
    3986           0 :     masm.loadPtr(Address(obj, NativeObject::offsetOfSlots()), priv);
    3987           0 :     masm.loadPrivate(Address(priv, 0), priv);
    3988             : 
    3989           0 :     masm.jump(&done);
    3990           0 :     masm.bind(&hasFixedSlots);
    3991             : 
    3992           0 :     masm.loadPrivate(Address(obj, NativeObject::getFixedSlotOffset(0)), priv);
    3993             : 
    3994           0 :     masm.bind(&done);
    3995           0 : }
    3996             : 
    3997             : void
    3998           0 : CodeGenerator::visitCallDOMNative(LCallDOMNative* call)
    3999             : {
    4000           0 :     WrappedFunction* target = call->getSingleTarget();
    4001           0 :     MOZ_ASSERT(target);
    4002           0 :     MOZ_ASSERT(target->isNative());
    4003           0 :     MOZ_ASSERT(target->jitInfo());
    4004           0 :     MOZ_ASSERT(call->mir()->isCallDOMNative());
    4005             : 
    4006           0 :     int callargslot = call->argslot();
    4007           0 :     int unusedStack = StackOffsetOfPassedArg(callargslot);
    4008             : 
    4009             :     // Registers used for callWithABI() argument-passing.
    4010           0 :     const Register argJSContext = ToRegister(call->getArgJSContext());
    4011           0 :     const Register argObj       = ToRegister(call->getArgObj());
    4012           0 :     const Register argPrivate   = ToRegister(call->getArgPrivate());
    4013           0 :     const Register argArgs      = ToRegister(call->getArgArgs());
    4014             : 
    4015           0 :     DebugOnly<uint32_t> initialStack = masm.framePushed();
    4016             : 
    4017           0 :     masm.checkStackAlignment();
    4018             : 
    4019             :     // DOM methods have the signature:
    4020             :     //  bool (*)(JSContext*, HandleObject, void* private, const JSJitMethodCallArgs& args)
    4021             :     // Where args is initialized from an argc and a vp, vp[0] is space for an
    4022             :     // outparam and the callee, vp[1] is |this|, and vp[2] onward are the
    4023             :     // function arguments.  Note that args stores the argv, not the vp, and
    4024             :     // argv == vp + 2.
    4025             : 
    4026             :     // Nestle the stack up against the pushed arguments, leaving StackPointer at
    4027             :     // &vp[1]
    4028           0 :     masm.adjustStack(unusedStack);
    4029             :     // argObj is filled with the extracted object, then returned.
    4030           0 :     Register obj = masm.extractObject(Address(masm.getStackPointer(), 0), argObj);
    4031           0 :     MOZ_ASSERT(obj == argObj);
    4032             : 
    4033             :     // Push a Value containing the callee object: natives are allowed to access their callee before
    4034             :     // setitng the return value. After this the StackPointer points to &vp[0].
    4035           0 :     masm.Push(ObjectValue(*target->rawJSFunction()));
    4036             : 
    4037             :     // Now compute the argv value.  Since StackPointer is pointing to &vp[0] and
    4038             :     // argv is &vp[2] we just need to add 2*sizeof(Value) to the current
    4039             :     // StackPointer.
    4040             :     JS_STATIC_ASSERT(JSJitMethodCallArgsTraits::offsetOfArgv == 0);
    4041             :     JS_STATIC_ASSERT(JSJitMethodCallArgsTraits::offsetOfArgc ==
    4042             :                      IonDOMMethodExitFrameLayoutTraits::offsetOfArgcFromArgv);
    4043           0 :     masm.computeEffectiveAddress(Address(masm.getStackPointer(), 2 * sizeof(Value)), argArgs);
    4044             : 
    4045           0 :     LoadDOMPrivate(masm, obj, argPrivate);
    4046             : 
    4047             :     // Push argc from the call instruction into what will become the IonExitFrame
    4048           0 :     masm.Push(Imm32(call->numActualArgs()));
    4049             : 
    4050             :     // Push our argv onto the stack
    4051           0 :     masm.Push(argArgs);
    4052             :     // And store our JSJitMethodCallArgs* in argArgs.
    4053           0 :     masm.moveStackPtrTo(argArgs);
    4054             : 
    4055             :     // Push |this| object for passing HandleObject. We push after argc to
    4056             :     // maintain the same sp-relative location of the object pointer with other
    4057             :     // DOMExitFrames.
    4058           0 :     masm.Push(argObj);
    4059           0 :     masm.moveStackPtrTo(argObj);
    4060             : 
    4061             :     // Construct native exit frame.
    4062           0 :     uint32_t safepointOffset = masm.buildFakeExitFrame(argJSContext);
    4063           0 :     masm.loadJSContext(argJSContext);
    4064           0 :     masm.enterFakeExitFrame(argJSContext, argJSContext, IonDOMMethodExitFrameLayoutToken);
    4065             : 
    4066           0 :     markSafepointAt(safepointOffset, call);
    4067             : 
    4068             :     // Construct and execute call.
    4069           0 :     masm.setupUnalignedABICall(argJSContext);
    4070           0 :     masm.loadJSContext(argJSContext);
    4071           0 :     masm.passABIArg(argJSContext);
    4072           0 :     masm.passABIArg(argObj);
    4073           0 :     masm.passABIArg(argPrivate);
    4074           0 :     masm.passABIArg(argArgs);
    4075           0 :     masm.callWithABI(JS_FUNC_TO_DATA_PTR(void*, target->jitInfo()->method));
    4076             : 
    4077           0 :     if (target->jitInfo()->isInfallible) {
    4078           0 :         masm.loadValue(Address(masm.getStackPointer(), IonDOMMethodExitFrameLayout::offsetOfResult()),
    4079           0 :                        JSReturnOperand);
    4080             :     } else {
    4081             :         // Test for failure.
    4082           0 :         masm.branchIfFalseBool(ReturnReg, masm.exceptionLabel());
    4083             : 
    4084             :         // Load the outparam vp[0] into output register(s).
    4085           0 :         masm.loadValue(Address(masm.getStackPointer(), IonDOMMethodExitFrameLayout::offsetOfResult()),
    4086           0 :                        JSReturnOperand);
    4087             :     }
    4088             : 
    4089             :     // The next instruction is removing the footer of the exit frame, so there
    4090             :     // is no need for leaveFakeExitFrame.
    4091             : 
    4092             :     // Move the StackPointer back to its original location, unwinding the native exit frame.
    4093           0 :     masm.adjustStack(IonDOMMethodExitFrameLayout::Size() - unusedStack);
    4094           0 :     MOZ_ASSERT(masm.framePushed() == initialStack);
    4095           0 : }
    4096             : 
    4097             : typedef bool (*GetIntrinsicValueFn)(JSContext* cx, HandlePropertyName, MutableHandleValue);
    4098           3 : static const VMFunction GetIntrinsicValueInfo =
    4099           6 :     FunctionInfo<GetIntrinsicValueFn>(GetIntrinsicValue, "GetIntrinsicValue");
    4100             : 
    4101             : void
    4102           1 : CodeGenerator::visitCallGetIntrinsicValue(LCallGetIntrinsicValue* lir)
    4103             : {
    4104           1 :     pushArg(ImmGCPtr(lir->mir()->name()));
    4105           1 :     callVM(GetIntrinsicValueInfo, lir);
    4106           1 : }
    4107             : 
    4108             : typedef bool (*InvokeFunctionFn)(JSContext*, HandleObject, bool, bool, uint32_t, Value*,
    4109             :                                  MutableHandleValue);
    4110           3 : static const VMFunction InvokeFunctionInfo =
    4111           6 :     FunctionInfo<InvokeFunctionFn>(InvokeFunction, "InvokeFunction");
    4112             : 
    4113             : void
    4114          18 : CodeGenerator::emitCallInvokeFunction(LInstruction* call, Register calleereg,
    4115             :                                       bool constructing, bool ignoresReturnValue,
    4116             :                                       uint32_t argc, uint32_t unusedStack)
    4117             : {
    4118             :     // Nestle %esp up to the argument vector.
    4119             :     // Each path must account for framePushed_ separately, for callVM to be valid.
    4120          18 :     masm.freeStack(unusedStack);
    4121             : 
    4122          18 :     pushArg(masm.getStackPointer()); // argv.
    4123          18 :     pushArg(Imm32(argc));            // argc.
    4124          18 :     pushArg(Imm32(ignoresReturnValue));
    4125          18 :     pushArg(Imm32(constructing));    // constructing.
    4126          18 :     pushArg(calleereg);              // JSFunction*.
    4127             : 
    4128          18 :     callVM(InvokeFunctionInfo, call);
    4129             : 
    4130             :     // Un-nestle %esp from the argument vector. No prefix was pushed.
    4131          18 :     masm.reserveStack(unusedStack);
    4132          18 : }
    4133             : 
    4134             : void
    4135           9 : CodeGenerator::visitCallGeneric(LCallGeneric* call)
    4136             : {
    4137           9 :     Register calleereg = ToRegister(call->getFunction());
    4138           9 :     Register objreg    = ToRegister(call->getTempObject());
    4139           9 :     Register nargsreg  = ToRegister(call->getNargsReg());
    4140           9 :     uint32_t unusedStack = StackOffsetOfPassedArg(call->argslot());
    4141          18 :     Label invoke, thunk, makeCall, end;
    4142             : 
    4143             :     // Known-target case is handled by LCallKnown.
    4144           9 :     MOZ_ASSERT(!call->hasSingleTarget());
    4145             : 
    4146             :     // Generate an ArgumentsRectifier.
    4147           9 :     JitCode* argumentsRectifier = gen->jitRuntime()->getArgumentsRectifier();
    4148             : 
    4149           9 :     masm.checkStackAlignment();
    4150             : 
    4151             :     // Guard that calleereg is actually a function object.
    4152           9 :     masm.loadObjClass(calleereg, nargsreg);
    4153           9 :     masm.branchPtr(Assembler::NotEqual, nargsreg, ImmPtr(&JSFunction::class_), &invoke);
    4154             : 
    4155             :     // Guard that calleereg is an interpreted function with a JSScript.
    4156             :     // If we are constructing, also ensure the callee is a constructor.
    4157           9 :     if (call->mir()->isConstructing()) {
    4158           4 :         masm.branchIfNotInterpretedConstructor(calleereg, nargsreg, &invoke);
    4159             :     } else {
    4160           5 :         masm.branchIfFunctionHasNoScript(calleereg, &invoke);
    4161           5 :         masm.branchFunctionKind(Assembler::Equal, JSFunction::ClassConstructor, calleereg, objreg, &invoke);
    4162             :     }
    4163             : 
    4164             :     // Knowing that calleereg is a non-native function, load the JSScript.
    4165           9 :     masm.loadPtr(Address(calleereg, JSFunction::offsetOfNativeOrScript()), objreg);
    4166             : 
    4167             :     // Load script jitcode.
    4168           9 :     masm.loadBaselineOrIonRaw(objreg, objreg, &invoke);
    4169             : 
    4170             :     // Nestle the StackPointer up to the argument vector.
    4171           9 :     masm.freeStack(unusedStack);
    4172             : 
    4173             :     // Construct the IonFramePrefix.
    4174           9 :     uint32_t descriptor = MakeFrameDescriptor(masm.framePushed(), JitFrame_IonJS,
    4175          18 :                                               JitFrameLayout::Size());
    4176           9 :     masm.Push(Imm32(call->numActualArgs()));
    4177           9 :     masm.PushCalleeToken(calleereg, call->mir()->isConstructing());
    4178           9 :     masm.Push(Imm32(descriptor));
    4179             : 
    4180             :     // Check whether the provided arguments satisfy target argc.
    4181             :     // We cannot have lowered to LCallGeneric with a known target. Assert that we didn't
    4182             :     // add any undefineds in IonBuilder. NB: MCall::numStackArgs includes |this|.
    4183          18 :     DebugOnly<unsigned> numNonArgsOnStack = 1 + call->isConstructing();
    4184           9 :     MOZ_ASSERT(call->numActualArgs() == call->mir()->numStackArgs() - numNonArgsOnStack);
    4185           9 :     masm.load16ZeroExtend(Address(calleereg, JSFunction::offsetOfNargs()), nargsreg);
    4186           9 :     masm.branch32(Assembler::Above, nargsreg, Imm32(call->numActualArgs()), &thunk);
    4187           9 :     masm.jump(&makeCall);
    4188             : 
    4189             :     // Argument fixed needed. Load the ArgumentsRectifier.
    4190           9 :     masm.bind(&thunk);
    4191             :     {
    4192           9 :         MOZ_ASSERT(ArgumentsRectifierReg != objreg);
    4193           9 :         masm.movePtr(ImmGCPtr(argumentsRectifier), objreg); // Necessary for GC marking.
    4194           9 :         masm.loadPtr(Address(objreg, JitCode::offsetOfCode()), objreg);
    4195           9 :         masm.move32(Imm32(call->numActualArgs()), ArgumentsRectifierReg);
    4196             :     }
    4197             : 
    4198             :     // Finally call the function in objreg.
    4199           9 :     masm.bind(&makeCall);
    4200           9 :     uint32_t callOffset = masm.callJit(objreg);
    4201           9 :     markSafepointAt(callOffset, call);
    4202             : 
    4203             :     // Increment to remove IonFramePrefix; decrement to fill FrameSizeClass.
    4204             :     // The return address has already been removed from the Ion frame.
    4205           9 :     int prefixGarbage = sizeof(JitFrameLayout) - sizeof(void*);
    4206           9 :     masm.adjustStack(prefixGarbage - unusedStack);
    4207           9 :     masm.jump(&end);
    4208             : 
    4209             :     // Handle uncompiled or native functions.
    4210           9 :     masm.bind(&invoke);
    4211           9 :     emitCallInvokeFunction(call, calleereg, call->isConstructing(), call->ignoresReturnValue(),
    4212           9 :                            call->numActualArgs(), unusedStack);
    4213             : 
    4214           9 :     masm.bind(&end);
    4215             : 
    4216             :     // If the return value of the constructing function is Primitive,
    4217             :     // replace the return value with the Object from CreateThis.
    4218           9 :     if (call->mir()->isConstructing()) {
    4219           8 :         Label notPrimitive;
    4220           4 :         masm.branchTestPrimitive(Assembler::NotEqual, JSReturnOperand, &notPrimitive);
    4221           4 :         masm.loadValue(Address(masm.getStackPointer(), unusedStack), JSReturnOperand);
    4222           4 :         masm.bind(&notPrimitive);
    4223             :     }
    4224           9 : }
    4225             : 
    4226             : typedef bool (*InvokeFunctionShuffleFn)(JSContext*, HandleObject, uint32_t, uint32_t, Value*,
    4227             :                                         MutableHandleValue);
    4228           3 : static const VMFunction InvokeFunctionShuffleInfo =
    4229           6 :     FunctionInfo<InvokeFunctionShuffleFn>(InvokeFunctionShuffleNewTarget,
    4230             :                                           "InvokeFunctionShuffleNewTarget");
    4231             : void
    4232           0 : CodeGenerator::emitCallInvokeFunctionShuffleNewTarget(LCallKnown* call, Register calleeReg,
    4233             :                                                       uint32_t numFormals, uint32_t unusedStack)
    4234             : {
    4235           0 :     masm.freeStack(unusedStack);
    4236             : 
    4237           0 :     pushArg(masm.getStackPointer());
    4238           0 :     pushArg(Imm32(numFormals));
    4239           0 :     pushArg(Imm32(call->numActualArgs()));
    4240           0 :     pushArg(calleeReg);
    4241             : 
    4242           0 :     callVM(InvokeFunctionShuffleInfo, call);
    4243             : 
    4244           0 :     masm.reserveStack(unusedStack);
    4245           0 : }
    4246             : 
    4247             : void
    4248           9 : CodeGenerator::visitCallKnown(LCallKnown* call)
    4249             : {
    4250           9 :     Register calleereg = ToRegister(call->getFunction());
    4251           9 :     Register objreg    = ToRegister(call->getTempObject());
    4252           9 :     uint32_t unusedStack = StackOffsetOfPassedArg(call->argslot());
    4253           9 :     WrappedFunction* target = call->getSingleTarget();
    4254          18 :     Label end, uncompiled;
    4255             : 
    4256             :     // Native single targets are handled by LCallNative.
    4257           9 :     MOZ_ASSERT(!target->isNative());
    4258             :     // Missing arguments must have been explicitly appended by the IonBuilder.
    4259          18 :     DebugOnly<unsigned> numNonArgsOnStack = 1 + call->isConstructing();
    4260           9 :     MOZ_ASSERT(target->nargs() <= call->mir()->numStackArgs() - numNonArgsOnStack);
    4261             : 
    4262           9 :     MOZ_ASSERT_IF(call->isConstructing(), target->isConstructor());
    4263             : 
    4264           9 :     masm.checkStackAlignment();
    4265             : 
    4266           9 :     if (target->isClassConstructor() && !call->isConstructing()) {
    4267           0 :         emitCallInvokeFunction(call, calleereg, call->isConstructing(), call->ignoresReturnValue(),
    4268           0 :                                call->numActualArgs(), unusedStack);
    4269           0 :         return;
    4270             :     }
    4271             : 
    4272           9 :     MOZ_ASSERT_IF(target->isClassConstructor(), call->isConstructing());
    4273             : 
    4274             :     // The calleereg is known to be a non-native function, but might point to
    4275             :     // a LazyScript instead of a JSScript.
    4276           9 :     masm.branchIfFunctionHasNoScript(calleereg, &uncompiled);
    4277             : 
    4278             :     // Knowing that calleereg is a non-native function, load the JSScript.
    4279           9 :     masm.loadPtr(Address(calleereg, JSFunction::offsetOfNativeOrScript()), objreg);
    4280             : 
    4281             :     // Load script jitcode.
    4282           9 :     if (call->mir()->needsArgCheck())
    4283           2 :         masm.loadBaselineOrIonRaw(objreg, objreg, &uncompiled);
    4284             :     else
    4285           7 :         masm.loadBaselineOrIonNoArgCheck(objreg, objreg, &uncompiled);
    4286             : 
    4287             :     // Nestle the StackPointer up to the argument vector.
    4288           9 :     masm.freeStack(unusedStack);
    4289             : 
    4290             :     // Construct the IonFramePrefix.
    4291           9 :     uint32_t descriptor = MakeFrameDescriptor(masm.framePushed(), JitFrame_IonJS,
    4292          18 :                                               JitFrameLayout::Size());
    4293           9 :     masm.Push(Imm32(call->numActualArgs()));
    4294           9 :     masm.PushCalleeToken(calleereg, call->mir()->isConstructing());
    4295           9 :     masm.Push(Imm32(descriptor));
    4296             : 
    4297             :     // Finally call the function in objreg.
    4298           9 :     uint32_t callOffset = masm.callJit(objreg);
    4299           9 :     markSafepointAt(callOffset, call);
    4300             : 
    4301             :     // Increment to remove IonFramePrefix; decrement to fill FrameSizeClass.
    4302             :     // The return address has already been removed from the Ion frame.
    4303           9 :     int prefixGarbage = sizeof(JitFrameLayout) - sizeof(void*);
    4304           9 :     masm.adjustStack(prefixGarbage - unusedStack);
    4305           9 :     masm.jump(&end);
    4306             : 
    4307             :     // Handle uncompiled functions.
    4308           9 :     masm.bind(&uncompiled);
    4309           9 :     if (call->isConstructing() && target->nargs() > call->numActualArgs())
    4310           0 :         emitCallInvokeFunctionShuffleNewTarget(call, calleereg, target->nargs(), unusedStack);
    4311             :     else
    4312           9 :         emitCallInvokeFunction(call, calleereg, call->isConstructing(), call->ignoresReturnValue(),
    4313           9 :                                call->numActualArgs(), unusedStack);
    4314             : 
    4315           9 :     masm.bind(&end);
    4316             : 
    4317             :     // If the return value of the constructing function is Primitive,
    4318             :     // replace the return value with the Object from CreateThis.
    4319           9 :     if (call->mir()->isConstructing()) {
    4320           0 :         Label notPrimitive;
    4321           0 :         masm.branchTestPrimitive(Assembler::NotEqual, JSReturnOperand, &notPrimitive);
    4322           0 :         masm.loadValue(Address(masm.getStackPointer(), unusedStack), JSReturnOperand);
    4323           0 :         masm.bind(&notPrimitive);
    4324             :     }
    4325             : }
    4326             : 
    4327             : template<typename T>
    4328             : void
    4329           0 : CodeGenerator::emitCallInvokeFunction(T* apply, Register extraStackSize)
    4330             : {
    4331           0 :     Register objreg = ToRegister(apply->getTempObject());
    4332           0 :     MOZ_ASSERT(objreg != extraStackSize);
    4333             : 
    4334             :     // Push the space used by the arguments.
    4335           0 :     masm.moveStackPtrTo(objreg);
    4336           0 :     masm.Push(extraStackSize);
    4337             : 
    4338           0 :     pushArg(objreg);                           // argv.
    4339           0 :     pushArg(ToRegister(apply->getArgc()));     // argc.
    4340           0 :     pushArg(Imm32(false));                     // ignoresReturnValue.
    4341           0 :     pushArg(Imm32(false));                     // isConstrucing.
    4342           0 :     pushArg(ToRegister(apply->getFunction())); // JSFunction*.
    4343             : 
    4344             :     // This specialization og callVM restore the extraStackSize after the call.
    4345           0 :     callVM(InvokeFunctionInfo, apply, &extraStackSize);
    4346             : 
    4347           0 :     masm.Pop(extraStackSize);
    4348           0 : }
    4349             : 
    4350             : // Do not bailout after the execution of this function since the stack no longer
    4351             : // correspond to what is expected by the snapshots.
    4352             : void
    4353           0 : CodeGenerator::emitAllocateSpaceForApply(Register argcreg, Register extraStackSpace, Label* end)
    4354             : {
    4355             :     // Initialize the loop counter AND Compute the stack usage (if == 0)
    4356           0 :     masm.movePtr(argcreg, extraStackSpace);
    4357             : 
    4358             :     // Align the JitFrameLayout on the JitStackAlignment.
    4359             :     if (JitStackValueAlignment > 1) {
    4360           0 :         MOZ_ASSERT(frameSize() % JitStackAlignment == 0,
    4361             :             "Stack padding assumes that the frameSize is correct");
    4362             :         MOZ_ASSERT(JitStackValueAlignment == 2);
    4363           0 :         Label noPaddingNeeded;
    4364             :         // if the number of arguments is odd, then we do not need any padding.
    4365           0 :         masm.branchTestPtr(Assembler::NonZero, argcreg, Imm32(1), &noPaddingNeeded);
    4366           0 :         masm.addPtr(Imm32(1), extraStackSpace);
    4367           0 :         masm.bind(&noPaddingNeeded);
    4368             :     }
    4369             : 
    4370             :     // Reserve space for copying the arguments.
    4371           0 :     NativeObject::elementsSizeMustNotOverflow();
    4372           0 :     masm.lshiftPtr(Imm32(ValueShift), extraStackSpace);
    4373           0 :     masm.subFromStackPtr(extraStackSpace);
    4374             : 
    4375             : #ifdef DEBUG
    4376             :     // Put a magic value in the space reserved for padding. Note, this code
    4377             :     // cannot be merged with the previous test, as not all architectures can
    4378             :     // write below their stack pointers.
    4379             :     if (JitStackValueAlignment > 1) {
    4380             :         MOZ_ASSERT(JitStackValueAlignment == 2);
    4381           0 :         Label noPaddingNeeded;
    4382             :         // if the number of arguments is odd, then we do not need any padding.
    4383           0 :         masm.branchTestPtr(Assembler::NonZero, argcreg, Imm32(1), &noPaddingNeeded);
    4384           0 :         BaseValueIndex dstPtr(masm.getStackPointer(), argcreg);
    4385           0 :         masm.storeValue(MagicValue(JS_ARG_POISON), dstPtr);
    4386           0 :         masm.bind(&noPaddingNeeded);
    4387             :     }
    4388             : #endif
    4389             : 
    4390             :     // Skip the copy of arguments if there are none.
    4391           0 :     masm.branchTestPtr(Assembler::Zero, argcreg, argcreg, end);
    4392           0 : }
    4393             : 
    4394             : // Destroys argvIndex and copyreg.
    4395             : void
    4396           0 : CodeGenerator::emitCopyValuesForApply(Register argvSrcBase, Register argvIndex, Register copyreg,
    4397             :                                       size_t argvSrcOffset, size_t argvDstOffset)
    4398             : {
    4399           0 :     Label loop;
    4400           0 :     masm.bind(&loop);
    4401             : 
    4402             :     // As argvIndex is off by 1, and we use the decBranchPtr instruction
    4403             :     // to loop back, we have to substract the size of the word which are
    4404             :     // copied.
    4405           0 :     BaseValueIndex srcPtr(argvSrcBase, argvIndex, argvSrcOffset - sizeof(void*));
    4406           0 :     BaseValueIndex dstPtr(masm.getStackPointer(), argvIndex, argvDstOffset - sizeof(void*));
    4407           0 :     masm.loadPtr(srcPtr, copyreg);
    4408           0 :     masm.storePtr(copyreg, dstPtr);
    4409             : 
    4410             :     // Handle 32 bits architectures.
    4411             :     if (sizeof(Value) == 2 * sizeof(void*)) {
    4412             :         BaseValueIndex srcPtrLow(argvSrcBase, argvIndex, argvSrcOffset - 2 * sizeof(void*));
    4413             :         BaseValueIndex dstPtrLow(masm.getStackPointer(), argvIndex, argvDstOffset - 2 * sizeof(void*));
    4414             :         masm.loadPtr(srcPtrLow, copyreg);
    4415             :         masm.storePtr(copyreg, dstPtrLow);
    4416             :     }
    4417             : 
    4418           0 :     masm.decBranchPtr(Assembler::NonZero, argvIndex, Imm32(1), &loop);
    4419           0 : }
    4420             : 
    4421             : void
    4422           0 : CodeGenerator::emitPopArguments(Register extraStackSpace)
    4423             : {
    4424             :     // Pop |this| and Arguments.
    4425           0 :     masm.freeStack(extraStackSpace);
    4426           0 : }
    4427             : 
    4428             : void
    4429           0 : CodeGenerator::emitPushArguments(LApplyArgsGeneric* apply, Register extraStackSpace)
    4430             : {
    4431             :     // Holds the function nargs. Initially the number of args to the caller.
    4432           0 :     Register argcreg = ToRegister(apply->getArgc());
    4433           0 :     Register copyreg = ToRegister(apply->getTempObject());
    4434             : 
    4435           0 :     Label end;
    4436           0 :     emitAllocateSpaceForApply(argcreg, extraStackSpace, &end);
    4437             : 
    4438             :     // We are making a copy of the arguments which are above the JitFrameLayout
    4439             :     // of the current Ion frame.
    4440             :     //
    4441             :     // [arg1] [arg0] <- src [this] [JitFrameLayout] [.. frameSize ..] [pad] [arg1] [arg0] <- dst
    4442             : 
    4443             :     // Compute the source and destination offsets into the stack.
    4444           0 :     size_t argvSrcOffset = frameSize() + JitFrameLayout::offsetOfActualArgs();
    4445           0 :     size_t argvDstOffset = 0;
    4446             : 
    4447             :     // Save the extra stack space, and re-use the register as a base.
    4448           0 :     masm.push(extraStackSpace);
    4449           0 :     Register argvSrcBase = extraStackSpace;
    4450           0 :     argvSrcOffset += sizeof(void*);
    4451           0 :     argvDstOffset += sizeof(void*);
    4452             : 
    4453             :     // Save the actual number of register, and re-use the register as an index register.
    4454           0 :     masm.push(argcreg);
    4455           0 :     Register argvIndex = argcreg;
    4456           0 :     argvSrcOffset += sizeof(void*);
    4457           0 :     argvDstOffset += sizeof(void*);
    4458             : 
    4459             :     // srcPtr = (StackPointer + extraStackSpace) + argvSrcOffset
    4460             :     // dstPtr = (StackPointer                  ) + argvDstOffset
    4461           0 :     masm.addStackPtrTo(argvSrcBase);
    4462             : 
    4463             :     // Copy arguments.
    4464           0 :     emitCopyValuesForApply(argvSrcBase, argvIndex, copyreg, argvSrcOffset, argvDstOffset);
    4465             : 
    4466             :     // Restore argcreg and the extra stack space counter.
    4467           0 :     masm.pop(argcreg);
    4468           0 :     masm.pop(extraStackSpace);
    4469             : 
    4470             :     // Join with all arguments copied and the extra stack usage computed.
    4471           0 :     masm.bind(&end);
    4472             : 
    4473             :     // Push |this|.
    4474           0 :     masm.addPtr(Imm32(sizeof(Value)), extraStackSpace);
    4475           0 :     masm.pushValue(ToValue(apply, LApplyArgsGeneric::ThisIndex));
    4476           0 : }
    4477             : 
    4478             : void
    4479           0 : CodeGenerator::emitPushArguments(LApplyArrayGeneric* apply, Register extraStackSpace)
    4480             : {
    4481           0 :     Label noCopy, epilogue;
    4482           0 :     Register tmpArgc = ToRegister(apply->getTempObject());
    4483           0 :     Register elementsAndArgc = ToRegister(apply->getElements());
    4484             : 
    4485             :     // Invariants guarded in the caller:
    4486             :     //  - the array is not too long
    4487             :     //  - the array length equals its initialized length
    4488             : 
    4489             :     // The array length is our argc for the purposes of allocating space.
    4490           0 :     Address length(ToRegister(apply->getElements()), ObjectElements::offsetOfLength());
    4491           0 :     masm.load32(length, tmpArgc);
    4492             : 
    4493             :     // Allocate space for the values.
    4494           0 :     emitAllocateSpaceForApply(tmpArgc, extraStackSpace, &noCopy);
    4495             : 
    4496             :     // Copy the values.  This code is skipped entirely if there are
    4497             :     // no values.
    4498           0 :     size_t argvDstOffset = 0;
    4499             : 
    4500           0 :     Register argvSrcBase = elementsAndArgc; // Elements value
    4501             : 
    4502           0 :     masm.push(extraStackSpace);
    4503           0 :     Register copyreg = extraStackSpace;
    4504           0 :     argvDstOffset += sizeof(void*);
    4505             : 
    4506           0 :     masm.push(tmpArgc);
    4507           0 :     Register argvIndex = tmpArgc;
    4508           0 :     argvDstOffset += sizeof(void*);
    4509             : 
    4510             :     // Copy
    4511           0 :     emitCopyValuesForApply(argvSrcBase, argvIndex, copyreg, 0, argvDstOffset);
    4512             : 
    4513             :     // Restore.
    4514           0 :     masm.pop(elementsAndArgc);
    4515           0 :     masm.pop(extraStackSpace);
    4516           0 :     masm.jump(&epilogue);
    4517             : 
    4518             :     // Clear argc if we skipped the copy step.
    4519           0 :     masm.bind(&noCopy);
    4520           0 :     masm.movePtr(ImmPtr(0), elementsAndArgc);
    4521             : 
    4522             :     // Join with all arguments copied and the extra stack usage computed.
    4523             :     // Note, "elements" has become "argc".
    4524           0 :     masm.bind(&epilogue);
    4525             : 
    4526             :     // Push |this|.
    4527           0 :     masm.addPtr(Imm32(sizeof(Value)), extraStackSpace);
    4528           0 :     masm.pushValue(ToValue(apply, LApplyArgsGeneric::ThisIndex));
    4529           0 : }
    4530             : 
    4531             : template<typename T>
    4532             : void
    4533           0 : CodeGenerator::emitApplyGeneric(T* apply)
    4534             : {
    4535             :     // Holds the function object.
    4536           0 :     Register calleereg = ToRegister(apply->getFunction());
    4537             : 
    4538             :     // Temporary register for modifying the function object.
    4539           0 :     Register objreg = ToRegister(apply->getTempObject());
    4540           0 :     Register extraStackSpace = ToRegister(apply->getTempStackCounter());
    4541             : 
    4542             :     // Holds the function nargs, computed in the invoker or (for
    4543             :     // ApplyArray) in the argument pusher.
    4544           0 :     Register argcreg = ToRegister(apply->getArgc());
    4545             : 
    4546             :     // Unless already known, guard that calleereg is actually a function object.
    4547           0 :     if (!apply->hasSingleTarget()) {
    4548           0 :         masm.loadObjClass(calleereg, objreg);
    4549             : 
    4550           0 :         ImmPtr ptr = ImmPtr(&JSFunction::class_);
    4551           0 :         bailoutCmpPtr(Assembler::NotEqual, objreg, ptr, apply->snapshot());
    4552             :     }
    4553             : 
    4554             :     // Copy the arguments of the current function.
    4555             :     //
    4556             :     // In the case of ApplyArray, also compute argc: the argc register
    4557             :     // and the elements register are the same; argc must not be
    4558             :     // referenced before the call to emitPushArguments() and elements
    4559             :     // must not be referenced after it returns.
    4560             :     //
    4561             :     // objreg is dead across this call.
    4562             :     //
    4563             :     // extraStackSpace is garbage on entry and defined on exit.
    4564           0 :     emitPushArguments(apply, extraStackSpace);
    4565             : 
    4566           0 :     masm.checkStackAlignment();
    4567             : 
    4568             :     // If the function is native, only emit the call to InvokeFunction.
    4569           0 :     if (apply->hasSingleTarget() && apply->getSingleTarget()->isNative()) {
    4570           0 :         emitCallInvokeFunction(apply, extraStackSpace);
    4571           0 :         emitPopArguments(extraStackSpace);
    4572           0 :         return;
    4573             :     }
    4574             : 
    4575           0 :     Label end, invoke;
    4576             : 
    4577             :     // Guard that calleereg is an interpreted function with a JSScript.
    4578           0 :     masm.branchIfFunctionHasNoScript(calleereg, &invoke);
    4579             : 
    4580             :     // Guard that calleereg is not a class constrcuctor
    4581           0 :     masm.branchFunctionKind(Assembler::Equal, JSFunction::ClassConstructor,
    4582             :                             calleereg, objreg, &invoke);
    4583             : 
    4584             :     // Knowing that calleereg is a non-native function, load the JSScript.
    4585           0 :     masm.loadPtr(Address(calleereg, JSFunction::offsetOfNativeOrScript()), objreg);
    4586             : 
    4587             :     // Load script jitcode.
    4588           0 :     masm.loadBaselineOrIonRaw(objreg, objreg, &invoke);
    4589             : 
    4590             :     // Call with an Ion frame or a rectifier frame.
    4591             :     {
    4592             :         // Create the frame descriptor.
    4593           0 :         unsigned pushed = masm.framePushed();
    4594           0 :         Register stackSpace = extraStackSpace;
    4595           0 :         masm.addPtr(Imm32(pushed), stackSpace);
    4596           0 :         masm.makeFrameDescriptor(stackSpace, JitFrame_IonJS, JitFrameLayout::Size());
    4597             : 
    4598           0 :         masm.Push(argcreg);
    4599           0 :         masm.Push(calleereg);
    4600           0 :         masm.Push(stackSpace); // descriptor
    4601             : 
    4602           0 :         Label underflow, rejoin;
    4603             : 
    4604             :         // Check whether the provided arguments satisfy target argc.
    4605           0 :         if (!apply->hasSingleTarget()) {
    4606           0 :             Register nformals = extraStackSpace;
    4607           0 :             masm.load16ZeroExtend(Address(calleereg, JSFunction::offsetOfNargs()), nformals);
    4608           0 :             masm.branch32(Assembler::Below, argcreg, nformals, &underflow);
    4609             :         } else {
    4610           0 :             masm.branch32(Assembler::Below, argcreg, Imm32(apply->getSingleTarget()->nargs()),
    4611             :                           &underflow);
    4612             :         }
    4613             : 
    4614             :         // Skip the construction of the rectifier frame because we have no
    4615             :         // underflow.
    4616           0 :         masm.jump(&rejoin);
    4617             : 
    4618             :         // Argument fixup needed. Get ready to call the argumentsRectifier.
    4619             :         {
    4620           0 :             masm.bind(&underflow);
    4621             : 
    4622             :             // Hardcode the address of the argumentsRectifier code.
    4623           0 :             JitCode* argumentsRectifier = gen->jitRuntime()->getArgumentsRectifier();
    4624             : 
    4625           0 :             MOZ_ASSERT(ArgumentsRectifierReg != objreg);
    4626           0 :             masm.movePtr(ImmGCPtr(argumentsRectifier), objreg); // Necessary for GC marking.
    4627           0 :             masm.loadPtr(Address(objreg, JitCode::offsetOfCode()), objreg);
    4628           0 :             masm.movePtr(argcreg, ArgumentsRectifierReg);
    4629             :         }
    4630             : 
    4631           0 :         masm.bind(&rejoin);
    4632             : 
    4633             :         // Finally call the function in objreg, as assigned by one of the paths above.
    4634           0 :         uint32_t callOffset = masm.callJit(objreg);
    4635           0 :         markSafepointAt(callOffset, apply);
    4636             : 
    4637             :         // Recover the number of arguments from the frame descriptor.
    4638           0 :         masm.loadPtr(Address(masm.getStackPointer(), 0), stackSpace);
    4639           0 :         masm.rshiftPtr(Imm32(FRAMESIZE_SHIFT), stackSpace);
    4640           0 :         masm.subPtr(Imm32(pushed), stackSpace);
    4641             : 
    4642             :         // Increment to remove IonFramePrefix; decrement to fill FrameSizeClass.
    4643             :         // The return address has already been removed from the Ion frame.
    4644           0 :         int prefixGarbage = sizeof(JitFrameLayout) - sizeof(void*);
    4645           0 :         masm.adjustStack(prefixGarbage);
    4646           0 :         masm.jump(&end);
    4647             :     }
    4648             : 
    4649             :     // Handle uncompiled or native functions.
    4650             :     {
    4651           0 :         masm.bind(&invoke);
    4652           0 :         emitCallInvokeFunction(apply, extraStackSpace);
    4653             :     }
    4654             : 
    4655             :     // Pop arguments and continue.
    4656           0 :     masm.bind(&end);
    4657           0 :     emitPopArguments(extraStackSpace);
    4658             : }
    4659             : 
    4660             : void
    4661           0 : CodeGenerator::visitApplyArgsGeneric(LApplyArgsGeneric* apply)
    4662             : {
    4663             :     // Limit the number of parameters we can handle to a number that does not risk
    4664             :     // us allocating too much stack, notably on Windows where there is a 4K guard page
    4665             :     // that has to be touched to extend the stack.  See bug 1351278.  The value "3000"
    4666             :     // is the size of the guard page minus an arbitrary, but large, safety margin.
    4667             : 
    4668           0 :     LSnapshot* snapshot = apply->snapshot();
    4669           0 :     Register argcreg = ToRegister(apply->getArgc());
    4670             : 
    4671           0 :     uint32_t limit = 3000 / sizeof(Value);
    4672           0 :     bailoutCmp32(Assembler::Above, argcreg, Imm32(limit), snapshot);
    4673             : 
    4674           0 :     emitApplyGeneric(apply);
    4675           0 : }
    4676             : 
    4677             : void
    4678           0 : CodeGenerator::visitApplyArrayGeneric(LApplyArrayGeneric* apply)
    4679             : {
    4680           0 :     LSnapshot* snapshot = apply->snapshot();
    4681           0 :     Register tmp = ToRegister(apply->getTempObject());
    4682             : 
    4683           0 :     Address length(ToRegister(apply->getElements()), ObjectElements::offsetOfLength());
    4684           0 :     masm.load32(length, tmp);
    4685             : 
    4686             :     // See comment in visitApplyArgsGeneric, above.
    4687             : 
    4688           0 :     uint32_t limit = 3000 / sizeof(Value);
    4689           0 :     bailoutCmp32(Assembler::Above, tmp, Imm32(limit), snapshot);
    4690             : 
    4691             :     // Ensure that the array does not contain an uninitialized tail.
    4692             : 
    4693             :     Address initializedLength(ToRegister(apply->getElements()),
    4694           0 :                               ObjectElements::offsetOfInitializedLength());
    4695           0 :     masm.sub32(initializedLength, tmp);
    4696           0 :     bailoutCmp32(Assembler::NotEqual, tmp, Imm32(0), snapshot);
    4697             : 
    4698           0 :     emitApplyGeneric(apply);
    4699           0 : }
    4700             : 
    4701             : void
    4702          18 : CodeGenerator::visitBail(LBail* lir)
    4703             : {
    4704          18 :     bailout(lir->snapshot());
    4705          18 : }
    4706             : 
    4707             : void
    4708          18 : CodeGenerator::visitUnreachable(LUnreachable* lir)
    4709             : {
    4710          18 :     masm.assumeUnreachable("end-of-block assumed unreachable");
    4711          18 : }
    4712             : 
    4713             : void
    4714           0 : CodeGenerator::visitEncodeSnapshot(LEncodeSnapshot* lir)
    4715             : {
    4716           0 :     encode(lir->snapshot());
    4717           0 : }
    4718             : 
    4719             : void
    4720           0 : CodeGenerator::visitGetDynamicName(LGetDynamicName* lir)
    4721             : {
    4722           0 :     Register envChain = ToRegister(lir->getEnvironmentChain());
    4723           0 :     Register name = ToRegister(lir->getName());
    4724           0 :     Register temp1 = ToRegister(lir->temp1());
    4725           0 :     Register temp2 = ToRegister(lir->temp2());
    4726           0 :     Register temp3 = ToRegister(lir->temp3());
    4727             : 
    4728           0 :     masm.loadJSContext(temp3);
    4729             : 
    4730             :     /* Make space for the outparam. */
    4731           0 :     masm.adjustStack(-int32_t(sizeof(Value)));
    4732           0 :     masm.moveStackPtrTo(temp2);
    4733             : 
    4734           0 :     masm.setupUnalignedABICall(temp1);
    4735           0 :     masm.passABIArg(temp3);
    4736           0 :     masm.passABIArg(envChain);
    4737           0 :     masm.passABIArg(name);
    4738           0 :     masm.passABIArg(temp2);
    4739           0 :     masm.callWithABI(JS_FUNC_TO_DATA_PTR(void*, GetDynamicName));
    4740             : 
    4741           0 :     const ValueOperand out = ToOutValue(lir);
    4742             : 
    4743           0 :     masm.loadValue(Address(masm.getStackPointer(), 0), out);
    4744           0 :     masm.adjustStack(sizeof(Value));
    4745             : 
    4746           0 :     Label undefined;
    4747           0 :     masm.branchTestUndefined(Assembler::Equal, out, &undefined);
    4748           0 :     bailoutFrom(&undefined, lir->snapshot());
    4749           0 : }
    4750             : 
    4751             : typedef bool (*DirectEvalSFn)(JSContext*, HandleObject, HandleScript, HandleValue,
    4752             :                               HandleString, jsbytecode*, MutableHandleValue);
    4753           3 : static const VMFunction DirectEvalStringInfo =
    4754           6 :     FunctionInfo<DirectEvalSFn>(DirectEvalStringFromIon, "DirectEvalStringFromIon");
    4755             : 
    4756             : void
    4757           0 : CodeGenerator::visitCallDirectEval(LCallDirectEval* lir)
    4758             : {
    4759           0 :     Register envChain = ToRegister(lir->getEnvironmentChain());
    4760           0 :     Register string = ToRegister(lir->getString());
    4761             : 
    4762           0 :     pushArg(ImmPtr(lir->mir()->pc()));
    4763           0 :     pushArg(string);
    4764           0 :     pushArg(ToValue(lir, LCallDirectEval::NewTarget));
    4765           0 :     pushArg(ImmGCPtr(current->mir()->info().script()));
    4766           0 :     pushArg(envChain);
    4767             : 
    4768           0 :     callVM(DirectEvalStringInfo, lir);
    4769           0 : }
    4770             : 
    4771             : void
    4772          16 : CodeGenerator::generateArgumentsChecks(bool bailout)
    4773             : {
    4774             :     // Registers safe for use before generatePrologue().
    4775             :     static const uint32_t EntryTempMask = Registers::TempMask & ~(1 << OsrFrameReg.code());
    4776             : 
    4777             :     // This function can be used the normal way to check the argument types,
    4778             :     // before entering the function and bailout when arguments don't match.
    4779             :     // For debug purpose, this is can also be used to force/check that the
    4780             :     // arguments are correct. Upon fail it will hit a breakpoint.
    4781             : 
    4782          16 :     MIRGraph& mir = gen->graph();
    4783          16 :     MResumePoint* rp = mir.entryResumePoint();
    4784             : 
    4785             :     // No registers are allocated yet, so it's safe to grab anything.
    4786          16 :     Register temp = AllocatableGeneralRegisterSet(EntryTempMask).getAny();
    4787             : 
    4788          16 :     const CompileInfo& info = gen->info();
    4789             : 
    4790          32 :     Label miss;
    4791          64 :     for (uint32_t i = info.startArgSlot(); i < info.endArgSlot(); i++) {
    4792             :         // All initial parameters are guaranteed to be MParameters.
    4793          48 :         MParameter* param = rp->getOperand(i)->toParameter();
    4794          48 :         const TypeSet* types = param->resultTypeSet();
    4795          48 :         if (!types || types->unknown())
    4796           0 :             continue;
    4797             : 
    4798             :         // Calculate the offset on the stack of the argument.
    4799             :         // (i - info.startArgSlot())    - Compute index of arg within arg vector.
    4800             :         // ... * sizeof(Value)          - Scale by value size.
    4801             :         // ArgToStackOffset(...)        - Compute displacement within arg vector.
    4802          48 :         int32_t offset = ArgToStackOffset((i - info.startArgSlot()) * sizeof(Value));
    4803          48 :         masm.guardTypeSet(Address(masm.getStackPointer(), offset), types, BarrierKind::TypeSet, temp, &miss);
    4804             :     }
    4805             : 
    4806          16 :     if (miss.used()) {
    4807          16 :         if (bailout) {
    4808           8 :             bailoutFrom(&miss, graph.entrySnapshot());
    4809             :         } else {
    4810          16 :             Label success;
    4811           8 :             masm.jump(&success);
    4812           8 :             masm.bind(&miss);
    4813             : 
    4814             :             // Check for cases where the type set guard might have missed due to
    4815             :             // changing object groups.
    4816          32 :             for (uint32_t i = info.startArgSlot(); i < info.endArgSlot(); i++) {
    4817          24 :                 MParameter* param = rp->getOperand(i)->toParameter();
    4818          24 :                 const TemporaryTypeSet* types = param->resultTypeSet();
    4819          24 :                 if (!types || types->unknown())
    4820           0 :                     continue;
    4821             : 
    4822          48 :                 Label skip;
    4823          24 :                 Address addr(masm.getStackPointer(), ArgToStackOffset((i - info.startArgSlot()) * sizeof(Value)));
    4824          24 :                 masm.branchTestObject(Assembler::NotEqual, addr, &skip);
    4825          24 :                 Register obj = masm.extractObject(addr, temp);
    4826          24 :                 masm.guardTypeSetMightBeIncomplete(types, obj, temp, &success);
    4827          24 :                 masm.bind(&skip);
    4828             :             }
    4829             : 
    4830           8 :             masm.assumeUnreachable("Argument check fail.");
    4831           8 :             masm.bind(&success);
    4832             :         }
    4833             :     }
    4834          16 : }
    4835             : 
    4836             : // Out-of-line path to report over-recursed error and fail.
    4837             : class CheckOverRecursedFailure : public OutOfLineCodeBase<CodeGenerator>
    4838             : {
    4839             :     LInstruction* lir_;
    4840             : 
    4841             :   public:
    4842           7 :     explicit CheckOverRecursedFailure(LInstruction* lir)
    4843           7 :       : lir_(lir)
    4844           7 :     { }
    4845             : 
    4846           7 :     void accept(CodeGenerator* codegen) {
    4847           7 :         codegen->visitCheckOverRecursedFailure(this);
    4848           7 :     }
    4849             : 
    4850          21 :     LInstruction* lir() const {
    4851          21 :         return lir_;
    4852             :     }
    4853             : };
    4854             : 
    4855             : void
    4856           8 : CodeGenerator::visitCheckOverRecursed(LCheckOverRecursed* lir)
    4857             : {
    4858             :     // If we don't push anything on the stack, skip the check.
    4859           8 :     if (omitOverRecursedCheck())
    4860           1 :         return;
    4861             : 
    4862             :     // Ensure that this frame will not cross the stack limit.
    4863             :     // This is a weak check, justified by Ion using the C stack: we must always
    4864             :     // be some distance away from the actual limit, since if the limit is
    4865             :     // crossed, an error must be thrown, which requires more frames.
    4866             :     //
    4867             :     // It must always be possible to trespass past the stack limit.
    4868             :     // Ion may legally place frames very close to the limit. Calling additional
    4869             :     // C functions may then violate the limit without any checking.
    4870             :     //
    4871             :     // Since Ion frames exist on the C stack, the stack limit may be
    4872             :     // dynamically set by JS_SetThreadStackLimit() and JS_SetNativeStackQuota().
    4873             : 
    4874           7 :     CheckOverRecursedFailure* ool = new(alloc()) CheckOverRecursedFailure(lir);
    4875           7 :     addOutOfLineCode(ool, lir->mir());
    4876             : 
    4877           7 :     Register temp = ToRegister(lir->temp());
    4878             : 
    4879             :     // Conditional forward (unlikely) branch to failure.
    4880           7 :     const void* contextAddr = GetJitContext()->compartment->zone()->addressOfJSContext();
    4881           7 :     masm.loadPtr(AbsoluteAddress(contextAddr), temp);
    4882          14 :     masm.branchStackPtrRhs(Assembler::AboveOrEqual,
    4883           7 :                            Address(temp, offsetof(JSContext, jitStackLimit)), ool->entry());
    4884           7 :     masm.bind(ool->rejoin());
    4885             : }
    4886             : 
    4887             : typedef bool (*DefVarFn)(JSContext*, HandlePropertyName, unsigned, HandleObject);
    4888           3 : static const VMFunction DefVarInfo = FunctionInfo<DefVarFn>(DefVar, "DefVar");
    4889             : 
    4890             : void
    4891           0 : CodeGenerator::visitDefVar(LDefVar* lir)
    4892             : {
    4893           0 :     Register envChain = ToRegister(lir->environmentChain());
    4894             : 
    4895           0 :     pushArg(envChain); // JSObject*
    4896           0 :     pushArg(Imm32(lir->mir()->attrs())); // unsigned
    4897           0 :     pushArg(ImmGCPtr(lir->mir()->name())); // PropertyName*
    4898             : 
    4899           0 :     callVM(DefVarInfo, lir);
    4900           0 : }
    4901             : 
    4902             : typedef bool (*DefLexicalFn)(JSContext*, HandlePropertyName, unsigned);
    4903           3 : static const VMFunction DefLexicalInfo =
    4904           6 :     FunctionInfo<DefLexicalFn>(DefGlobalLexical, "DefGlobalLexical");
    4905             : 
    4906             : void
    4907           0 : CodeGenerator::visitDefLexical(LDefLexical* lir)
    4908             : {
    4909           0 :     pushArg(Imm32(lir->mir()->attrs())); // unsigned
    4910           0 :     pushArg(ImmGCPtr(lir->mir()->name())); // PropertyName*
    4911             : 
    4912           0 :     callVM(DefLexicalInfo, lir);
    4913           0 : }
    4914             : 
    4915             : typedef bool (*DefFunOperationFn)(JSContext*, HandleScript, HandleObject, HandleFunction);
    4916           3 : static const VMFunction DefFunOperationInfo =
    4917           6 :     FunctionInfo<DefFunOperationFn>(DefFunOperation, "DefFunOperation");
    4918             : 
    4919             : void
    4920           0 : CodeGenerator::visitDefFun(LDefFun* lir)
    4921             : {
    4922           0 :     Register envChain = ToRegister(lir->environmentChain());
    4923             : 
    4924           0 :     Register fun = ToRegister(lir->fun());
    4925           0 :     pushArg(fun);
    4926           0 :     pushArg(envChain);
    4927           0 :     pushArg(ImmGCPtr(current->mir()->info().script()));
    4928             : 
    4929           0 :     callVM(DefFunOperationInfo, lir);
    4930           0 : }
    4931             : 
    4932             : typedef bool (*CheckOverRecursedFn)(JSContext*);
    4933           3 : static const VMFunction CheckOverRecursedInfo =
    4934           6 :     FunctionInfo<CheckOverRecursedFn>(CheckOverRecursed, "CheckOverRecursed");
    4935             : 
    4936             : void
    4937           7 : CodeGenerator::visitCheckOverRecursedFailure(CheckOverRecursedFailure* ool)
    4938             : {
    4939             :     // The OOL path is hit if the recursion depth has been exceeded.
    4940             :     // Throw an InternalError for over-recursion.
    4941             : 
    4942             :     // LFunctionEnvironment can appear before LCheckOverRecursed, so we have
    4943             :     // to save all live registers to avoid crashes if CheckOverRecursed triggers
    4944             :     // a GC.
    4945           7 :     saveLive(ool->lir());
    4946             : 
    4947           7 :     callVM(CheckOverRecursedInfo, ool->lir());
    4948             : 
    4949           7 :     restoreLive(ool->lir());
    4950           7 :     masm.jump(ool->rejoin());
    4951           7 : }
    4952             : 
    4953             : IonScriptCounts*
    4954           8 : CodeGenerator::maybeCreateScriptCounts()
    4955             : {
    4956             :     // If scripts are being profiled, create a new IonScriptCounts for the
    4957             :     // profiling data, which will be attached to the associated JSScript or
    4958             :     // wasm module after code generation finishes.
    4959           8 :     if (!GetJitContext()->hasProfilingScripts())
    4960           8 :         return nullptr;
    4961             : 
    4962             :     // This test inhibits IonScriptCount creation for wasm code which is
    4963             :     // currently incompatible with wasm codegen for two reasons: (1) wasm code
    4964             :     // must be serializable and script count codegen bakes in absolute
    4965             :     // addresses, (2) wasm code does not have a JSScript with which to associate
    4966             :     // code coverage data.
    4967           0 :     JSScript* script = gen->info().script();
    4968           0 :     if (!script)
    4969           0 :         return nullptr;
    4970             : 
    4971           0 :     UniquePtr<IonScriptCounts> counts(js_new<IonScriptCounts>());
    4972           0 :     if (!counts || !counts->init(graph.numBlocks()))
    4973           0 :         return nullptr;
    4974             : 
    4975           0 :     for (size_t i = 0; i < graph.numBlocks(); i++) {
    4976           0 :         MBasicBlock* block = graph.getBlock(i)->mir();
    4977             : 
    4978           0 :         uint32_t offset = 0;
    4979           0 :         char* description = nullptr;
    4980           0 :         if (MResumePoint* resume = block->entryResumePoint()) {
    4981             :             // Find a PC offset in the outermost script to use. If this
    4982             :             // block is from an inlined script, find a location in the
    4983             :             // outer script to associate information about the inlining
    4984             :             // with.
    4985           0 :             while (resume->caller())
    4986           0 :                 resume = resume->caller();
    4987           0 :             offset = script->pcToOffset(resume->pc());
    4988             : 
    4989           0 :             if (block->entryResumePoint()->caller()) {
    4990             :                 // Get the filename and line number of the inner script.
    4991           0 :                 JSScript* innerScript = block->info().script();
    4992           0 :                 description = (char*) js_calloc(200);
    4993           0 :                 if (description) {
    4994           0 :                     snprintf(description, 200, "%s:%" PRIuSIZE,
    4995           0 :                              innerScript->filename(), innerScript->lineno());
    4996             :                 }
    4997             :             }
    4998             :         }
    4999             : 
    5000           0 :         if (!counts->block(i).init(block->id(), offset, description, block->numSuccessors()))
    5001           0 :             return nullptr;
    5002             : 
    5003           0 :         for (size_t j = 0; j < block->numSuccessors(); j++)
    5004           0 :             counts->block(i).setSuccessor(j, skipTrivialBlocks(block->getSuccessor(j))->id());
    5005             :     }
    5006             : 
    5007           0 :     scriptCounts_ = counts.release();
    5008           0 :     return scriptCounts_;
    5009             : }
    5010             : 
    5011             : // Structure for managing the state tracked for a block by script counters.
    5012             : struct ScriptCountBlockState
    5013             : {
    5014             :     IonBlockCounts& block;
    5015             :     MacroAssembler& masm;
    5016             : 
    5017             :     Sprinter printer;
    5018             : 
    5019             :   public:
    5020           0 :     ScriptCountBlockState(IonBlockCounts* block, MacroAssembler* masm)
    5021           0 :       : block(*block), masm(*masm), printer(GetJitContext()->cx, false)
    5022             :     {
    5023           0 :     }
    5024             : 
    5025           0 :     bool init()
    5026             :     {
    5027           0 :         if (!printer.init())
    5028           0 :             return false;
    5029             : 
    5030             :         // Bump the hit count for the block at the start. This code is not
    5031             :         // included in either the text for the block or the instruction byte
    5032             :         // counts.
    5033           0 :         masm.inc64(AbsoluteAddress(block.addressOfHitCount()));
    5034             : 
    5035             :         // Collect human readable assembly for the code generated in the block.
    5036           0 :         masm.setPrinter(&printer);
    5037             : 
    5038           0 :         return true;
    5039             :     }
    5040             : 
    5041           0 :     void visitInstruction(LInstruction* ins)
    5042             :     {
    5043             :         // Prefix stream of assembly instructions with their LIR instruction
    5044             :         // name and any associated high level info.
    5045           0 :         if (const char* extra = ins->extraName())
    5046           0 :             printer.printf("[%s:%s]\n", ins->opName(), extra);
    5047             :         else
    5048           0 :             printer.printf("[%s]\n", ins->opName());
    5049           0 :     }
    5050             : 
    5051           0 :     ~ScriptCountBlockState()
    5052           0 :     {
    5053           0 :         masm.setPrinter(nullptr);
    5054             : 
    5055           0 :         if (!printer.hadOutOfMemory())
    5056           0 :             block.setCode(printer.string());
    5057           0 :     }
    5058             : };
    5059             : 
    5060             : void
    5061         368 : CodeGenerator::branchIfInvalidated(Register temp, Label* invalidated)
    5062             : {
    5063         368 :     CodeOffset label = masm.movWithPatch(ImmWord(uintptr_t(-1)), temp);
    5064         368 :     masm.propagateOOM(ionScriptLabels_.append(label));
    5065             : 
    5066             :     // If IonScript::invalidationCount_ != 0, the script has been invalidated.
    5067        1104 :     masm.branch32(Assembler::NotEqual,
    5068         736 :                   Address(temp, IonScript::offsetOfInvalidationCount()),
    5069             :                   Imm32(0),
    5070         368 :                   invalidated);
    5071         368 : }
    5072             : 
    5073             : void
    5074         150 : CodeGenerator::emitAssertObjectOrStringResult(Register input, MIRType type, const TemporaryTypeSet* typeset)
    5075             : {
    5076         150 :     MOZ_ASSERT(type == MIRType::Object || type == MIRType::ObjectOrNull ||
    5077             :                type == MIRType::String || type == MIRType::Symbol);
    5078             : 
    5079         150 :     AllocatableGeneralRegisterSet regs(GeneralRegisterSet::All());
    5080         150 :     regs.take(input);
    5081             : 
    5082         150 :     Register temp = regs.takeAny();
    5083         150 :     masm.push(temp);
    5084             : 
    5085             :     // Don't check if the script has been invalidated. In that case invalid
    5086             :     // types are expected (until we reach the OsiPoint and bailout).
    5087         300 :     Label done;
    5088         150 :     branchIfInvalidated(temp, &done);
    5089             : 
    5090         204 :     if ((type == MIRType::Object || type == MIRType::ObjectOrNull) &&
    5091         202 :         typeset && !typeset->unknownObject())
    5092             :     {
    5093             :         // We have a result TypeSet, assert this object is in it.
    5094          96 :         Label miss, ok;
    5095          48 :         if (type == MIRType::ObjectOrNull)
    5096           0 :             masm.branchPtr(Assembler::Equal, input, ImmWord(0), &ok);
    5097          48 :         if (typeset->getObjectCount() > 0)
    5098          43 :             masm.guardObjectType(input, typeset, temp, &miss);
    5099             :         else
    5100           5 :             masm.jump(&miss);
    5101          48 :         masm.jump(&ok);
    5102             : 
    5103          48 :         masm.bind(&miss);
    5104          48 :         masm.guardTypeSetMightBeIncomplete(typeset, input, temp, &ok);
    5105             : 
    5106          48 :         masm.assumeUnreachable("MIR instruction returned object with unexpected type");
    5107             : 
    5108          48 :         masm.bind(&ok);
    5109             :     }
    5110             : 
    5111             :     // Check that we have a valid GC pointer.
    5112         150 :     saveVolatile();
    5113         150 :     masm.setupUnalignedABICall(temp);
    5114         150 :     masm.loadJSContext(temp);
    5115         150 :     masm.passABIArg(temp);
    5116         150 :     masm.passABIArg(input);
    5117             : 
    5118             :     void* callee;
    5119         150 :     switch (type) {
    5120             :       case MIRType::Object:
    5121          96 :         callee = JS_FUNC_TO_DATA_PTR(void*, AssertValidObjectPtr);
    5122          96 :         break;
    5123             :       case MIRType::ObjectOrNull:
    5124           0 :         callee = JS_FUNC_TO_DATA_PTR(void*, AssertValidObjectOrNullPtr);
    5125           0 :         break;
    5126             :       case MIRType::String:
    5127          54 :         callee = JS_FUNC_TO_DATA_PTR(void*, AssertValidStringPtr);
    5128          54 :         break;
    5129             :       case MIRType::Symbol:
    5130           0 :         callee = JS_FUNC_TO_DATA_PTR(void*, AssertValidSymbolPtr);
    5131           0 :         break;
    5132             :       default:
    5133           0 :         MOZ_CRASH();
    5134             :     }
    5135             : 
    5136         150 :     masm.callWithABI(callee);
    5137         150 :     restoreVolatile();
    5138             : 
    5139         150 :     masm.bind(&done);
    5140         150 :     masm.pop(temp);
    5141         150 : }
    5142             : 
    5143             : void
    5144         218 : CodeGenerator::emitAssertResultV(const ValueOperand input, const TemporaryTypeSet* typeset)
    5145             : {
    5146         218 :     AllocatableGeneralRegisterSet regs(GeneralRegisterSet::All());
    5147         218 :     regs.take(input);
    5148             : 
    5149         218 :     Register temp1 = regs.takeAny();
    5150         218 :     Register temp2 = regs.takeAny();
    5151         218 :     masm.push(temp1);
    5152         218 :     masm.push(temp2);
    5153             : 
    5154             :     // Don't check if the script has been invalidated. In that case invalid
    5155             :     // types are expected (until we reach the OsiPoint and bailout).
    5156         436 :     Label done;
    5157         218 :     branchIfInvalidated(temp1, &done);
    5158             : 
    5159         218 :     if (typeset && !typeset->unknown()) {
    5160             :         // We have a result TypeSet, assert this value is in it.
    5161         166 :         Label miss, ok;
    5162          83 :         masm.guardTypeSet(input, typeset, BarrierKind::TypeSet, temp1, &miss);
    5163          83 :         masm.jump(&ok);
    5164             : 
    5165          83 :         masm.bind(&miss);
    5166             : 
    5167             :         // Check for cases where the type set guard might have missed due to
    5168             :         // changing object groups.
    5169         166 :         Label realMiss;
    5170          83 :         masm.branchTestObject(Assembler::NotEqual, input, &realMiss);
    5171          83 :         Register payload = masm.extractObject(input, temp1);
    5172          83 :         masm.guardTypeSetMightBeIncomplete(typeset, payload, temp1, &ok);
    5173          83 :         masm.bind(&realMiss);
    5174             : 
    5175          83 :         masm.assumeUnreachable("MIR instruction returned value with unexpected type");
    5176             : 
    5177          83 :         masm.bind(&ok);
    5178             :     }
    5179             : 
    5180             :     // Check that we have a valid GC pointer.
    5181         218 :     saveVolatile();
    5182             : 
    5183         218 :     masm.pushValue(input);
    5184         218 :     masm.moveStackPtrTo(temp1);
    5185             : 
    5186         218 :     masm.setupUnalignedABICall(temp2);
    5187         218 :     masm.loadJSContext(temp2);
    5188         218 :     masm.passABIArg(temp2);
    5189         218 :     masm.passABIArg(temp1);
    5190         218 :     masm.callWithABI(JS_FUNC_TO_DATA_PTR(void*, AssertValidValue));
    5191         218 :     masm.popValue(input);
    5192         218 :     restoreVolatile();
    5193             : 
    5194         218 :     masm.bind(&done);
    5195         218 :     masm.pop(temp2);
    5196         218 :     masm.pop(temp1);
    5197         218 : }
    5198             : 
    5199             : #ifdef DEBUG
    5200             : void
    5201         179 : CodeGenerator::emitObjectOrStringResultChecks(LInstruction* lir, MDefinition* mir)
    5202             : {
    5203         179 :     if (lir->numDefs() == 0)
    5204          29 :         return;
    5205             : 
    5206         150 :     MOZ_ASSERT(lir->numDefs() == 1);
    5207         150 :     Register output = ToRegister(lir->getDef(0));
    5208             : 
    5209         150 :     emitAssertObjectOrStringResult(output, mir->type(), mir->resultTypeSet());
    5210             : }
    5211             : 
    5212             : void
    5213         301 : CodeGenerator::emitValueResultChecks(LInstruction* lir, MDefinition* mir)
    5214             : {
    5215         301 :     if (lir->numDefs() == 0)
    5216         130 :         return;
    5217             : 
    5218         254 :     MOZ_ASSERT(lir->numDefs() == BOX_PIECES);
    5219         254 :     if (!lir->getDef(0)->output()->isRegister())
    5220          36 :         return;
    5221             : 
    5222         218 :     ValueOperand output = ToOutValue(lir);
    5223             : 
    5224         218 :     emitAssertResultV(output, mir->resultTypeSet());
    5225             : }
    5226             : 
    5227             : void
    5228        1681 : CodeGenerator::emitDebugResultChecks(LInstruction* ins)
    5229             : {
    5230             :     // In debug builds, check that LIR instructions return valid values.
    5231             : 
    5232        1681 :     MDefinition* mir = ins->mirRaw();
    5233        1681 :     if (!mir)
    5234         866 :         return;
    5235             : 
    5236         815 :     switch (mir->type()) {
    5237             :       case MIRType::Object:
    5238             :       case MIRType::ObjectOrNull:
    5239             :       case MIRType::String:
    5240             :       case MIRType::Symbol:
    5241         179 :         emitObjectOrStringResultChecks(ins, mir);
    5242         179 :         break;
    5243             :       case MIRType::Value:
    5244         301 :         emitValueResultChecks(ins, mir);
    5245         301 :         break;
    5246             :       default:
    5247         335 :         break;
    5248             :     }
    5249             : }
    5250             : 
    5251             : void
    5252        1681 : CodeGenerator::emitDebugForceBailing(LInstruction* lir)
    5253             : {
    5254        1681 :     if (!lir->snapshot())
    5255        2855 :         return;
    5256         326 :     if (lir->isStart())
    5257          11 :         return;
    5258         315 :     if (lir->isOsiPoint())
    5259         134 :         return;
    5260             : 
    5261         181 :     masm.comment("emitDebugForceBailing");
    5262         181 :     const void* bailAfterAddr = GetJitContext()->compartment->zone()->addressOfIonBailAfter();
    5263             : 
    5264         181 :     AllocatableGeneralRegisterSet regs(GeneralRegisterSet::All());
    5265             : 
    5266         362 :     Label done, notBail, bail;
    5267         181 :     masm.branch32(Assembler::Equal, AbsoluteAddress(bailAfterAddr), Imm32(0), &done);
    5268             :     {
    5269         181 :         Register temp = regs.takeAny();
    5270             : 
    5271         181 :         masm.push(temp);
    5272         181 :         masm.load32(AbsoluteAddress(bailAfterAddr), temp);
    5273         181 :         masm.sub32(Imm32(1), temp);
    5274         181 :         masm.store32(temp, AbsoluteAddress(bailAfterAddr));
    5275             : 
    5276         181 :         masm.branch32(Assembler::NotEqual, temp, Imm32(0), &notBail);
    5277             :         {
    5278         181 :             masm.pop(temp);
    5279         181 :             masm.jump(&bail);
    5280         181 :             bailoutFrom(&bail, lir->snapshot());
    5281             :         }
    5282         181 :         masm.bind(&notBail);
    5283         181 :         masm.pop(temp);
    5284             :     }
    5285         181 :     masm.bind(&done);
    5286             : }
    5287             : #endif
    5288             : 
    5289             : static void
    5290           0 : DumpTrackedSite(const BytecodeSite* site)
    5291             : {
    5292           0 :     if (!JitSpewEnabled(JitSpew_OptimizationTracking))
    5293           0 :         return;
    5294             : 
    5295             : #ifdef JS_JITSPEW
    5296           0 :     unsigned column = 0;
    5297           0 :     unsigned lineNumber = PCToLineNumber(site->script(), site->pc(), &column);
    5298           0 :     JitSpew(JitSpew_OptimizationTracking, "Types for %s at %s:%u:%u",
    5299           0 :             CodeName[JSOp(*site->pc())],
    5300             :             site->script()->filename(),
    5301             :             lineNumber,
    5302           0 :             column);
    5303             : #endif
    5304             : }
    5305             : 
    5306             : static void
    5307           0 : DumpTrackedOptimizations(TrackedOptimizations* optimizations)
    5308             : {
    5309           0 :     if (!JitSpewEnabled(JitSpew_OptimizationTracking))
    5310           0 :         return;
    5311             : 
    5312           0 :     optimizations->spew(JitSpew_OptimizationTracking);
    5313             : }
    5314             : 
    5315             : bool
    5316           8 : CodeGenerator::generateBody()
    5317             : {
    5318           8 :     IonScriptCounts* counts = maybeCreateScriptCounts();
    5319             : 
    5320             : #if defined(JS_ION_PERF)
    5321             :     PerfSpewer* perfSpewer = &perfSpewer_;
    5322             :     if (gen->compilingWasm())
    5323             :         perfSpewer = &gen->perfSpewer();
    5324             : #endif
    5325             : 
    5326         411 :     for (size_t i = 0; i < graph.numBlocks(); i++) {
    5327         403 :         current = graph.getBlock(i);
    5328             : 
    5329             :         // Don't emit any code for trivial blocks, containing just a goto. Such
    5330             :         // blocks are created to split critical edges, and if we didn't end up
    5331             :         // putting any instructions in them, we can skip them.
    5332         403 :         if (current->isTrivial())
    5333         107 :             continue;
    5334             : 
    5335             : #ifdef JS_JITSPEW
    5336         296 :         const char* filename = nullptr;
    5337         296 :         size_t lineNumber = 0;
    5338         296 :         unsigned columnNumber = 0;
    5339         296 :         if (current->mir()->info().script()) {
    5340         296 :             filename = current->mir()->info().script()->filename();
    5341         296 :             if (current->mir()->pc())
    5342         296 :                 lineNumber = PCToLineNumber(current->mir()->info().script(), current->mir()->pc(),
    5343             :                                             &columnNumber);
    5344             :         } else {
    5345             : #ifdef DEBUG
    5346           0 :             lineNumber = current->mir()->lineno();
    5347           0 :             columnNumber = current->mir()->columnIndex();
    5348             : #endif
    5349             :         }
    5350         592 :         JitSpew(JitSpew_Codegen, "# block%" PRIuSIZE " %s:%" PRIuSIZE ":%u%s:",
    5351             :                 i, filename ? filename : "?", lineNumber, columnNumber,
    5352         888 :                 current->mir()->isLoopHeader() ? " (loop header)" : "");
    5353             : #endif
    5354             : 
    5355         296 :         masm.bind(current->label());
    5356             : 
    5357         592 :         mozilla::Maybe<ScriptCountBlockState> blockCounts;
    5358         296 :         if (counts) {
    5359           0 :             blockCounts.emplace(&counts->block(i), &masm);
    5360           0 :             if (!blockCounts->init())
    5361           0 :                 return false;
    5362             :         }
    5363         296 :         TrackedOptimizations* last = nullptr;
    5364             : 
    5365             : #if defined(JS_ION_PERF)
    5366             :         perfSpewer->startBasicBlock(current->mir(), masm);
    5367             : #endif
    5368             : 
    5369        1977 :         for (LInstructionIterator iter = current->begin(); iter != current->end(); iter++) {
    5370        1681 :             if (!alloc().ensureBallast())
    5371           0 :                 return false;
    5372             : 
    5373             : #ifdef JS_JITSPEW
    5374        1681 :             JitSpewStart(JitSpew_Codegen, "instruction %s", iter->opName());
    5375        1681 :             if (const char* extra = iter->extraName())
    5376         225 :                 JitSpewCont(JitSpew_Codegen, ":%s", extra);
    5377        1681 :             JitSpewFin(JitSpew_Codegen);
    5378             : #endif
    5379             : 
    5380        1681 :             if (counts)
    5381           0 :                 blockCounts->visitInstruction(*iter);
    5382             : 
    5383             : #ifdef CHECK_OSIPOINT_REGISTERS
    5384        1681 :             if (iter->safepoint())
    5385         134 :                 resetOsiPointRegs(iter->safepoint());
    5386             : #endif
    5387             : 
    5388        1681 :             if (iter->mirRaw()) {
    5389             :                 // Only add instructions that have a tracked inline script tree.
    5390         815 :                 if (iter->mirRaw()->trackedTree()) {
    5391         815 :                     if (!addNativeToBytecodeEntry(iter->mirRaw()->trackedSite()))
    5392           0 :                         return false;
    5393             :                 }
    5394             : 
    5395             :                 // Track the start native offset of optimizations.
    5396         815 :                 if (iter->mirRaw()->trackedOptimizations()) {
    5397           0 :                     if (last != iter->mirRaw()->trackedOptimizations()) {
    5398           0 :                         DumpTrackedSite(iter->mirRaw()->trackedSite());
    5399           0 :                         DumpTrackedOptimizations(iter->mirRaw()->trackedOptimizations());
    5400           0 :                         last = iter->mirRaw()->trackedOptimizations();
    5401             :                     }
    5402           0 :                     if (!addTrackedOptimizationsEntry(iter->mirRaw()->trackedOptimizations()))
    5403           0 :                         return false;
    5404             :                 }
    5405             :             }
    5406             : 
    5407             : #ifdef DEBUG
    5408        1681 :             setElement(*iter); // needed to encode correct snapshot location.
    5409        1681 :             emitDebugForceBailing(*iter);
    5410             : #endif
    5411             : 
    5412        1681 :             iter->accept(this);
    5413             : 
    5414             :             // Track the end native offset of optimizations.
    5415        1681 :             if (iter->mirRaw() && iter->mirRaw()->trackedOptimizations())
    5416           0 :                 extendTrackedOptimizationsEntry(iter->mirRaw()->trackedOptimizations());
    5417             : 
    5418             : #ifdef DEBUG
    5419        1681 :             if (!counts) {
    5420        1681 :                 if (JitOptions.fullDebugChecks)
    5421        1681 :                     emitDebugResultChecks(*iter);
    5422             :             }
    5423             : #endif
    5424             :         }
    5425         296 :         if (masm.oom())
    5426           0 :             return false;
    5427             : 
    5428             : #if defined(JS_ION_PERF)
    5429             :         perfSpewer->endBasicBlock(masm);
    5430             : #endif
    5431             :     }
    5432             : 
    5433           8 :     return true;
    5434             : }
    5435             : 
    5436             : // Out-of-line object allocation for LNewArray.
    5437             : class OutOfLineNewArray : public OutOfLineCodeBase<CodeGenerator>
    5438             : {
    5439             :     LNewArray* lir_;
    5440             : 
    5441             :   public:
    5442           3 :     explicit OutOfLineNewArray(LNewArray* lir)
    5443           3 :       : lir_(lir)
    5444           3 :     { }
    5445             : 
    5446           3 :     void accept(CodeGenerator* codegen) {
    5447           3 :         codegen->visitOutOfLineNewArray(this);
    5448           3 :     }
    5449             : 
    5450           3 :     LNewArray* lir() const {
    5451           3 :         return lir_;
    5452             :     }
    5453             : };
    5454             : 
    5455             : typedef JSObject* (*NewArrayOperationFn)(JSContext*, HandleScript, jsbytecode*, uint32_t,
    5456             :                                          NewObjectKind);
    5457           3 : static const VMFunction NewArrayOperationInfo =
    5458           6 :     FunctionInfo<NewArrayOperationFn>(NewArrayOperation, "NewArrayOperation");
    5459             : 
    5460             : static JSObject*
    5461           0 : NewArrayWithGroup(JSContext* cx, uint32_t length, HandleObjectGroup group,
    5462             :                   bool convertDoubleElements)
    5463             : {
    5464           0 :     JSObject* res = NewFullyAllocatedArrayTryUseGroup(cx, group, length);
    5465           0 :     if (!res)
    5466           0 :         return nullptr;
    5467           0 :     if (convertDoubleElements)
    5468           0 :         res->as<ArrayObject>().setShouldConvertDoubleElements();
    5469           0 :     return res;
    5470             : }
    5471             : 
    5472             : typedef JSObject* (*NewArrayWithGroupFn)(JSContext*, uint32_t, HandleObjectGroup, bool);
    5473           3 : static const VMFunction NewArrayWithGroupInfo =
    5474           6 :     FunctionInfo<NewArrayWithGroupFn>(NewArrayWithGroup, "NewArrayWithGroup");
    5475             : 
    5476             : void
    5477           3 : CodeGenerator::visitNewArrayCallVM(LNewArray* lir)
    5478             : {
    5479           3 :     Register objReg = ToRegister(lir->output());
    5480             : 
    5481           3 :     MOZ_ASSERT(!lir->isCall());
    5482           3 :     saveLive(lir);
    5483             : 
    5484           3 :     JSObject* templateObject = lir->mir()->templateObject();
    5485             : 
    5486           3 :     if (templateObject) {
    5487           3 :         pushArg(Imm32(lir->mir()->convertDoubleElements()));
    5488           3 :         pushArg(ImmGCPtr(templateObject->group()));
    5489           3 :         pushArg(Imm32(lir->mir()->length()));
    5490             : 
    5491           3 :         callVM(NewArrayWithGroupInfo, lir);
    5492             :     } else {
    5493           0 :         pushArg(Imm32(GenericObject));
    5494           0 :         pushArg(Imm32(lir->mir()->length()));
    5495           0 :         pushArg(ImmPtr(lir->mir()->pc()));
    5496           0 :         pushArg(ImmGCPtr(lir->mir()->block()->info().script()));
    5497             : 
    5498           0 :         callVM(NewArrayOperationInfo, lir);
    5499             :     }
    5500             : 
    5501           3 :     if (ReturnReg != objReg)
    5502           3 :         masm.movePtr(ReturnReg, objReg);
    5503             : 
    5504           3 :     restoreLive(lir);
    5505           3 : }
    5506             : 
    5507             : typedef JSObject* (*NewDerivedTypedObjectFn)(JSContext*,
    5508             :                                              HandleObject type,
    5509             :                                              HandleObject owner,
    5510             :                                              int32_t offset);
    5511           3 : static const VMFunction CreateDerivedTypedObjInfo =
    5512           6 :     FunctionInfo<NewDerivedTypedObjectFn>(CreateDerivedTypedObj, "CreateDerivedTypedObj");
    5513             : 
    5514             : void
    5515           0 : CodeGenerator::visitNewDerivedTypedObject(LNewDerivedTypedObject* lir)
    5516             : {
    5517           0 :     pushArg(ToRegister(lir->offset()));
    5518           0 :     pushArg(ToRegister(lir->owner()));
    5519           0 :     pushArg(ToRegister(lir->type()));
    5520           0 :     callVM(CreateDerivedTypedObjInfo, lir);
    5521           0 : }
    5522             : 
    5523             : void
    5524           0 : CodeGenerator::visitAtan2D(LAtan2D* lir)
    5525             : {
    5526           0 :     Register temp = ToRegister(lir->temp());
    5527           0 :     FloatRegister y = ToFloatRegister(lir->y());
    5528           0 :     FloatRegister x = ToFloatRegister(lir->x());
    5529             : 
    5530           0 :     masm.setupUnalignedABICall(temp);
    5531           0 :     masm.passABIArg(y, MoveOp::DOUBLE);
    5532           0 :     masm.passABIArg(x, MoveOp::DOUBLE);
    5533           0 :     masm.callWithABI(JS_FUNC_TO_DATA_PTR(void*, ecmaAtan2), MoveOp::DOUBLE);
    5534             : 
    5535           0 :     MOZ_ASSERT(ToFloatRegister(lir->output()) == ReturnDoubleReg);
    5536           0 : }
    5537             : 
    5538             : void
    5539           0 : CodeGenerator::visitHypot(LHypot* lir)
    5540             : {
    5541           0 :     Register temp = ToRegister(lir->temp());
    5542           0 :     uint32_t numArgs = lir->numArgs();
    5543           0 :     masm.setupUnalignedABICall(temp);
    5544             : 
    5545           0 :     for (uint32_t i = 0 ; i < numArgs; ++i)
    5546           0 :         masm.passABIArg(ToFloatRegister(lir->getOperand(i)), MoveOp::DOUBLE);
    5547             : 
    5548           0 :     switch(numArgs) {
    5549             :       case 2:
    5550           0 :         masm.callWithABI(JS_FUNC_TO_DATA_PTR(void*, ecmaHypot), MoveOp::DOUBLE);
    5551           0 :         break;
    5552             :       case 3:
    5553           0 :         masm.callWithABI(JS_FUNC_TO_DATA_PTR(void*, hypot3), MoveOp::DOUBLE);
    5554           0 :         break;
    5555             :       case 4:
    5556           0 :         masm.callWithABI(JS_FUNC_TO_DATA_PTR(void*, hypot4), MoveOp::DOUBLE);
    5557           0 :         break;
    5558             :       default:
    5559           0 :         MOZ_CRASH("Unexpected number of arguments to hypot function.");
    5560             :     }
    5561           0 :     MOZ_ASSERT(ToFloatRegister(lir->output()) == ReturnDoubleReg);
    5562           0 : }
    5563             : 
    5564             : void
    5565           3 : CodeGenerator::visitNewArray(LNewArray* lir)
    5566             : {
    5567           3 :     Register objReg = ToRegister(lir->output());
    5568           3 :     Register tempReg = ToRegister(lir->temp());
    5569           3 :     JSObject* templateObject = lir->mir()->templateObject();
    5570           6 :     DebugOnly<uint32_t> length = lir->mir()->length();
    5571             : 
    5572           3 :     MOZ_ASSERT(length <= NativeObject::MAX_DENSE_ELEMENTS_COUNT);
    5573             : 
    5574           3 :     if (lir->mir()->isVMCall()) {
    5575           0 :         visitNewArrayCallVM(lir);
    5576           0 :         return;
    5577             :     }
    5578             : 
    5579           3 :     OutOfLineNewArray* ool = new(alloc()) OutOfLineNewArray(lir);
    5580           3 :     addOutOfLineCode(ool, lir->mir());
    5581             : 
    5582           3 :     masm.createGCObject(objReg, tempReg, templateObject, lir->mir()->initialHeap(),
    5583             :                         ool->entry(), /* initContents = */ true,
    5584           6 :                         lir->mir()->convertDoubleElements());
    5585             : 
    5586           3 :     masm.bind(ool->rejoin());
    5587             : }
    5588             : 
    5589             : void
    5590           3 : CodeGenerator::visitOutOfLineNewArray(OutOfLineNewArray* ool)
    5591             : {
    5592           3 :     visitNewArrayCallVM(ool->lir());
    5593           3 :     masm.jump(ool->rejoin());
    5594           3 : }
    5595             : 
    5596             : void
    5597           0 : CodeGenerator::visitNewArrayCopyOnWrite(LNewArrayCopyOnWrite* lir)
    5598             : {
    5599           0 :     Register objReg = ToRegister(lir->output());
    5600           0 :     Register tempReg = ToRegister(lir->temp());
    5601           0 :     ArrayObject* templateObject = lir->mir()->templateObject();
    5602           0 :     gc::InitialHeap initialHeap = lir->mir()->initialHeap();
    5603             : 
    5604             :     // If we have a template object, we can inline call object creation.
    5605           0 :     OutOfLineCode* ool = oolCallVM(NewArrayCopyOnWriteInfo, lir,
    5606           0 :                                    ArgList(ImmGCPtr(templateObject), Imm32(initialHeap)),
    5607           0 :                                    StoreRegisterTo(objReg));
    5608             : 
    5609           0 :     masm.createGCObject(objReg, tempReg, templateObject, initialHeap, ool->entry());
    5610             : 
    5611           0 :     masm.bind(ool->rejoin());
    5612           0 : }
    5613             : 
    5614             : typedef JSObject* (*ArrayConstructorOneArgFn)(JSContext*, HandleObjectGroup, int32_t length);
    5615           3 : static const VMFunction ArrayConstructorOneArgInfo =
    5616           6 :     FunctionInfo<ArrayConstructorOneArgFn>(ArrayConstructorOneArg, "ArrayConstructorOneArg");
    5617             : 
    5618             : void
    5619           0 : CodeGenerator::visitNewArrayDynamicLength(LNewArrayDynamicLength* lir)
    5620             : {
    5621           0 :     Register lengthReg = ToRegister(lir->length());
    5622           0 :     Register objReg = ToRegister(lir->output());
    5623           0 :     Register tempReg = ToRegister(lir->temp());
    5624             : 
    5625           0 :     JSObject* templateObject = lir->mir()->templateObject();
    5626           0 :     gc::InitialHeap initialHeap = lir->mir()->initialHeap();
    5627             : 
    5628           0 :     OutOfLineCode* ool = oolCallVM(ArrayConstructorOneArgInfo, lir,
    5629           0 :                                    ArgList(ImmGCPtr(templateObject->group()), lengthReg),
    5630           0 :                                    StoreRegisterTo(objReg));
    5631             : 
    5632           0 :     bool canInline = true;
    5633           0 :     size_t inlineLength = 0;
    5634           0 :     if (templateObject->is<ArrayObject>()) {
    5635           0 :         if (templateObject->as<ArrayObject>().hasFixedElements()) {
    5636           0 :             size_t numSlots = gc::GetGCKindSlots(templateObject->asTenured().getAllocKind());
    5637           0 :             inlineLength = numSlots - ObjectElements::VALUES_PER_HEADER;
    5638             :         } else {
    5639           0 :             canInline = false;
    5640             :         }
    5641             :     } else {
    5642           0 :         if (templateObject->as<UnboxedArrayObject>().hasInlineElements()) {
    5643             :             size_t nbytes =
    5644           0 :                 templateObject->tenuredSizeOfThis() - UnboxedArrayObject::offsetOfInlineElements();
    5645           0 :             inlineLength = nbytes / templateObject->as<UnboxedArrayObject>().elementSize();
    5646             :         } else {
    5647           0 :             canInline = false;
    5648             :         }
    5649             :     }
    5650             : 
    5651           0 :     if (canInline) {
    5652             :         // Try to do the allocation inline if the template object is big enough
    5653             :         // for the length in lengthReg. If the length is bigger we could still
    5654             :         // use the template object and not allocate the elements, but it's more
    5655             :         // efficient to do a single big allocation than (repeatedly) reallocating
    5656             :         // the array later on when filling it.
    5657           0 :         masm.branch32(Assembler::Above, lengthReg, Imm32(inlineLength), ool->entry());
    5658             : 
    5659           0 :         masm.createGCObject(objReg, tempReg, templateObject, initialHeap, ool->entry());
    5660             : 
    5661           0 :         size_t lengthOffset = NativeObject::offsetOfFixedElements() + ObjectElements::offsetOfLength();
    5662           0 :         masm.store32(lengthReg, Address(objReg, lengthOffset));
    5663             :     } else {
    5664           0 :         masm.jump(ool->entry());
    5665             :     }
    5666             : 
    5667           0 :     masm.bind(ool->rejoin());
    5668           0 : }
    5669             : 
    5670             : typedef ArrayIteratorObject* (*NewArrayIteratorObjectFn)(JSContext*, NewObjectKind);
    5671           3 : static const VMFunction NewArrayIteratorObjectInfo =
    5672           6 :     FunctionInfo<NewArrayIteratorObjectFn>(NewArrayIteratorObject, "NewArrayIteratorObject");
    5673             : 
    5674             : typedef StringIteratorObject* (*NewStringIteratorObjectFn)(JSContext*, NewObjectKind);
    5675           3 : static const VMFunction NewStringIteratorObjectInfo =
    5676           6 :     FunctionInfo<NewStringIteratorObjectFn>(NewStringIteratorObject, "NewStringIteratorObject");
    5677             : 
    5678             : void
    5679           0 : CodeGenerator::visitNewIterator(LNewIterator* lir)
    5680             : {
    5681           0 :     Register objReg = ToRegister(lir->output());
    5682           0 :     Register tempReg = ToRegister(lir->temp());
    5683           0 :     JSObject* templateObject = lir->mir()->templateObject();
    5684             : 
    5685             :     OutOfLineCode* ool;
    5686           0 :     switch (lir->mir()->type()) {
    5687             :       case MNewIterator::ArrayIterator:
    5688           0 :         ool = oolCallVM(NewArrayIteratorObjectInfo, lir,
    5689           0 :                         ArgList(Imm32(GenericObject)),
    5690           0 :                         StoreRegisterTo(objReg));
    5691           0 :         break;
    5692             :       case MNewIterator::StringIterator:
    5693           0 :         ool = oolCallVM(NewStringIteratorObjectInfo, lir,
    5694           0 :                         ArgList(Imm32(GenericObject)),
    5695           0 :                         StoreRegisterTo(objReg));
    5696           0 :         break;
    5697             :       default:
    5698           0 :           MOZ_CRASH("unexpected iterator type");
    5699             :     }
    5700             : 
    5701           0 :     masm.createGCObject(objReg, tempReg, templateObject, gc::DefaultHeap, ool->entry());
    5702             : 
    5703           0 :     masm.bind(ool->rejoin());
    5704           0 : }
    5705             : 
    5706             : typedef TypedArrayObject* (*TypedArrayConstructorOneArgFn)(JSContext*, HandleObject, int32_t length);
    5707           3 : static const VMFunction TypedArrayConstructorOneArgInfo =
    5708           6 :     FunctionInfo<TypedArrayConstructorOneArgFn>(TypedArrayCreateWithTemplate,
    5709             :                                                 "TypedArrayCreateWithTemplate");
    5710             : 
    5711             : void
    5712           0 : CodeGenerator::visitNewTypedArray(LNewTypedArray* lir)
    5713             : {
    5714           0 :     Register objReg = ToRegister(lir->output());
    5715           0 :     Register tempReg = ToRegister(lir->temp1());
    5716           0 :     Register lengthReg = ToRegister(lir->temp2());
    5717           0 :     LiveRegisterSet liveRegs = lir->safepoint()->liveRegs();
    5718             : 
    5719           0 :     JSObject* templateObject = lir->mir()->templateObject();
    5720           0 :     gc::InitialHeap initialHeap = lir->mir()->initialHeap();
    5721             : 
    5722           0 :     TypedArrayObject* ttemplate = &templateObject->as<TypedArrayObject>();
    5723           0 :     uint32_t n = ttemplate->length();
    5724             : 
    5725           0 :     OutOfLineCode* ool = oolCallVM(TypedArrayConstructorOneArgInfo, lir,
    5726           0 :                                    ArgList(ImmGCPtr(templateObject), Imm32(n)),
    5727           0 :                                    StoreRegisterTo(objReg));
    5728             : 
    5729           0 :     masm.createGCObject(objReg, tempReg, templateObject, initialHeap,
    5730           0 :                         ool->entry(), /*initContents*/true, /*convertDoubleElements*/false);
    5731             : 
    5732           0 :     masm.initTypedArraySlots(objReg, tempReg, lengthReg, liveRegs, ool->entry(),
    5733           0 :                              ttemplate, TypedArrayLength::Fixed);
    5734             : 
    5735           0 :     masm.bind(ool->rejoin());
    5736           0 : }
    5737             : 
    5738             : void
    5739           0 : CodeGenerator::visitNewTypedArrayDynamicLength(LNewTypedArrayDynamicLength* lir)
    5740             : {
    5741           0 :     Register lengthReg = ToRegister(lir->length());
    5742           0 :     Register objReg = ToRegister(lir->output());
    5743           0 :     Register tempReg = ToRegister(lir->temp());
    5744           0 :     LiveRegisterSet liveRegs = lir->safepoint()->liveRegs();
    5745             : 
    5746           0 :     JSObject* templateObject = lir->mir()->templateObject();
    5747           0 :     gc::InitialHeap initialHeap = lir->mir()->initialHeap();
    5748             : 
    5749           0 :     TypedArrayObject* ttemplate = &templateObject->as<TypedArrayObject>();
    5750             : 
    5751           0 :     OutOfLineCode* ool = oolCallVM(TypedArrayConstructorOneArgInfo, lir,
    5752           0 :                                    ArgList(ImmGCPtr(templateObject), lengthReg),
    5753           0 :                                    StoreRegisterTo(objReg));
    5754             : 
    5755           0 :     masm.createGCObject(objReg, tempReg, templateObject, initialHeap,
    5756           0 :                         ool->entry(), /*initContents*/true, /*convertDoubleElements*/false);
    5757             : 
    5758           0 :     masm.initTypedArraySlots(objReg, tempReg, lengthReg, liveRegs, ool->entry(),
    5759           0 :                              ttemplate, TypedArrayLength::Dynamic);
    5760             : 
    5761           0 :     masm.bind(ool->rejoin());
    5762           0 : }
    5763             : 
    5764             : // Out-of-line object allocation for JSOP_NEWOBJECT.
    5765             : class OutOfLineNewObject : public OutOfLineCodeBase<CodeGenerator>
    5766             : {
    5767             :     LNewObject* lir_;
    5768             : 
    5769             :   public:
    5770           1 :     explicit OutOfLineNewObject(LNewObject* lir)
    5771           1 :       : lir_(lir)
    5772           1 :     { }
    5773             : 
    5774           1 :     void accept(CodeGenerator* codegen) {
    5775           1 :         codegen->visitOutOfLineNewObject(this);
    5776           1 :     }
    5777             : 
    5778           1 :     LNewObject* lir() const {
    5779           1 :         return lir_;
    5780             :     }
    5781             : };
    5782             : 
    5783             : typedef JSObject* (*NewInitObjectWithTemplateFn)(JSContext*, HandleObject);
    5784           3 : static const VMFunction NewInitObjectWithTemplateInfo =
    5785           6 :     FunctionInfo<NewInitObjectWithTemplateFn>(NewObjectOperationWithTemplate,
    5786             :                                               "NewObjectOperationWithTemplate");
    5787             : 
    5788             : typedef JSObject* (*NewInitObjectFn)(JSContext*, HandleScript, jsbytecode* pc, NewObjectKind);
    5789           3 : static const VMFunction NewInitObjectInfo =
    5790           6 :     FunctionInfo<NewInitObjectFn>(NewObjectOperation, "NewObjectOperation");
    5791             : 
    5792             : typedef PlainObject* (*ObjectCreateWithTemplateFn)(JSContext*, HandlePlainObject);
    5793           3 : static const VMFunction ObjectCreateWithTemplateInfo =
    5794           6 :     FunctionInfo<ObjectCreateWithTemplateFn>(ObjectCreateWithTemplate, "ObjectCreateWithTemplate");
    5795             : 
    5796             : void
    5797           1 : CodeGenerator::visitNewObjectVMCall(LNewObject* lir)
    5798             : {
    5799           1 :     Register objReg = ToRegister(lir->output());
    5800             : 
    5801           1 :     MOZ_ASSERT(!lir->isCall());
    5802           1 :     saveLive(lir);
    5803             : 
    5804           1 :     JSObject* templateObject = lir->mir()->templateObject();
    5805             : 
    5806             :     // If we're making a new object with a class prototype (that is, an object
    5807             :     // that derives its class from its prototype instead of being
    5808             :     // PlainObject::class_'d) from self-hosted code, we need a different init
    5809             :     // function.
    5810           1 :     switch (lir->mir()->mode()) {
    5811             :       case MNewObject::ObjectLiteral:
    5812           1 :         if (templateObject) {
    5813           1 :             pushArg(ImmGCPtr(templateObject));
    5814           1 :             callVM(NewInitObjectWithTemplateInfo, lir);
    5815             :         } else {
    5816           0 :             pushArg(Imm32(GenericObject));
    5817           0 :             pushArg(ImmPtr(lir->mir()->resumePoint()->pc()));
    5818           0 :             pushArg(ImmGCPtr(lir->mir()->block()->info().script()));
    5819           0 :             callVM(NewInitObjectInfo, lir);
    5820             :         }
    5821           1 :         break;
    5822             :       case MNewObject::ObjectCreate:
    5823           0 :         pushArg(ImmGCPtr(templateObject));
    5824           0 :         callVM(ObjectCreateWithTemplateInfo, lir);
    5825           0 :         break;
    5826             :     }
    5827             : 
    5828           1 :     if (ReturnReg != objReg)
    5829           1 :         masm.movePtr(ReturnReg, objReg);
    5830             : 
    5831           1 :     restoreLive(lir);
    5832           1 : }
    5833             : 
    5834             : static bool
    5835           3 : ShouldInitFixedSlots(LInstruction* lir, JSObject* obj)
    5836             : {
    5837           3 :     if (!obj->isNative())
    5838           0 :         return true;
    5839           3 :     NativeObject* templateObj = &obj->as<NativeObject>();
    5840             : 
    5841             :     // Look for StoreFixedSlot instructions following an object allocation
    5842             :     // that write to this object before a GC is triggered or this object is
    5843             :     // passed to a VM call. If all fixed slots will be initialized, the
    5844             :     // allocation code doesn't need to set the slots to |undefined|.
    5845             : 
    5846           3 :     uint32_t nfixed = templateObj->numUsedFixedSlots();
    5847           3 :     if (nfixed == 0)
    5848           0 :         return false;
    5849             : 
    5850             :     // Only optimize if all fixed slots are initially |undefined|, so that we
    5851             :     // can assume incremental pre-barriers are not necessary. See also the
    5852             :     // comment below.
    5853           5 :     for (uint32_t slot = 0; slot < nfixed; slot++) {
    5854           4 :         if (!templateObj->getSlot(slot).isUndefined())
    5855           2 :             return true;
    5856             :     }
    5857             : 
    5858             :     // Keep track of the fixed slots that are initialized. initializedSlots is
    5859             :     // a bit mask with a bit for each slot.
    5860           1 :     MOZ_ASSERT(nfixed <= NativeObject::MAX_FIXED_SLOTS);
    5861             :     static_assert(NativeObject::MAX_FIXED_SLOTS <= 32, "Slot bits must fit in 32 bits");
    5862           1 :     uint32_t initializedSlots = 0;
    5863           1 :     uint32_t numInitialized = 0;
    5864             : 
    5865           1 :     MInstruction* allocMir = lir->mirRaw()->toInstruction();
    5866           1 :     MBasicBlock* block = allocMir->block();
    5867             : 
    5868             :     // Skip the allocation instruction.
    5869           1 :     MInstructionIterator iter = block->begin(allocMir);
    5870           1 :     MOZ_ASSERT(*iter == allocMir);
    5871           1 :     iter++;
    5872             : 
    5873             :     while (true) {
    5874           3 :         for (; iter != block->end(); iter++) {
    5875           2 :             if (iter->isNop() || iter->isConstant() || iter->isPostWriteBarrier()) {
    5876             :                 // These instructions won't trigger a GC or read object slots.
    5877           0 :                 continue;
    5878             :             }
    5879             : 
    5880           2 :             if (iter->isStoreFixedSlot()) {
    5881           2 :                 MStoreFixedSlot* store = iter->toStoreFixedSlot();
    5882           2 :                 if (store->object() != allocMir)
    5883           0 :                     return true;
    5884             : 
    5885             :                 // We may not initialize this object slot on allocation, so the
    5886             :                 // pre-barrier could read uninitialized memory. Simply disable
    5887             :                 // the barrier for this store: the object was just initialized
    5888             :                 // so the barrier is not necessary.
    5889           2 :                 store->setNeedsBarrier(false);
    5890             : 
    5891           2 :                 uint32_t slot = store->slot();
    5892           2 :                 MOZ_ASSERT(slot < nfixed);
    5893           2 :                 if ((initializedSlots & (1 << slot)) == 0) {
    5894           2 :                     numInitialized++;
    5895           2 :                     initializedSlots |= (1 << slot);
    5896             : 
    5897           2 :                     if (numInitialized == nfixed) {
    5898             :                         // All fixed slots will be initialized.
    5899           1 :                         MOZ_ASSERT(mozilla::CountPopulation32(initializedSlots) == nfixed);
    5900           1 :                         return false;
    5901             :                     }
    5902             :                 }
    5903           1 :                 continue;
    5904             :             }
    5905             : 
    5906           0 :             if (iter->isGoto()) {
    5907           0 :                 block = iter->toGoto()->target();
    5908           0 :                 if (block->numPredecessors() != 1)
    5909           0 :                     return true;
    5910           0 :                 break;
    5911             :             }
    5912             : 
    5913             :             // Unhandled instruction, assume it bails or reads object slots.
    5914           0 :             return true;
    5915             :         }
    5916           0 :         iter = block->begin();
    5917           0 :     }
    5918             : 
    5919             :     MOZ_CRASH("Shouldn't get here");
    5920             : }
    5921             : 
    5922             : void
    5923           1 : CodeGenerator::visitNewObject(LNewObject* lir)
    5924             : {
    5925           1 :     Register objReg = ToRegister(lir->output());
    5926           1 :     Register tempReg = ToRegister(lir->temp());
    5927           1 :     JSObject* templateObject = lir->mir()->templateObject();
    5928             : 
    5929           1 :     if (lir->mir()->isVMCall()) {
    5930           0 :         visitNewObjectVMCall(lir);
    5931           0 :         return;
    5932             :     }
    5933             : 
    5934           1 :     OutOfLineNewObject* ool = new(alloc()) OutOfLineNewObject(lir);
    5935           1 :     addOutOfLineCode(ool, lir->mir());
    5936             : 
    5937           1 :     bool initContents = ShouldInitFixedSlots(lir, templateObject);
    5938           1 :     masm.createGCObject(objReg, tempReg, templateObject, lir->mir()->initialHeap(), ool->entry(),
    5939           1 :                         initContents);
    5940             : 
    5941           1 :     masm.bind(ool->rejoin());
    5942             : }
    5943             : 
    5944             : void
    5945           1 : CodeGenerator::visitOutOfLineNewObject(OutOfLineNewObject* ool)
    5946             : {
    5947           1 :     visitNewObjectVMCall(ool->lir());
    5948           1 :     masm.jump(ool->rejoin());
    5949           1 : }
    5950             : 
    5951             : typedef InlineTypedObject* (*NewTypedObjectFn)(JSContext*, Handle<InlineTypedObject*>, gc::InitialHeap);
    5952           3 : static const VMFunction NewTypedObjectInfo =
    5953           6 :     FunctionInfo<NewTypedObjectFn>(InlineTypedObject::createCopy, "InlineTypedObject::createCopy");
    5954             : 
    5955             : void
    5956           0 : CodeGenerator::visitNewTypedObject(LNewTypedObject* lir)
    5957             : {
    5958           0 :     Register object = ToRegister(lir->output());
    5959           0 :     Register temp = ToRegister(lir->temp());
    5960           0 :     InlineTypedObject* templateObject = lir->mir()->templateObject();
    5961           0 :     gc::InitialHeap initialHeap = lir->mir()->initialHeap();
    5962             : 
    5963           0 :     OutOfLineCode* ool = oolCallVM(NewTypedObjectInfo, lir,
    5964           0 :                                    ArgList(ImmGCPtr(templateObject), Imm32(initialHeap)),
    5965           0 :                                    StoreRegisterTo(object));
    5966             : 
    5967           0 :     masm.createGCObject(object, temp, templateObject, initialHeap, ool->entry());
    5968             : 
    5969           0 :     masm.bind(ool->rejoin());
    5970           0 : }
    5971             : 
    5972             : void
    5973           0 : CodeGenerator::visitSimdBox(LSimdBox* lir)
    5974             : {
    5975           0 :     FloatRegister in = ToFloatRegister(lir->input());
    5976           0 :     Register object = ToRegister(lir->output());
    5977           0 :     Register temp = ToRegister(lir->temp());
    5978           0 :     InlineTypedObject* templateObject = lir->mir()->templateObject();
    5979           0 :     gc::InitialHeap initialHeap = lir->mir()->initialHeap();
    5980           0 :     MIRType type = lir->mir()->input()->type();
    5981             : 
    5982           0 :     registerSimdTemplate(lir->mir()->simdType());
    5983             : 
    5984           0 :     MOZ_ASSERT(lir->safepoint()->liveRegs().has(in), "Save the input register across oolCallVM");
    5985           0 :     OutOfLineCode* ool = oolCallVM(NewTypedObjectInfo, lir,
    5986           0 :                                    ArgList(ImmGCPtr(templateObject), Imm32(initialHeap)),
    5987           0 :                                    StoreRegisterTo(object));
    5988             : 
    5989           0 :     masm.createGCObject(object, temp, templateObject, initialHeap, ool->entry());
    5990           0 :     masm.bind(ool->rejoin());
    5991             : 
    5992           0 :     Address objectData(object, InlineTypedObject::offsetOfDataStart());
    5993           0 :     switch (type) {
    5994             :       case MIRType::Int8x16:
    5995             :       case MIRType::Int16x8:
    5996             :       case MIRType::Int32x4:
    5997             :       case MIRType::Bool8x16:
    5998             :       case MIRType::Bool16x8:
    5999             :       case MIRType::Bool32x4:
    6000           0 :         masm.storeUnalignedSimd128Int(in, objectData);
    6001           0 :         break;
    6002             :       case MIRType::Float32x4:
    6003           0 :         masm.storeUnalignedSimd128Float(in, objectData);
    6004           0 :         break;
    6005             :       default:
    6006           0 :         MOZ_CRASH("Unknown SIMD kind when generating code for SimdBox.");
    6007             :     }
    6008           0 : }
    6009             : 
    6010             : void
    6011           0 : CodeGenerator::registerSimdTemplate(SimdType simdType)
    6012             : {
    6013           0 :     simdRefreshTemplatesDuringLink_ |= 1 << uint32_t(simdType);
    6014           0 : }
    6015             : 
    6016             : void
    6017           7 : CodeGenerator::captureSimdTemplate(JSContext* cx)
    6018             : {
    6019           7 :     JitCompartment* jitCompartment = cx->compartment()->jitCompartment();
    6020           7 :     while (simdRefreshTemplatesDuringLink_) {
    6021           0 :         uint32_t typeIndex = mozilla::CountTrailingZeroes32(simdRefreshTemplatesDuringLink_);
    6022           0 :         simdRefreshTemplatesDuringLink_ ^= 1 << typeIndex;
    6023           0 :         SimdType type = SimdType(typeIndex);
    6024             : 
    6025             :         // Note: the weak-reference on the template object should not have been
    6026             :         // garbage collected. It is either registered by IonBuilder, or verified
    6027             :         // before using it in the EagerSimdUnbox phase.
    6028           0 :         jitCompartment->registerSimdTemplateObjectFor(type);
    6029             :     }
    6030           7 : }
    6031             : 
    6032             : void
    6033           0 : CodeGenerator::visitSimdUnbox(LSimdUnbox* lir)
    6034             : {
    6035           0 :     Register object = ToRegister(lir->input());
    6036           0 :     FloatRegister simd = ToFloatRegister(lir->output());
    6037           0 :     Register temp = ToRegister(lir->temp());
    6038           0 :     Label bail;
    6039             : 
    6040             :     // obj->group()
    6041           0 :     masm.loadPtr(Address(object, JSObject::offsetOfGroup()), temp);
    6042             : 
    6043             :     // Guard that the object has the same representation as the one produced for
    6044             :     // SIMD value-type.
    6045           0 :     Address clasp(temp, ObjectGroup::offsetOfClasp());
    6046             :     static_assert(!SimdTypeDescr::Opaque, "SIMD objects are transparent");
    6047           0 :     masm.branchPtr(Assembler::NotEqual, clasp, ImmPtr(&InlineTransparentTypedObject::class_),
    6048           0 :                    &bail);
    6049             : 
    6050             :     // obj->type()->typeDescr()
    6051             :     // The previous class pointer comparison implies that the addendumKind is
    6052             :     // Addendum_TypeDescr.
    6053           0 :     masm.loadPtr(Address(temp, ObjectGroup::offsetOfAddendum()), temp);
    6054             : 
    6055             :     // Check for the /Kind/ reserved slot of the TypeDescr.  This is an Int32
    6056             :     // Value which is equivalent to the object class check.
    6057             :     static_assert(JS_DESCR_SLOT_KIND < NativeObject::MAX_FIXED_SLOTS, "Load from fixed slots");
    6058           0 :     Address typeDescrKind(temp, NativeObject::getFixedSlotOffset(JS_DESCR_SLOT_KIND));
    6059           0 :     masm.assertTestInt32(Assembler::Equal, typeDescrKind,
    6060           0 :       "MOZ_ASSERT(obj->type()->typeDescr()->getReservedSlot(JS_DESCR_SLOT_KIND).isInt32())");
    6061           0 :     masm.branch32(Assembler::NotEqual, masm.ToPayload(typeDescrKind), Imm32(js::type::Simd), &bail);
    6062             : 
    6063           0 :     SimdType type = lir->mir()->simdType();
    6064             : 
    6065             :     // Check if the SimdTypeDescr /Type/ match the specialization of this
    6066             :     // MSimdUnbox instruction.
    6067             :     static_assert(JS_DESCR_SLOT_TYPE < NativeObject::MAX_FIXED_SLOTS, "Load from fixed slots");
    6068           0 :     Address typeDescrType(temp, NativeObject::getFixedSlotOffset(JS_DESCR_SLOT_TYPE));
    6069           0 :     masm.assertTestInt32(Assembler::Equal, typeDescrType,
    6070           0 :       "MOZ_ASSERT(obj->type()->typeDescr()->getReservedSlot(JS_DESCR_SLOT_TYPE).isInt32())");
    6071           0 :     masm.branch32(Assembler::NotEqual, masm.ToPayload(typeDescrType), Imm32(int32_t(type)), &bail);
    6072             : 
    6073             :     // Load the value from the data of the InlineTypedObject.
    6074           0 :     Address objectData(object, InlineTypedObject::offsetOfDataStart());
    6075           0 :     switch (lir->mir()->type()) {
    6076             :       case MIRType::Int8x16:
    6077             :       case MIRType::Int16x8:
    6078             :       case MIRType::Int32x4:
    6079             :       case MIRType::Bool8x16:
    6080             :       case MIRType::Bool16x8:
    6081             :       case MIRType::Bool32x4:
    6082           0 :         masm.loadUnalignedSimd128Int(objectData, simd);
    6083           0 :         break;
    6084             :       case MIRType::Float32x4:
    6085           0 :         masm.loadUnalignedSimd128Float(objectData, simd);
    6086           0 :         break;
    6087             :       default:
    6088           0 :         MOZ_CRASH("The impossible happened!");
    6089             :     }
    6090             : 
    6091           0 :     bailoutFrom(&bail, lir->snapshot());
    6092           0 : }
    6093             : 
    6094             : typedef js::NamedLambdaObject* (*NewNamedLambdaObjectFn)(JSContext*, HandleFunction, gc::InitialHeap);
    6095           3 : static const VMFunction NewNamedLambdaObjectInfo =
    6096           6 :     FunctionInfo<NewNamedLambdaObjectFn>(NamedLambdaObject::createTemplateObject,
    6097             :                                          "NamedLambdaObject::createTemplateObject");
    6098             : 
    6099             : void
    6100           0 : CodeGenerator::visitNewNamedLambdaObject(LNewNamedLambdaObject* lir)
    6101             : {
    6102           0 :     Register objReg = ToRegister(lir->output());
    6103           0 :     Register tempReg = ToRegister(lir->temp());
    6104           0 :     EnvironmentObject* templateObj = lir->mir()->templateObj();
    6105           0 :     const CompileInfo& info = lir->mir()->block()->info();
    6106             : 
    6107             :     // If we have a template object, we can inline call object creation.
    6108           0 :     OutOfLineCode* ool = oolCallVM(NewNamedLambdaObjectInfo, lir,
    6109           0 :                                    ArgList(ImmGCPtr(info.funMaybeLazy()), Imm32(gc::DefaultHeap)),
    6110           0 :                                    StoreRegisterTo(objReg));
    6111             : 
    6112           0 :     bool initContents = ShouldInitFixedSlots(lir, templateObj);
    6113           0 :     masm.createGCObject(objReg, tempReg, templateObj, gc::DefaultHeap, ool->entry(),
    6114           0 :                         initContents);
    6115             : 
    6116           0 :     masm.bind(ool->rejoin());
    6117           0 : }
    6118             : 
    6119             : typedef JSObject* (*NewCallObjectFn)(JSContext*, HandleShape, HandleObjectGroup);
    6120           3 : static const VMFunction NewCallObjectInfo =
    6121           6 :     FunctionInfo<NewCallObjectFn>(NewCallObject, "NewCallObject");
    6122             : 
    6123             : void
    6124           2 : CodeGenerator::visitNewCallObject(LNewCallObject* lir)
    6125             : {
    6126           2 :     Register objReg = ToRegister(lir->output());
    6127           2 :     Register tempReg = ToRegister(lir->temp());
    6128             : 
    6129           2 :     CallObject* templateObj = lir->mir()->templateObject();
    6130             : 
    6131           2 :     OutOfLineCode* ool = oolCallVM(NewCallObjectInfo, lir,
    6132           4 :                                    ArgList(ImmGCPtr(templateObj->lastProperty()),
    6133           4 :                                            ImmGCPtr(templateObj->group())),
    6134           6 :                                    StoreRegisterTo(objReg));
    6135             : 
    6136             :     // Inline call object creation, using the OOL path only for tricky cases.
    6137           2 :     bool initContents = ShouldInitFixedSlots(lir, templateObj);
    6138           2 :     masm.createGCObject(objReg, tempReg, templateObj, gc::DefaultHeap, ool->entry(),
    6139           2 :                         initContents);
    6140             : 
    6141           2 :     masm.bind(ool->rejoin());
    6142           2 : }
    6143             : 
    6144             : typedef JSObject* (*NewSingletonCallObjectFn)(JSContext*, HandleShape);
    6145           3 : static const VMFunction NewSingletonCallObjectInfo =
    6146           6 :     FunctionInfo<NewSingletonCallObjectFn>(NewSingletonCallObject, "NewSingletonCallObject");
    6147             : 
    6148             : void
    6149           0 : CodeGenerator::visitNewSingletonCallObject(LNewSingletonCallObject* lir)
    6150             : {
    6151           0 :     Register objReg = ToRegister(lir->output());
    6152             : 
    6153           0 :     JSObject* templateObj = lir->mir()->templateObject();
    6154             : 
    6155             :     OutOfLineCode* ool;
    6156           0 :     ool = oolCallVM(NewSingletonCallObjectInfo, lir,
    6157           0 :                     ArgList(ImmGCPtr(templateObj->as<CallObject>().lastProperty())),
    6158           0 :                     StoreRegisterTo(objReg));
    6159             : 
    6160             :     // Objects can only be given singleton types in VM calls.  We make the call
    6161             :     // out of line to not bloat inline code, even if (naively) this seems like
    6162             :     // extra work.
    6163           0 :     masm.jump(ool->entry());
    6164           0 :     masm.bind(ool->rejoin());
    6165           0 : }
    6166             : 
    6167             : typedef JSObject* (*NewStringObjectFn)(JSContext*, HandleString);
    6168           3 : static const VMFunction NewStringObjectInfo =
    6169           6 :     FunctionInfo<NewStringObjectFn>(NewStringObject, "NewStringObject");
    6170             : 
    6171             : void
    6172           0 : CodeGenerator::visitNewStringObject(LNewStringObject* lir)
    6173             : {
    6174           0 :     Register input = ToRegister(lir->input());
    6175           0 :     Register output = ToRegister(lir->output());
    6176           0 :     Register temp = ToRegister(lir->temp());
    6177             : 
    6178           0 :     StringObject* templateObj = lir->mir()->templateObj();
    6179             : 
    6180           0 :     OutOfLineCode* ool = oolCallVM(NewStringObjectInfo, lir, ArgList(input),
    6181           0 :                                    StoreRegisterTo(output));
    6182             : 
    6183           0 :     masm.createGCObject(output, temp, templateObj, gc::DefaultHeap, ool->entry());
    6184             : 
    6185           0 :     masm.loadStringLength(input, temp);
    6186             : 
    6187           0 :     masm.storeValue(JSVAL_TYPE_STRING, input, Address(output, StringObject::offsetOfPrimitiveValue()));
    6188           0 :     masm.storeValue(JSVAL_TYPE_INT32, temp, Address(output, StringObject::offsetOfLength()));
    6189             : 
    6190           0 :     masm.bind(ool->rejoin());
    6191           0 : }
    6192             : 
    6193             : typedef bool(*InitElemFn)(JSContext* cx, jsbytecode* pc, HandleObject obj,
    6194             :                           HandleValue id, HandleValue value);
    6195           3 : static const VMFunction InitElemInfo =
    6196           6 :     FunctionInfo<InitElemFn>(InitElemOperation, "InitElemOperation");
    6197             : 
    6198             : void
    6199           0 : CodeGenerator::visitInitElem(LInitElem* lir)
    6200             : {
    6201           0 :     Register objReg = ToRegister(lir->getObject());
    6202             : 
    6203           0 :     pushArg(ToValue(lir, LInitElem::ValueIndex));
    6204           0 :     pushArg(ToValue(lir, LInitElem::IdIndex));
    6205           0 :     pushArg(objReg);
    6206           0 :     pushArg(ImmPtr(lir->mir()->resumePoint()->pc()));
    6207             : 
    6208           0 :     callVM(InitElemInfo, lir);
    6209           0 : }
    6210             : 
    6211             : typedef bool (*InitElemGetterSetterFn)(JSContext*, jsbytecode*, HandleObject, HandleValue,
    6212             :                                        HandleObject);
    6213           3 : static const VMFunction InitElemGetterSetterInfo =
    6214           6 :     FunctionInfo<InitElemGetterSetterFn>(InitGetterSetterOperation, "InitGetterSetterOperation");
    6215             : 
    6216             : void
    6217           0 : CodeGenerator::visitInitElemGetterSetter(LInitElemGetterSetter* lir)
    6218             : {
    6219           0 :     Register obj = ToRegister(lir->object());
    6220           0 :     Register value = ToRegister(lir->value());
    6221             : 
    6222           0 :     pushArg(value);
    6223           0 :     pushArg(ToValue(lir, LInitElemGetterSetter::IdIndex));
    6224           0 :     pushArg(obj);
    6225           0 :     pushArg(ImmPtr(lir->mir()->resumePoint()->pc()));
    6226             : 
    6227           0 :     callVM(InitElemGetterSetterInfo, lir);
    6228           0 : }
    6229             : 
    6230             : typedef bool(*MutatePrototypeFn)(JSContext* cx, HandlePlainObject obj, HandleValue value);
    6231           3 : static const VMFunction MutatePrototypeInfo =
    6232           6 :     FunctionInfo<MutatePrototypeFn>(MutatePrototype, "MutatePrototype");
    6233             : 
    6234             : void
    6235           0 : CodeGenerator::visitMutateProto(LMutateProto* lir)
    6236             : {
    6237           0 :     Register objReg = ToRegister(lir->getObject());
    6238             : 
    6239           0 :     pushArg(ToValue(lir, LMutateProto::ValueIndex));
    6240           0 :     pushArg(objReg);
    6241             : 
    6242           0 :     callVM(MutatePrototypeInfo, lir);
    6243           0 : }
    6244             : 
    6245             : typedef bool(*InitPropFn)(JSContext*, HandleObject, HandlePropertyName, HandleValue, jsbytecode* pc);
    6246           3 : static const VMFunction InitPropInfo = FunctionInfo<InitPropFn>(InitProp, "InitProp");
    6247             : 
    6248             : void
    6249           0 : CodeGenerator::visitInitProp(LInitProp* lir)
    6250             : {
    6251           0 :     Register objReg = ToRegister(lir->getObject());
    6252             : 
    6253           0 :     pushArg(ImmPtr(lir->mir()->resumePoint()->pc()));
    6254           0 :     pushArg(ToValue(lir, LInitProp::ValueIndex));
    6255           0 :     pushArg(ImmGCPtr(lir->mir()->propertyName()));
    6256           0 :     pushArg(objReg);
    6257             : 
    6258           0 :     callVM(InitPropInfo, lir);
    6259           0 : }
    6260             : 
    6261             : typedef bool(*InitPropGetterSetterFn)(JSContext*, jsbytecode*, HandleObject, HandlePropertyName,
    6262             :                                       HandleObject);
    6263           3 : static const VMFunction InitPropGetterSetterInfo =
    6264           6 :     FunctionInfo<InitPropGetterSetterFn>(InitGetterSetterOperation, "InitGetterSetterOperation");
    6265             : 
    6266             : void
    6267           0 : CodeGenerator::visitInitPropGetterSetter(LInitPropGetterSetter* lir)
    6268             : {
    6269           0 :     Register obj = ToRegister(lir->object());
    6270           0 :     Register value = ToRegister(lir->value());
    6271             : 
    6272           0 :     pushArg(value);
    6273           0 :     pushArg(ImmGCPtr(lir->mir()->name()));
    6274           0 :     pushArg(obj);
    6275           0 :     pushArg(ImmPtr(lir->mir()->resumePoint()->pc()));
    6276             : 
    6277           0 :     callVM(InitPropGetterSetterInfo, lir);
    6278           0 : }
    6279             : 
    6280             : typedef bool (*CreateThisFn)(JSContext* cx, HandleObject callee, HandleObject newTarget, MutableHandleValue rval);
    6281           3 : static const VMFunction CreateThisInfoCodeGen = FunctionInfo<CreateThisFn>(CreateThis, "CreateThis");
    6282             : 
    6283             : void
    6284           4 : CodeGenerator::visitCreateThis(LCreateThis* lir)
    6285             : {
    6286           4 :     const LAllocation* callee = lir->getCallee();
    6287           4 :     const LAllocation* newTarget = lir->getNewTarget();
    6288             : 
    6289           4 :     if (newTarget->isConstant())
    6290           0 :         pushArg(ImmGCPtr(&newTarget->toConstant()->toObject()));
    6291             :     else
    6292           4 :         pushArg(ToRegister(newTarget));
    6293             : 
    6294           4 :     if (callee->isConstant())
    6295           0 :         pushArg(ImmGCPtr(&callee->toConstant()->toObject()));
    6296             :     else
    6297           4 :         pushArg(ToRegister(callee));
    6298             : 
    6299           4 :     callVM(CreateThisInfoCodeGen, lir);
    6300           4 : }
    6301             : 
    6302             : static JSObject*
    6303           0 : CreateThisForFunctionWithProtoWrapper(JSContext* cx, HandleObject callee, HandleObject newTarget,
    6304             :                                       HandleObject proto)
    6305             : {
    6306           0 :     return CreateThisForFunctionWithProto(cx, callee, newTarget, proto);
    6307             : }
    6308             : 
    6309             : typedef JSObject* (*CreateThisWithProtoFn)(JSContext* cx, HandleObject callee,
    6310             :                                            HandleObject newTarget, HandleObject proto);
    6311           3 : static const VMFunction CreateThisWithProtoInfo =
    6312           6 :     FunctionInfo<CreateThisWithProtoFn>(CreateThisForFunctionWithProtoWrapper,
    6313             :                                         "CreateThisForFunctionWithProtoWrapper");
    6314             : 
    6315             : void
    6316           0 : CodeGenerator::visitCreateThisWithProto(LCreateThisWithProto* lir)
    6317             : {
    6318           0 :     const LAllocation* callee = lir->getCallee();
    6319           0 :     const LAllocation* newTarget = lir->getNewTarget();
    6320           0 :     const LAllocation* proto = lir->getPrototype();
    6321             : 
    6322           0 :     if (proto->isConstant())
    6323           0 :         pushArg(ImmGCPtr(&proto->toConstant()->toObject()));
    6324             :     else
    6325           0 :         pushArg(ToRegister(proto));
    6326             : 
    6327           0 :     if (newTarget->isConstant())
    6328           0 :         pushArg(ImmGCPtr(&newTarget->toConstant()->toObject()));
    6329             :     else
    6330           0 :         pushArg(ToRegister(newTarget));
    6331             : 
    6332           0 :     if (callee->isConstant())
    6333           0 :         pushArg(ImmGCPtr(&callee->toConstant()->toObject()));
    6334             :     else
    6335           0 :         pushArg(ToRegister(callee));
    6336             : 
    6337           0 :     callVM(CreateThisWithProtoInfo, lir);
    6338           0 : }
    6339             : 
    6340             : void
    6341           0 : CodeGenerator::visitCreateThisWithTemplate(LCreateThisWithTemplate* lir)
    6342             : {
    6343           0 :     JSObject* templateObject = lir->mir()->templateObject();
    6344           0 :     Register objReg = ToRegister(lir->output());
    6345           0 :     Register tempReg = ToRegister(lir->temp());
    6346             : 
    6347           0 :     OutOfLineCode* ool = oolCallVM(NewInitObjectWithTemplateInfo, lir,
    6348           0 :                                    ArgList(ImmGCPtr(templateObject)),
    6349           0 :                                    StoreRegisterTo(objReg));
    6350             : 
    6351             :     // Allocate. If the FreeList is empty, call to VM, which may GC.
    6352           0 :     bool initContents = !templateObject->is<PlainObject>() ||
    6353           0 :                         ShouldInitFixedSlots(lir, &templateObject->as<PlainObject>());
    6354           0 :     masm.createGCObject(objReg, tempReg, templateObject, lir->mir()->initialHeap(), ool->entry(),
    6355           0 :                         initContents);
    6356             : 
    6357           0 :     masm.bind(ool->rejoin());
    6358           0 : }
    6359             : 
    6360             : typedef JSObject* (*NewIonArgumentsObjectFn)(JSContext* cx, JitFrameLayout* frame, HandleObject);
    6361           3 : static const VMFunction NewIonArgumentsObjectInfo =
    6362           6 :     FunctionInfo<NewIonArgumentsObjectFn>((NewIonArgumentsObjectFn) ArgumentsObject::createForIon,
    6363             :                                           "ArgumentsObject::createForIon");
    6364             : 
    6365             : void
    6366           0 : CodeGenerator::visitCreateArgumentsObject(LCreateArgumentsObject* lir)
    6367             : {
    6368             :     // This should be getting constructed in the first block only, and not any OSR entry blocks.
    6369           0 :     MOZ_ASSERT(lir->mir()->block()->id() == 0);
    6370             : 
    6371           0 :     Register callObj = ToRegister(lir->getCallObject());
    6372           0 :     Register temp = ToRegister(lir->temp0());
    6373           0 :     Label done;
    6374             : 
    6375           0 :     if (ArgumentsObject* templateObj = lir->mir()->templateObject()) {
    6376           0 :         Register objTemp = ToRegister(lir->temp1());
    6377           0 :         Register cxTemp = ToRegister(lir->temp2());
    6378             : 
    6379           0 :         masm.Push(callObj);
    6380             : 
    6381             :         // Try to allocate an arguments object. This will leave the reserved
    6382             :         // slots uninitialized, so it's important we don't GC until we
    6383             :         // initialize these slots in ArgumentsObject::finishForIon.
    6384           0 :         Label failure;
    6385           0 :         masm.createGCObject(objTemp, temp, templateObj, gc::DefaultHeap, &failure,
    6386           0 :                             /* initContents = */ false);
    6387             : 
    6388           0 :         masm.moveStackPtrTo(temp);
    6389           0 :         masm.addPtr(Imm32(masm.framePushed()), temp);
    6390             : 
    6391           0 :         masm.setupUnalignedABICall(cxTemp);
    6392           0 :         masm.loadJSContext(cxTemp);
    6393           0 :         masm.passABIArg(cxTemp);
    6394           0 :         masm.passABIArg(temp);
    6395           0 :         masm.passABIArg(callObj);
    6396           0 :         masm.passABIArg(objTemp);
    6397             : 
    6398           0 :         masm.callWithABI(JS_FUNC_TO_DATA_PTR(void*, ArgumentsObject::finishForIon));
    6399           0 :         masm.branchTestPtr(Assembler::Zero, ReturnReg, ReturnReg, &failure);
    6400             : 
    6401             :         // Discard saved callObj on the stack.
    6402           0 :         masm.addToStackPtr(Imm32(sizeof(uintptr_t)));
    6403           0 :         masm.jump(&done);
    6404             : 
    6405           0 :         masm.bind(&failure);
    6406           0 :         masm.Pop(callObj);
    6407             :     }
    6408             : 
    6409           0 :     masm.moveStackPtrTo(temp);
    6410           0 :     masm.addPtr(Imm32(frameSize()), temp);
    6411             : 
    6412           0 :     pushArg(callObj);
    6413           0 :     pushArg(temp);
    6414           0 :     callVM(NewIonArgumentsObjectInfo, lir);
    6415             : 
    6416           0 :     masm.bind(&done);
    6417           0 : }
    6418             : 
    6419             : void
    6420           0 : CodeGenerator::visitGetArgumentsObjectArg(LGetArgumentsObjectArg* lir)
    6421             : {
    6422           0 :     Register temp = ToRegister(lir->getTemp(0));
    6423           0 :     Register argsObj = ToRegister(lir->getArgsObject());
    6424           0 :     ValueOperand out = ToOutValue(lir);
    6425             : 
    6426           0 :     masm.loadPrivate(Address(argsObj, ArgumentsObject::getDataSlotOffset()), temp);
    6427           0 :     Address argAddr(temp, ArgumentsData::offsetOfArgs() + lir->mir()->argno() * sizeof(Value));
    6428           0 :     masm.loadValue(argAddr, out);
    6429             : #ifdef DEBUG
    6430           0 :     Label success;
    6431           0 :     masm.branchTestMagic(Assembler::NotEqual, out, &success);
    6432           0 :     masm.assumeUnreachable("Result from ArgumentObject shouldn't be JSVAL_TYPE_MAGIC.");
    6433           0 :     masm.bind(&success);
    6434             : #endif
    6435           0 : }
    6436             : 
    6437             : void
    6438           0 : CodeGenerator::visitSetArgumentsObjectArg(LSetArgumentsObjectArg* lir)
    6439             : {
    6440           0 :     Register temp = ToRegister(lir->getTemp(0));
    6441           0 :     Register argsObj = ToRegister(lir->getArgsObject());
    6442           0 :     ValueOperand value = ToValue(lir, LSetArgumentsObjectArg::ValueIndex);
    6443             : 
    6444           0 :     masm.loadPrivate(Address(argsObj, ArgumentsObject::getDataSlotOffset()), temp);
    6445           0 :     Address argAddr(temp, ArgumentsData::offsetOfArgs() + lir->mir()->argno() * sizeof(Value));
    6446           0 :     emitPreBarrier(argAddr);
    6447             : #ifdef DEBUG
    6448           0 :     Label success;
    6449           0 :     masm.branchTestMagic(Assembler::NotEqual, argAddr, &success);
    6450           0 :     masm.assumeUnreachable("Result in ArgumentObject shouldn't be JSVAL_TYPE_MAGIC.");
    6451           0 :     masm.bind(&success);
    6452             : #endif
    6453           0 :     masm.storeValue(value, argAddr);
    6454           0 : }
    6455             : 
    6456             : void
    6457           0 : CodeGenerator::visitReturnFromCtor(LReturnFromCtor* lir)
    6458             : {
    6459           0 :     ValueOperand value = ToValue(lir, LReturnFromCtor::ValueIndex);
    6460           0 :     Register obj = ToRegister(lir->getObject());
    6461           0 :     Register output = ToRegister(lir->output());
    6462             : 
    6463           0 :     Label valueIsObject, end;
    6464             : 
    6465           0 :     masm.branchTestObject(Assembler::Equal, value, &valueIsObject);
    6466             : 
    6467             :     // Value is not an object. Return that other object.
    6468           0 :     masm.movePtr(obj, output);
    6469           0 :     masm.jump(&end);
    6470             : 
    6471             :     // Value is an object. Return unbox(Value).
    6472           0 :     masm.bind(&valueIsObject);
    6473           0 :     Register payload = masm.extractObject(value, output);
    6474           0 :     if (payload != output)
    6475           0 :         masm.movePtr(payload, output);
    6476             : 
    6477           0 :     masm.bind(&end);
    6478           0 : }
    6479             : 
    6480             : typedef bool (*BoxNonStrictThisFn)(JSContext*, HandleValue, MutableHandleValue);
    6481           3 : static const VMFunction BoxNonStrictThisInfo =
    6482           6 :     FunctionInfo<BoxNonStrictThisFn>(BoxNonStrictThis, "BoxNonStrictThis");
    6483             : 
    6484             : void
    6485           0 : CodeGenerator::visitComputeThis(LComputeThis* lir)
    6486             : {
    6487           0 :     ValueOperand value = ToValue(lir, LComputeThis::ValueIndex);
    6488           0 :     ValueOperand output = ToOutValue(lir);
    6489             : 
    6490           0 :     OutOfLineCode* ool = oolCallVM(BoxNonStrictThisInfo, lir, ArgList(value), StoreValueTo(output));
    6491             : 
    6492           0 :     masm.branchTestObject(Assembler::NotEqual, value, ool->entry());
    6493           0 :     masm.moveValue(value, output);
    6494           0 :     masm.bind(ool->rejoin());
    6495           0 : }
    6496             : 
    6497             : void
    6498           0 : CodeGenerator::visitArrowNewTarget(LArrowNewTarget* lir)
    6499             : {
    6500           0 :     Register callee = ToRegister(lir->callee());
    6501           0 :     ValueOperand output = ToOutValue(lir);
    6502           0 :     masm.loadValue(Address(callee, FunctionExtended::offsetOfArrowNewTargetSlot()), output);
    6503           0 : }
    6504             : 
    6505             : void
    6506           2 : CodeGenerator::visitArrayLength(LArrayLength* lir)
    6507             : {
    6508           2 :     Address length(ToRegister(lir->elements()), ObjectElements::offsetOfLength());
    6509           2 :     masm.load32(length, ToRegister(lir->output()));
    6510           2 : }
    6511             : 
    6512             : void
    6513           0 : CodeGenerator::visitSetArrayLength(LSetArrayLength* lir)
    6514             : {
    6515           0 :     Address length(ToRegister(lir->elements()), ObjectElements::offsetOfLength());
    6516           0 :     RegisterOrInt32Constant newLength = ToRegisterOrInt32Constant(lir->index());
    6517             : 
    6518           0 :     masm.inc32(&newLength);
    6519           0 :     masm.store32(newLength, length);
    6520             :     // Restore register value if it is used/captured after.
    6521           0 :     masm.dec32(&newLength);
    6522           0 : }
    6523             : 
    6524             : template <class OrderedHashTable>
    6525             : static void
    6526             : RangeFront(MacroAssembler&, Register, Register, Register);
    6527             : 
    6528             : template <>
    6529             : void
    6530           0 : RangeFront<ValueMap>(MacroAssembler& masm, Register range, Register i, Register front)
    6531             : {
    6532           0 :     masm.loadPtr(Address(range, ValueMap::Range::offsetOfHashTable()), front);
    6533           0 :     masm.loadPtr(Address(front, ValueMap::offsetOfImplData()), front);
    6534             : 
    6535           0 :     MOZ_ASSERT(ValueMap::offsetOfImplDataElement() == 0, "offsetof(Data, element) is 0");
    6536             :     static_assert(ValueMap::sizeofImplData() == 24, "sizeof(Data) is 24");
    6537           0 :     masm.mulBy3(i, i);
    6538           0 :     masm.lshiftPtr(Imm32(3), i);
    6539           0 :     masm.addPtr(i, front);
    6540           0 : }
    6541             : 
    6542             : template <>
    6543             : void
    6544           0 : RangeFront<ValueSet>(MacroAssembler& masm, Register range, Register i, Register front)
    6545             : {
    6546           0 :     masm.loadPtr(Address(range, ValueSet::Range::offsetOfHashTable()), front);
    6547           0 :     masm.loadPtr(Address(front, ValueSet::offsetOfImplData()), front);
    6548             : 
    6549           0 :     MOZ_ASSERT(ValueSet::offsetOfImplDataElement() == 0, "offsetof(Data, element) is 0");
    6550             :     static_assert(ValueSet::sizeofImplData() == 16, "sizeof(Data) is 16");
    6551           0 :     masm.lshiftPtr(Imm32(4), i);
    6552           0 :     masm.addPtr(i, front);
    6553           0 : }
    6554             : 
    6555             : template <class OrderedHashTable>
    6556             : static void
    6557           0 : RangePopFront(MacroAssembler& masm, Register range, Register front, Register dataLength,
    6558             :               Register temp)
    6559             : {
    6560           0 :     Register i = temp;
    6561             : 
    6562           0 :     masm.add32(Imm32(1), Address(range, OrderedHashTable::Range::offsetOfCount()));
    6563             : 
    6564           0 :     masm.load32(Address(range, OrderedHashTable::Range::offsetOfI()), i);
    6565           0 :     masm.add32(Imm32(1), i);
    6566             : 
    6567           0 :     Label done, seek;
    6568           0 :     masm.bind(&seek);
    6569           0 :     masm.branch32(Assembler::AboveOrEqual, i, dataLength, &done);
    6570             : 
    6571             :     // We can add sizeof(Data) to |front| to select the next element, because
    6572             :     // |front| and |range.ht.data[i]| point to the same location.
    6573           0 :     MOZ_ASSERT(OrderedHashTable::offsetOfImplDataElement() == 0, "offsetof(Data, element) is 0");
    6574           0 :     masm.addPtr(Imm32(OrderedHashTable::sizeofImplData()), front);
    6575             : 
    6576           0 :     masm.branchTestMagic(Assembler::NotEqual, Address(front, OrderedHashTable::offsetOfEntryKey()),
    6577             :                          JS_HASH_KEY_EMPTY, &done);
    6578             : 
    6579           0 :     masm.add32(Imm32(1), i);
    6580           0 :     masm.jump(&seek);
    6581             : 
    6582           0 :     masm.bind(&done);
    6583           0 :     masm.store32(i, Address(range, OrderedHashTable::Range::offsetOfI()));
    6584           0 : }
    6585             : 
    6586             : template <class OrderedHashTable>
    6587             : static inline void
    6588           0 : RangeDestruct(MacroAssembler& masm, Register range, Register temp0, Register temp1)
    6589             : {
    6590           0 :     Register next = temp0;
    6591           0 :     Register prevp = temp1;
    6592             : 
    6593           0 :     masm.loadPtr(Address(range, OrderedHashTable::Range::offsetOfNext()), next);
    6594           0 :     masm.loadPtr(Address(range, OrderedHashTable::Range::offsetOfPrevP()), prevp);
    6595           0 :     masm.storePtr(next, Address(prevp, 0));
    6596             : 
    6597           0 :     Label hasNoNext;
    6598           0 :     masm.branchTestPtr(Assembler::Zero, next, next, &hasNoNext);
    6599             : 
    6600           0 :     masm.storePtr(prevp, Address(next, OrderedHashTable::Range::offsetOfPrevP()));
    6601             : 
    6602           0 :     masm.bind(&hasNoNext);
    6603             : 
    6604           0 :     masm.callFreeStub(range);
    6605           0 : }
    6606             : 
    6607             : template <>
    6608             : void
    6609           0 : CodeGenerator::emitLoadIteratorValues<ValueMap>(Register result, Register temp, Register front)
    6610             : {
    6611           0 :     size_t elementsOffset = NativeObject::offsetOfFixedElements();
    6612             : 
    6613           0 :     Address keyAddress(front, ValueMap::Entry::offsetOfKey());
    6614           0 :     Address valueAddress(front, ValueMap::Entry::offsetOfValue());
    6615           0 :     Address keyElemAddress(result, elementsOffset);
    6616           0 :     Address valueElemAddress(result, elementsOffset + sizeof(Value));
    6617           0 :     masm.guardedCallPreBarrier(keyElemAddress, MIRType::Value);
    6618           0 :     masm.guardedCallPreBarrier(valueElemAddress, MIRType::Value);
    6619           0 :     masm.storeValue(keyAddress, keyElemAddress, temp);
    6620           0 :     masm.storeValue(valueAddress, valueElemAddress, temp);
    6621             : 
    6622           0 :     Label keyIsNotObject, valueIsNotNurseryObject, emitBarrier;
    6623           0 :     masm.branchTestObject(Assembler::NotEqual, keyAddress, &keyIsNotObject);
    6624           0 :     masm.branchValueIsNurseryObject(Assembler::Equal, keyAddress, temp, &emitBarrier);
    6625           0 :     masm.bind(&keyIsNotObject);
    6626           0 :     masm.branchTestObject(Assembler::NotEqual, valueAddress, &valueIsNotNurseryObject);
    6627           0 :     masm.branchValueIsNurseryObject(Assembler::NotEqual, valueAddress, temp,
    6628           0 :                                     &valueIsNotNurseryObject);
    6629             :     {
    6630           0 :         masm.bind(&emitBarrier);
    6631           0 :         saveVolatile(temp);
    6632           0 :         emitPostWriteBarrier(result);
    6633           0 :         restoreVolatile(temp);
    6634             :     }
    6635           0 :     masm.bind(&valueIsNotNurseryObject);
    6636           0 : }
    6637             : 
    6638             : template <>
    6639             : void
    6640           0 : CodeGenerator::emitLoadIteratorValues<ValueSet>(Register result, Register temp, Register front)
    6641             : {
    6642           0 :     size_t elementsOffset = NativeObject::offsetOfFixedElements();
    6643             : 
    6644           0 :     Address keyAddress(front, ValueSet::offsetOfEntryKey());
    6645           0 :     Address keyElemAddress(result, elementsOffset);
    6646           0 :     masm.guardedCallPreBarrier(keyElemAddress, MIRType::Value);
    6647           0 :     masm.storeValue(keyAddress, keyElemAddress, temp);
    6648             : 
    6649           0 :     Label keyIsNotObject;
    6650           0 :     masm.branchTestObject(Assembler::NotEqual, keyAddress, &keyIsNotObject);
    6651           0 :     masm.branchValueIsNurseryObject(Assembler::NotEqual, keyAddress, temp, &keyIsNotObject);
    6652             :     {
    6653           0 :         saveVolatile(temp);
    6654           0 :         emitPostWriteBarrier(result);
    6655           0 :         restoreVolatile(temp);
    6656             :     }
    6657           0 :     masm.bind(&keyIsNotObject);
    6658           0 : }
    6659             : 
    6660             : template <class IteratorObject, class OrderedHashTable>
    6661             : void
    6662           0 : CodeGenerator::emitGetNextEntryForIterator(LGetNextEntryForIterator* lir)
    6663             : {
    6664           0 :     Register iter = ToRegister(lir->iter());
    6665           0 :     Register result = ToRegister(lir->result());
    6666           0 :     Register temp = ToRegister(lir->temp0());
    6667           0 :     Register dataLength = ToRegister(lir->temp1());
    6668           0 :     Register range = ToRegister(lir->temp2());
    6669           0 :     Register output = ToRegister(lir->output());
    6670             : 
    6671           0 :     masm.loadPrivate(Address(iter, NativeObject::getFixedSlotOffset(IteratorObject::RangeSlot)),
    6672             :                      range);
    6673             : 
    6674           0 :     Label iterAlreadyDone, iterDone, done;
    6675           0 :     masm.branchTestPtr(Assembler::Zero, range, range, &iterAlreadyDone);
    6676             : 
    6677           0 :     masm.load32(Address(range, OrderedHashTable::Range::offsetOfI()), temp);
    6678           0 :     masm.loadPtr(Address(range, OrderedHashTable::Range::offsetOfHashTable()), dataLength);
    6679           0 :     masm.load32(Address(dataLength, OrderedHashTable::offsetOfImplDataLength()), dataLength);
    6680           0 :     masm.branch32(Assembler::AboveOrEqual, temp, dataLength, &iterDone);
    6681             :     {
    6682           0 :         masm.push(iter);
    6683             : 
    6684           0 :         Register front = iter;
    6685           0 :         RangeFront<OrderedHashTable>(masm, range, temp, front);
    6686             : 
    6687           0 :         emitLoadIteratorValues<OrderedHashTable>(result, temp, front);
    6688             : 
    6689           0 :         RangePopFront<OrderedHashTable>(masm, range, front, dataLength, temp);
    6690             : 
    6691           0 :         masm.pop(iter);
    6692           0 :         masm.move32(Imm32(0), output);
    6693             :     }
    6694           0 :     masm.jump(&done);
    6695             :     {
    6696           0 :         masm.bind(&iterDone);
    6697             : 
    6698           0 :         RangeDestruct<OrderedHashTable>(masm, range, temp, dataLength);
    6699             : 
    6700           0 :         masm.storeValue(PrivateValue(nullptr),
    6701           0 :                         Address(iter, NativeObject::getFixedSlotOffset(IteratorObject::RangeSlot)));
    6702             : 
    6703           0 :         masm.bind(&iterAlreadyDone);
    6704             : 
    6705           0 :         masm.move32(Imm32(1), output);
    6706             :     }
    6707           0 :     masm.bind(&done);
    6708           0 : }
    6709             : 
    6710             : void
    6711           0 : CodeGenerator::visitGetNextEntryForIterator(LGetNextEntryForIterator* lir)
    6712             : {
    6713           0 :     if (lir->mir()->mode() == MGetNextEntryForIterator::Map) {
    6714           0 :         emitGetNextEntryForIterator<MapIteratorObject, ValueMap>(lir);
    6715             :     } else {
    6716           0 :         MOZ_ASSERT(lir->mir()->mode() == MGetNextEntryForIterator::Set);
    6717           0 :         emitGetNextEntryForIterator<SetIteratorObject, ValueSet>(lir);
    6718             :     }
    6719           0 : }
    6720             : 
    6721             : void
    6722           0 : CodeGenerator::visitTypedArrayLength(LTypedArrayLength* lir)
    6723             : {
    6724           0 :     Register obj = ToRegister(lir->object());
    6725           0 :     Register out = ToRegister(lir->output());
    6726           0 :     masm.unboxInt32(Address(obj, TypedArrayObject::lengthOffset()), out);
    6727           0 : }
    6728             : 
    6729             : void
    6730           0 : CodeGenerator::visitTypedArrayElements(LTypedArrayElements* lir)
    6731             : {
    6732           0 :     Register obj = ToRegister(lir->object());
    6733           0 :     Register out = ToRegister(lir->output());
    6734           0 :     masm.loadPtr(Address(obj, TypedArrayObject::dataOffset()), out);
    6735           0 : }
    6736             : 
    6737             : void
    6738           0 : CodeGenerator::visitSetDisjointTypedElements(LSetDisjointTypedElements* lir)
    6739             : {
    6740           0 :     Register target = ToRegister(lir->target());
    6741           0 :     Register targetOffset = ToRegister(lir->targetOffset());
    6742           0 :     Register source = ToRegister(lir->source());
    6743             : 
    6744           0 :     Register temp = ToRegister(lir->temp());
    6745             : 
    6746           0 :     masm.setupUnalignedABICall(temp);
    6747           0 :     masm.passABIArg(target);
    6748           0 :     masm.passABIArg(targetOffset);
    6749           0 :     masm.passABIArg(source);
    6750           0 :     masm.callWithABI(JS_FUNC_TO_DATA_PTR(void*, js::SetDisjointTypedElements));
    6751           0 : }
    6752             : 
    6753             : void
    6754           0 : CodeGenerator::visitTypedObjectDescr(LTypedObjectDescr* lir)
    6755             : {
    6756           0 :     Register obj = ToRegister(lir->object());
    6757           0 :     Register out = ToRegister(lir->output());
    6758             : 
    6759           0 :     masm.loadPtr(Address(obj, JSObject::offsetOfGroup()), out);
    6760           0 :     masm.loadPtr(Address(out, ObjectGroup::offsetOfAddendum()), out);
    6761           0 : }
    6762             : 
    6763             : void
    6764           0 : CodeGenerator::visitTypedObjectElements(LTypedObjectElements* lir)
    6765             : {
    6766           0 :     Register obj = ToRegister(lir->object());
    6767           0 :     Register out = ToRegister(lir->output());
    6768             : 
    6769           0 :     if (lir->mir()->definitelyOutline()) {
    6770           0 :         masm.loadPtr(Address(obj, OutlineTypedObject::offsetOfData()), out);
    6771             :     } else {
    6772           0 :         Label inlineObject, done;
    6773           0 :         masm.loadObjClass(obj, out);
    6774           0 :         masm.branchPtr(Assembler::Equal, out, ImmPtr(&InlineOpaqueTypedObject::class_), &inlineObject);
    6775           0 :         masm.branchPtr(Assembler::Equal, out, ImmPtr(&InlineTransparentTypedObject::class_), &inlineObject);
    6776             : 
    6777           0 :         masm.loadPtr(Address(obj, OutlineTypedObject::offsetOfData()), out);
    6778           0 :         masm.jump(&done);
    6779             : 
    6780           0 :         masm.bind(&inlineObject);
    6781           0 :         masm.computeEffectiveAddress(Address(obj, InlineTypedObject::offsetOfDataStart()), out);
    6782           0 :         masm.bind(&done);
    6783             :     }
    6784           0 : }
    6785             : 
    6786             : void
    6787           0 : CodeGenerator::visitSetTypedObjectOffset(LSetTypedObjectOffset* lir)
    6788             : {
    6789           0 :     Register object = ToRegister(lir->object());
    6790           0 :     Register offset = ToRegister(lir->offset());
    6791           0 :     Register temp0 = ToRegister(lir->temp0());
    6792           0 :     Register temp1 = ToRegister(lir->temp1());
    6793             : 
    6794             :     // Compute the base pointer for the typed object's owner.
    6795           0 :     masm.loadPtr(Address(object, OutlineTypedObject::offsetOfOwner()), temp0);
    6796             : 
    6797           0 :     Label inlineObject, done;
    6798           0 :     masm.loadObjClass(temp0, temp1);
    6799           0 :     masm.branchPtr(Assembler::Equal, temp1, ImmPtr(&InlineOpaqueTypedObject::class_), &inlineObject);
    6800           0 :     masm.branchPtr(Assembler::Equal, temp1, ImmPtr(&InlineTransparentTypedObject::class_), &inlineObject);
    6801             : 
    6802           0 :     masm.loadPrivate(Address(temp0, ArrayBufferObject::offsetOfDataSlot()), temp0);
    6803           0 :     masm.jump(&done);
    6804             : 
    6805           0 :     masm.bind(&inlineObject);
    6806           0 :     masm.addPtr(ImmWord(InlineTypedObject::offsetOfDataStart()), temp0);
    6807             : 
    6808           0 :     masm.bind(&done);
    6809             : 
    6810             :     // Compute the new data pointer and set it in the object.
    6811           0 :     masm.addPtr(offset, temp0);
    6812           0 :     masm.storePtr(temp0, Address(object, OutlineTypedObject::offsetOfData()));
    6813           0 : }
    6814             : 
    6815             : void
    6816           8 : CodeGenerator::visitStringLength(LStringLength* lir)
    6817             : {
    6818           8 :     Register input = ToRegister(lir->string());
    6819           8 :     Register output = ToRegister(lir->output());
    6820             : 
    6821           8 :     masm.loadStringLength(input, output);
    6822           8 : }
    6823             : 
    6824             : void
    6825           5 : CodeGenerator::visitMinMaxI(LMinMaxI* ins)
    6826             : {
    6827           5 :     Register first = ToRegister(ins->first());
    6828           5 :     Register output = ToRegister(ins->output());
    6829             : 
    6830           5 :     MOZ_ASSERT(first == output);
    6831             : 
    6832          10 :     Label done;
    6833           5 :     Assembler::Condition cond = ins->mir()->isMax()
    6834           5 :                                 ? Assembler::GreaterThan
    6835           5 :                                 : Assembler::LessThan;
    6836             : 
    6837           5 :     if (ins->second()->isConstant()) {
    6838           5 :         masm.branch32(cond, first, Imm32(ToInt32(ins->second())), &done);
    6839           5 :         masm.move32(Imm32(ToInt32(ins->second())), output);
    6840             :     } else {
    6841           0 :         masm.branch32(cond, first, ToRegister(ins->second()), &done);
    6842           0 :         masm.move32(ToRegister(ins->second()), output);
    6843             :     }
    6844             : 
    6845           5 :     masm.bind(&done);
    6846           5 : }
    6847             : 
    6848             : void
    6849           0 : CodeGenerator::visitAbsI(LAbsI* ins)
    6850             : {
    6851           0 :     Register input = ToRegister(ins->input());
    6852           0 :     Label positive;
    6853             : 
    6854           0 :     MOZ_ASSERT(input == ToRegister(ins->output()));
    6855           0 :     masm.branchTest32(Assembler::NotSigned, input, input, &positive);
    6856           0 :     masm.neg32(input);
    6857           0 :     LSnapshot* snapshot = ins->snapshot();
    6858             : #if defined(JS_CODEGEN_MIPS32) || defined(JS_CODEGEN_MIPS64)
    6859             :     if (snapshot)
    6860             :         bailoutCmp32(Assembler::Equal, input, Imm32(INT32_MIN), snapshot);
    6861             : #else
    6862           0 :     if (snapshot)
    6863           0 :         bailoutIf(Assembler::Overflow, snapshot);
    6864             : #endif
    6865           0 :     masm.bind(&positive);
    6866           0 : }
    6867             : 
    6868             : void
    6869           0 : CodeGenerator::visitPowI(LPowI* ins)
    6870             : {
    6871           0 :     FloatRegister value = ToFloatRegister(ins->value());
    6872           0 :     Register power = ToRegister(ins->power());
    6873           0 :     Register temp = ToRegister(ins->temp());
    6874             : 
    6875           0 :     MOZ_ASSERT(power != temp);
    6876             : 
    6877           0 :     masm.setupUnalignedABICall(temp);
    6878           0 :     masm.passABIArg(value, MoveOp::DOUBLE);
    6879           0 :     masm.passABIArg(power);
    6880             : 
    6881           0 :     masm.callWithABI(JS_FUNC_TO_DATA_PTR(void*, js::powi), MoveOp::DOUBLE);
    6882           0 :     MOZ_ASSERT(ToFloatRegister(ins->output()) == ReturnDoubleReg);
    6883           0 : }
    6884             : 
    6885             : void
    6886           0 : CodeGenerator::visitPowD(LPowD* ins)
    6887             : {
    6888           0 :     FloatRegister value = ToFloatRegister(ins->value());
    6889           0 :     FloatRegister power = ToFloatRegister(ins->power());
    6890           0 :     Register temp = ToRegister(ins->temp());
    6891             : 
    6892           0 :     masm.setupUnalignedABICall(temp);
    6893           0 :     masm.passABIArg(value, MoveOp::DOUBLE);
    6894           0 :     masm.passABIArg(power, MoveOp::DOUBLE);
    6895           0 :     masm.callWithABI(JS_FUNC_TO_DATA_PTR(void*, ecmaPow), MoveOp::DOUBLE);
    6896             : 
    6897           0 :     MOZ_ASSERT(ToFloatRegister(ins->output()) == ReturnDoubleReg);
    6898           0 : }
    6899             : 
    6900             : using PowFn = bool (*)(JSContext*, HandleValue, HandleValue, MutableHandleValue);
    6901           3 : static const VMFunction PowInfo =
    6902           6 :     FunctionInfo<PowFn>(js::math_pow_handle, "math_pow_handle");
    6903             : 
    6904             : void
    6905           0 : CodeGenerator::visitPowV(LPowV* ins)
    6906             : {
    6907           0 :     pushArg(ToValue(ins, LPowV::PowerInput));
    6908           0 :     pushArg(ToValue(ins, LPowV::ValueInput));
    6909           0 :     callVM(PowInfo, ins);
    6910           0 : }
    6911             : 
    6912             : void
    6913           0 : CodeGenerator::visitMathFunctionD(LMathFunctionD* ins)
    6914             : {
    6915           0 :     Register temp = ToRegister(ins->temp());
    6916           0 :     FloatRegister input = ToFloatRegister(ins->input());
    6917           0 :     MOZ_ASSERT(ToFloatRegister(ins->output()) == ReturnDoubleReg);
    6918             : 
    6919           0 :     masm.setupUnalignedABICall(temp);
    6920             : 
    6921           0 :     const MathCache* mathCache = ins->mir()->cache();
    6922           0 :     if (mathCache) {
    6923           0 :         masm.movePtr(ImmPtr(mathCache), temp);
    6924           0 :         masm.passABIArg(temp);
    6925             :     }
    6926           0 :     masm.passABIArg(input, MoveOp::DOUBLE);
    6927             : 
    6928             : #   define MAYBE_CACHED(fcn) (mathCache ? (void*)fcn ## _impl : (void*)fcn ## _uncached)
    6929             : 
    6930           0 :     void* funptr = nullptr;
    6931           0 :     switch (ins->mir()->function()) {
    6932             :       case MMathFunction::Log:
    6933           0 :         funptr = JS_FUNC_TO_DATA_PTR(void*, MAYBE_CACHED(js::math_log));
    6934           0 :         break;
    6935             :       case MMathFunction::Sin:
    6936           0 :         funptr = JS_FUNC_TO_DATA_PTR(void*, MAYBE_CACHED(js::math_sin));
    6937           0 :         break;
    6938             :       case MMathFunction::Cos:
    6939           0 :         funptr = JS_FUNC_TO_DATA_PTR(void*, MAYBE_CACHED(js::math_cos));
    6940           0 :         break;
    6941             :       case MMathFunction::Exp:
    6942           0 :         funptr = JS_FUNC_TO_DATA_PTR(void*, MAYBE_CACHED(js::math_exp));
    6943           0 :         break;
    6944             :       case MMathFunction::Tan:
    6945           0 :         funptr = JS_FUNC_TO_DATA_PTR(void*, MAYBE_CACHED(js::math_tan));
    6946           0 :         break;
    6947             :       case MMathFunction::ATan:
    6948           0 :         funptr = JS_FUNC_TO_DATA_PTR(void*, MAYBE_CACHED(js::math_atan));
    6949           0 :         break;
    6950             :       case MMathFunction::ASin:
    6951           0 :         funptr = JS_FUNC_TO_DATA_PTR(void*, MAYBE_CACHED(js::math_asin));
    6952           0 :         break;
    6953             :       case MMathFunction::ACos:
    6954           0 :         funptr = JS_FUNC_TO_DATA_PTR(void*, MAYBE_CACHED(js::math_acos));
    6955           0 :         break;
    6956             :       case MMathFunction::Log10:
    6957           0 :         funptr = JS_FUNC_TO_DATA_PTR(void*, MAYBE_CACHED(js::math_log10));
    6958           0 :         break;
    6959             :       case MMathFunction::Log2:
    6960           0 :         funptr = JS_FUNC_TO_DATA_PTR(void*, MAYBE_CACHED(js::math_log2));
    6961           0 :         break;
    6962             :       case MMathFunction::Log1P:
    6963           0 :         funptr = JS_FUNC_TO_DATA_PTR(void*, MAYBE_CACHED(js::math_log1p));
    6964           0 :         break;
    6965             :       case MMathFunction::ExpM1:
    6966           0 :         funptr = JS_FUNC_TO_DATA_PTR(void*, MAYBE_CACHED(js::math_expm1));
    6967           0 :         break;
    6968             :       case MMathFunction::CosH:
    6969           0 :         funptr = JS_FUNC_TO_DATA_PTR(void*, MAYBE_CACHED(js::math_cosh));
    6970           0 :         break;
    6971             :       case MMathFunction::SinH:
    6972           0 :         funptr = JS_FUNC_TO_DATA_PTR(void*, MAYBE_CACHED(js::math_sinh));
    6973           0 :         break;
    6974             :       case MMathFunction::TanH:
    6975           0 :         funptr = JS_FUNC_TO_DATA_PTR(void*, MAYBE_CACHED(js::math_tanh));
    6976           0 :         break;
    6977             :       case MMathFunction::ACosH:
    6978           0 :         funptr = JS_FUNC_TO_DATA_PTR(void*, MAYBE_CACHED(js::math_acosh));
    6979           0 :         break;
    6980             :       case MMathFunction::ASinH:
    6981           0 :         funptr = JS_FUNC_TO_DATA_PTR(void*, MAYBE_CACHED(js::math_asinh));
    6982           0 :         break;
    6983             :       case MMathFunction::ATanH:
    6984           0 :         funptr = JS_FUNC_TO_DATA_PTR(void*, MAYBE_CACHED(js::math_atanh));
    6985           0 :         break;
    6986             :       case MMathFunction::Sign:
    6987           0 :         funptr = JS_FUNC_TO_DATA_PTR(void*, MAYBE_CACHED(js::math_sign));
    6988           0 :         break;
    6989             :       case MMathFunction::Trunc:
    6990           0 :         funptr = JS_FUNC_TO_DATA_PTR(void*, MAYBE_CACHED(js::math_trunc));
    6991           0 :         break;
    6992             :       case MMathFunction::Cbrt:
    6993           0 :         funptr = JS_FUNC_TO_DATA_PTR(void*, MAYBE_CACHED(js::math_cbrt));
    6994           0 :         break;
    6995             :       case MMathFunction::Floor:
    6996           0 :         funptr = JS_FUNC_TO_DATA_PTR(void*, js::math_floor_impl);
    6997           0 :         break;
    6998             :       case MMathFunction::Ceil:
    6999           0 :         funptr = JS_FUNC_TO_DATA_PTR(void*, js::math_ceil_impl);
    7000           0 :         break;
    7001             :       case MMathFunction::Round:
    7002           0 :         funptr = JS_FUNC_TO_DATA_PTR(void*, js::math_round_impl);
    7003           0 :         break;
    7004             :       default:
    7005           0 :         MOZ_CRASH("Unknown math function");
    7006             :     }
    7007             : 
    7008             : #   undef MAYBE_CACHED
    7009             : 
    7010           0 :     masm.callWithABI(funptr, MoveOp::DOUBLE);
    7011           0 : }
    7012             : 
    7013             : void
    7014           0 : CodeGenerator::visitMathFunctionF(LMathFunctionF* ins)
    7015             : {
    7016           0 :     Register temp = ToRegister(ins->temp());
    7017           0 :     FloatRegister input = ToFloatRegister(ins->input());
    7018           0 :     MOZ_ASSERT(ToFloatRegister(ins->output()) == ReturnFloat32Reg);
    7019             : 
    7020           0 :     masm.setupUnalignedABICall(temp);
    7021           0 :     masm.passABIArg(input, MoveOp::FLOAT32);
    7022             : 
    7023           0 :     void* funptr = nullptr;
    7024           0 :     switch (ins->mir()->function()) {
    7025           0 :       case MMathFunction::Floor: funptr = JS_FUNC_TO_DATA_PTR(void*, floorf);           break;
    7026           0 :       case MMathFunction::Round: funptr = JS_FUNC_TO_DATA_PTR(void*, math_roundf_impl); break;
    7027           0 :       case MMathFunction::Ceil:  funptr = JS_FUNC_TO_DATA_PTR(void*, ceilf);            break;
    7028             :       default:
    7029           0 :         MOZ_CRASH("Unknown or unsupported float32 math function");
    7030             :     }
    7031             : 
    7032           0 :     masm.callWithABI(funptr, MoveOp::FLOAT32);
    7033           0 : }
    7034             : 
    7035             : void
    7036           0 : CodeGenerator::visitModD(LModD* ins)
    7037             : {
    7038           0 :     FloatRegister lhs = ToFloatRegister(ins->lhs());
    7039           0 :     FloatRegister rhs = ToFloatRegister(ins->rhs());
    7040             : 
    7041           0 :     MOZ_ASSERT(ToFloatRegister(ins->output()) == ReturnDoubleReg);
    7042           0 :     MOZ_ASSERT(ins->temp()->isBogusTemp() == gen->compilingWasm());
    7043             : 
    7044           0 :     if (gen->compilingWasm()) {
    7045           0 :         masm.setupWasmABICall();
    7046           0 :         masm.passABIArg(lhs, MoveOp::DOUBLE);
    7047           0 :         masm.passABIArg(rhs, MoveOp::DOUBLE);
    7048           0 :         masm.callWithABI(ins->mir()->bytecodeOffset(), wasm::SymbolicAddress::ModD, MoveOp::DOUBLE);
    7049             :     } else {
    7050           0 :         masm.setupUnalignedABICall(ToRegister(ins->temp()));
    7051           0 :         masm.passABIArg(lhs, MoveOp::DOUBLE);
    7052           0 :         masm.passABIArg(rhs, MoveOp::DOUBLE);
    7053           0 :         masm.callWithABI(JS_FUNC_TO_DATA_PTR(void*, NumberMod), MoveOp::DOUBLE);
    7054             :     }
    7055           0 : }
    7056             : 
    7057             : typedef bool (*BinaryFn)(JSContext*, MutableHandleValue, MutableHandleValue, MutableHandleValue);
    7058             : 
    7059           3 : static const VMFunction AddInfo = FunctionInfo<BinaryFn>(js::AddValues, "AddValues");
    7060           3 : static const VMFunction SubInfo = FunctionInfo<BinaryFn>(js::SubValues, "SubValues");
    7061           3 : static const VMFunction MulInfo = FunctionInfo<BinaryFn>(js::MulValues, "MulValues");
    7062           3 : static const VMFunction DivInfo = FunctionInfo<BinaryFn>(js::DivValues, "DivValues");
    7063           3 : static const VMFunction ModInfo = FunctionInfo<BinaryFn>(js::ModValues, "ModValues");
    7064           3 : static const VMFunction UrshInfo = FunctionInfo<BinaryFn>(js::UrshValues, "UrshValues");
    7065             : 
    7066             : void
    7067           0 : CodeGenerator::visitBinaryV(LBinaryV* lir)
    7068             : {
    7069           0 :     pushArg(ToValue(lir, LBinaryV::RhsInput));
    7070           0 :     pushArg(ToValue(lir, LBinaryV::LhsInput));
    7071             : 
    7072           0 :     switch (lir->jsop()) {
    7073             :       case JSOP_ADD:
    7074           0 :         callVM(AddInfo, lir);
    7075           0 :         break;
    7076             : 
    7077             :       case JSOP_SUB:
    7078           0 :         callVM(SubInfo, lir);
    7079           0 :         break;
    7080             : 
    7081             :       case JSOP_MUL:
    7082           0 :         callVM(MulInfo, lir);
    7083           0 :         break;
    7084             : 
    7085             :       case JSOP_DIV:
    7086           0 :         callVM(DivInfo, lir);
    7087           0 :         break;
    7088             : 
    7089             :       case JSOP_MOD:
    7090           0 :         callVM(ModInfo, lir);
    7091           0 :         break;
    7092             : 
    7093             :       case JSOP_URSH:
    7094           0 :         callVM(UrshInfo, lir);
    7095           0 :         break;
    7096             : 
    7097             :       default:
    7098           0 :         MOZ_CRASH("Unexpected binary op");
    7099             :     }
    7100           0 : }
    7101             : 
    7102             : typedef bool (*StringCompareFn)(JSContext*, HandleString, HandleString, bool*);
    7103           3 : static const VMFunction StringsEqualInfo =
    7104           6 :     FunctionInfo<StringCompareFn>(jit::StringsEqual<true>, "StringsEqual");
    7105           3 : static const VMFunction StringsNotEqualInfo =
    7106           6 :     FunctionInfo<StringCompareFn>(jit::StringsEqual<false>, "StringsEqual");
    7107             : 
    7108             : void
    7109           0 : CodeGenerator::emitCompareS(LInstruction* lir, JSOp op, Register left, Register right,
    7110             :                             Register output)
    7111             : {
    7112           0 :     MOZ_ASSERT(lir->isCompareS() || lir->isCompareStrictS());
    7113             : 
    7114           0 :     OutOfLineCode* ool = nullptr;
    7115             : 
    7116           0 :     if (op == JSOP_EQ || op == JSOP_STRICTEQ) {
    7117           0 :         ool = oolCallVM(StringsEqualInfo, lir, ArgList(left, right),  StoreRegisterTo(output));
    7118             :     } else {
    7119           0 :         MOZ_ASSERT(op == JSOP_NE || op == JSOP_STRICTNE);
    7120           0 :         ool = oolCallVM(StringsNotEqualInfo, lir, ArgList(left, right), StoreRegisterTo(output));
    7121             :     }
    7122             : 
    7123           0 :     masm.compareStrings(op, left, right, output, ool->entry());
    7124             : 
    7125           0 :     masm.bind(ool->rejoin());
    7126           0 : }
    7127             : 
    7128             : void
    7129           0 : CodeGenerator::visitCompareStrictS(LCompareStrictS* lir)
    7130             : {
    7131           0 :     JSOp op = lir->mir()->jsop();
    7132           0 :     MOZ_ASSERT(op == JSOP_STRICTEQ || op == JSOP_STRICTNE);
    7133             : 
    7134           0 :     const ValueOperand leftV = ToValue(lir, LCompareStrictS::Lhs);
    7135           0 :     Register right = ToRegister(lir->right());
    7136           0 :     Register output = ToRegister(lir->output());
    7137           0 :     Register tempToUnbox = ToTempUnboxRegister(lir->tempToUnbox());
    7138             : 
    7139           0 :     Label string, done;
    7140             : 
    7141           0 :     masm.branchTestString(Assembler::Equal, leftV, &string);
    7142           0 :     masm.move32(Imm32(op == JSOP_STRICTNE), output);
    7143           0 :     masm.jump(&done);
    7144             : 
    7145           0 :     masm.bind(&string);
    7146           0 :     Register left = masm.extractString(leftV, tempToUnbox);
    7147           0 :     emitCompareS(lir, op, left, right, output);
    7148             : 
    7149           0 :     masm.bind(&done);
    7150           0 : }
    7151             : 
    7152             : void
    7153           0 : CodeGenerator::visitCompareS(LCompareS* lir)
    7154             : {
    7155           0 :     JSOp op = lir->mir()->jsop();
    7156           0 :     Register left = ToRegister(lir->left());
    7157           0 :     Register right = ToRegister(lir->right());
    7158           0 :     Register output = ToRegister(lir->output());
    7159             : 
    7160           0 :     emitCompareS(lir, op, left, right, output);
    7161           0 : }
    7162             : 
    7163             : typedef bool (*CompareFn)(JSContext*, MutableHandleValue, MutableHandleValue, bool*);
    7164           3 : static const VMFunction EqInfo =
    7165           6 :     FunctionInfo<CompareFn>(jit::LooselyEqual<true>, "LooselyEqual");
    7166           3 : static const VMFunction NeInfo =
    7167           6 :     FunctionInfo<CompareFn>(jit::LooselyEqual<false>, "LooselyEqual");
    7168           3 : static const VMFunction StrictEqInfo =
    7169           6 :     FunctionInfo<CompareFn>(jit::StrictlyEqual<true>, "StrictlyEqual");
    7170           3 : static const VMFunction StrictNeInfo =
    7171           6 :     FunctionInfo<CompareFn>(jit::StrictlyEqual<false>, "StrictlyEqual");
    7172           3 : static const VMFunction LtInfo =
    7173           6 :     FunctionInfo<CompareFn>(jit::LessThan, "LessThan");
    7174           3 : static const VMFunction LeInfo =
    7175           6 :     FunctionInfo<CompareFn>(jit::LessThanOrEqual, "LessThanOrEqual");
    7176           3 : static const VMFunction GtInfo =
    7177           6 :     FunctionInfo<CompareFn>(jit::GreaterThan, "GreaterThan");
    7178           3 : static const VMFunction GeInfo =
    7179           6 :     FunctionInfo<CompareFn>(jit::GreaterThanOrEqual, "GreaterThanOrEqual");
    7180             : 
    7181             : void
    7182           0 : CodeGenerator::visitCompareVM(LCompareVM* lir)
    7183             : {
    7184           0 :     pushArg(ToValue(lir, LBinaryV::RhsInput));
    7185           0 :     pushArg(ToValue(lir, LBinaryV::LhsInput));
    7186             : 
    7187           0 :     switch (lir->mir()->jsop()) {
    7188             :       case JSOP_EQ:
    7189           0 :         callVM(EqInfo, lir);
    7190           0 :         break;
    7191             : 
    7192             :       case JSOP_NE:
    7193           0 :         callVM(NeInfo, lir);
    7194           0 :         break;
    7195             : 
    7196             :       case JSOP_STRICTEQ:
    7197           0 :         callVM(StrictEqInfo, lir);
    7198           0 :         break;
    7199             : 
    7200             :       case JSOP_STRICTNE:
    7201           0 :         callVM(StrictNeInfo, lir);
    7202           0 :         break;
    7203             : 
    7204             :       case JSOP_LT:
    7205           0 :         callVM(LtInfo, lir);
    7206           0 :         break;
    7207             : 
    7208             :       case JSOP_LE:
    7209           0 :         callVM(LeInfo, lir);
    7210           0 :         break;
    7211             : 
    7212             :       case JSOP_GT:
    7213           0 :         callVM(GtInfo, lir);
    7214           0 :         break;
    7215             : 
    7216             :       case JSOP_GE:
    7217           0 :         callVM(GeInfo, lir);
    7218           0 :         break;
    7219             : 
    7220             :       default:
    7221           0 :         MOZ_CRASH("Unexpected compare op");
    7222             :     }
    7223           0 : }
    7224             : 
    7225             : void
    7226           0 : CodeGenerator::visitIsNullOrLikeUndefinedV(LIsNullOrLikeUndefinedV* lir)
    7227             : {
    7228           0 :     JSOp op = lir->mir()->jsop();
    7229           0 :     MCompare::CompareType compareType = lir->mir()->compareType();
    7230           0 :     MOZ_ASSERT(compareType == MCompare::Compare_Undefined ||
    7231             :                compareType == MCompare::Compare_Null);
    7232             : 
    7233           0 :     const ValueOperand value = ToValue(lir, LIsNullOrLikeUndefinedV::Value);
    7234           0 :     Register output = ToRegister(lir->output());
    7235             : 
    7236           0 :     if (op == JSOP_EQ || op == JSOP_NE) {
    7237           0 :         MOZ_ASSERT(lir->mir()->lhs()->type() != MIRType::Object ||
    7238             :                    lir->mir()->operandMightEmulateUndefined(),
    7239             :                    "Operands which can't emulate undefined should have been folded");
    7240             : 
    7241           0 :         OutOfLineTestObjectWithLabels* ool = nullptr;
    7242           0 :         Maybe<Label> label1, label2;
    7243             :         Label* nullOrLikeUndefined;
    7244             :         Label* notNullOrLikeUndefined;
    7245           0 :         if (lir->mir()->operandMightEmulateUndefined()) {
    7246           0 :             ool = new(alloc()) OutOfLineTestObjectWithLabels();
    7247           0 :             addOutOfLineCode(ool, lir->mir());
    7248           0 :             nullOrLikeUndefined = ool->label1();
    7249           0 :             notNullOrLikeUndefined = ool->label2();
    7250             :         } else {
    7251           0 :             label1.emplace();
    7252           0 :             label2.emplace();
    7253           0 :             nullOrLikeUndefined = label1.ptr();
    7254           0 :             notNullOrLikeUndefined = label2.ptr();
    7255             :         }
    7256             : 
    7257           0 :         Register tag = masm.splitTagForTest(value);
    7258           0 :         MDefinition* input = lir->mir()->lhs();
    7259           0 :         if (input->mightBeType(MIRType::Null))
    7260           0 :             masm.branchTestNull(Assembler::Equal, tag, nullOrLikeUndefined);
    7261           0 :         if (input->mightBeType(MIRType::Undefined))
    7262           0 :             masm.branchTestUndefined(Assembler::Equal, tag, nullOrLikeUndefined);
    7263             : 
    7264           0 :         if (ool) {
    7265             :             // Check whether it's a truthy object or a falsy object that emulates
    7266             :             // undefined.
    7267           0 :             masm.branchTestObject(Assembler::NotEqual, tag, notNullOrLikeUndefined);
    7268             : 
    7269           0 :             Register objreg = masm.extractObject(value, ToTempUnboxRegister(lir->tempToUnbox()));
    7270           0 :             branchTestObjectEmulatesUndefined(objreg, nullOrLikeUndefined, notNullOrLikeUndefined,
    7271           0 :                                               ToRegister(lir->temp()), ool);
    7272             :             // fall through
    7273             :         }
    7274             : 
    7275           0 :         Label done;
    7276             : 
    7277             :         // It's not null or undefined, and if it's an object it doesn't
    7278             :         // emulate undefined, so it's not like undefined.
    7279           0 :         masm.move32(Imm32(op == JSOP_NE), output);
    7280           0 :         masm.jump(&done);
    7281             : 
    7282           0 :         masm.bind(nullOrLikeUndefined);
    7283           0 :         masm.move32(Imm32(op == JSOP_EQ), output);
    7284             : 
    7285             :         // Both branches meet here.
    7286           0 :         masm.bind(&done);
    7287           0 :         return;
    7288             :     }
    7289             : 
    7290           0 :     MOZ_ASSERT(op == JSOP_STRICTEQ || op == JSOP_STRICTNE);
    7291             : 
    7292           0 :     Assembler::Condition cond = JSOpToCondition(compareType, op);
    7293           0 :     if (compareType == MCompare::Compare_Null)
    7294           0 :         masm.testNullSet(cond, value, output);
    7295             :     else
    7296           0 :         masm.testUndefinedSet(cond, value, output);
    7297             : }
    7298             : 
    7299             : void
    7300           0 : CodeGenerator::visitIsNullOrLikeUndefinedAndBranchV(LIsNullOrLikeUndefinedAndBranchV* lir)
    7301             : {
    7302           0 :     JSOp op = lir->cmpMir()->jsop();
    7303           0 :     MCompare::CompareType compareType = lir->cmpMir()->compareType();
    7304           0 :     MOZ_ASSERT(compareType == MCompare::Compare_Undefined ||
    7305             :                compareType == MCompare::Compare_Null);
    7306             : 
    7307           0 :     const ValueOperand value = ToValue(lir, LIsNullOrLikeUndefinedAndBranchV::Value);
    7308             : 
    7309           0 :     if (op == JSOP_EQ || op == JSOP_NE) {
    7310             :         MBasicBlock* ifTrue;
    7311             :         MBasicBlock* ifFalse;
    7312             : 
    7313           0 :         if (op == JSOP_EQ) {
    7314           0 :             ifTrue = lir->ifTrue();
    7315           0 :             ifFalse = lir->ifFalse();
    7316             :         } else {
    7317             :             // Swap branches.
    7318           0 :             ifTrue = lir->ifFalse();
    7319           0 :             ifFalse = lir->ifTrue();
    7320           0 :             op = JSOP_EQ;
    7321             :         }
    7322             : 
    7323           0 :         MOZ_ASSERT(lir->cmpMir()->lhs()->type() != MIRType::Object ||
    7324             :                    lir->cmpMir()->operandMightEmulateUndefined(),
    7325             :                    "Operands which can't emulate undefined should have been folded");
    7326             : 
    7327           0 :         OutOfLineTestObject* ool = nullptr;
    7328           0 :         if (lir->cmpMir()->operandMightEmulateUndefined()) {
    7329           0 :             ool = new(alloc()) OutOfLineTestObject();
    7330           0 :             addOutOfLineCode(ool, lir->cmpMir());
    7331             :         }
    7332             : 
    7333           0 :         Register tag = masm.splitTagForTest(value);
    7334             : 
    7335           0 :         Label* ifTrueLabel = getJumpLabelForBranch(ifTrue);
    7336           0 :         Label* ifFalseLabel = getJumpLabelForBranch(ifFalse);
    7337             : 
    7338           0 :         MDefinition* input = lir->cmpMir()->lhs();
    7339           0 :         if (input->mightBeType(MIRType::Null))
    7340           0 :             masm.branchTestNull(Assembler::Equal, tag, ifTrueLabel);
    7341           0 :         if (input->mightBeType(MIRType::Undefined))
    7342           0 :             masm.branchTestUndefined(Assembler::Equal, tag, ifTrueLabel);
    7343             : 
    7344           0 :         if (ool) {
    7345           0 :             masm.branchTestObject(Assembler::NotEqual, tag, ifFalseLabel);
    7346             : 
    7347             :             // Objects that emulate undefined are loosely equal to null/undefined.
    7348           0 :             Register objreg = masm.extractObject(value, ToTempUnboxRegister(lir->tempToUnbox()));
    7349           0 :             Register scratch = ToRegister(lir->temp());
    7350           0 :             testObjectEmulatesUndefined(objreg, ifTrueLabel, ifFalseLabel, scratch, ool);
    7351             :         } else {
    7352           0 :             masm.jump(ifFalseLabel);
    7353             :         }
    7354           0 :         return;
    7355             :     }
    7356             : 
    7357           0 :     MOZ_ASSERT(op == JSOP_STRICTEQ || op == JSOP_STRICTNE);
    7358             : 
    7359           0 :     Assembler::Condition cond = JSOpToCondition(compareType, op);
    7360           0 :     if (compareType == MCompare::Compare_Null)
    7361           0 :         testNullEmitBranch(cond, value, lir->ifTrue(), lir->ifFalse());
    7362             :     else
    7363           0 :         testUndefinedEmitBranch(cond, value, lir->ifTrue(), lir->ifFalse());
    7364             : }
    7365             : 
    7366             : void
    7367           0 : CodeGenerator::visitIsNullOrLikeUndefinedT(LIsNullOrLikeUndefinedT * lir)
    7368             : {
    7369           0 :     MOZ_ASSERT(lir->mir()->compareType() == MCompare::Compare_Undefined ||
    7370             :                lir->mir()->compareType() == MCompare::Compare_Null);
    7371             : 
    7372           0 :     MIRType lhsType = lir->mir()->lhs()->type();
    7373           0 :     MOZ_ASSERT(lhsType == MIRType::Object || lhsType == MIRType::ObjectOrNull);
    7374             : 
    7375           0 :     JSOp op = lir->mir()->jsop();
    7376           0 :     MOZ_ASSERT(lhsType == MIRType::ObjectOrNull || op == JSOP_EQ || op == JSOP_NE,
    7377             :                "Strict equality should have been folded");
    7378             : 
    7379           0 :     MOZ_ASSERT(lhsType == MIRType::ObjectOrNull || lir->mir()->operandMightEmulateUndefined(),
    7380             :                "If the object couldn't emulate undefined, this should have been folded.");
    7381             : 
    7382           0 :     Register objreg = ToRegister(lir->input());
    7383           0 :     Register output = ToRegister(lir->output());
    7384             : 
    7385           0 :     if ((op == JSOP_EQ || op == JSOP_NE) && lir->mir()->operandMightEmulateUndefined()) {
    7386           0 :         OutOfLineTestObjectWithLabels* ool = new(alloc()) OutOfLineTestObjectWithLabels();
    7387           0 :         addOutOfLineCode(ool, lir->mir());
    7388             : 
    7389           0 :         Label* emulatesUndefined = ool->label1();
    7390           0 :         Label* doesntEmulateUndefined = ool->label2();
    7391             : 
    7392           0 :         if (lhsType == MIRType::ObjectOrNull)
    7393           0 :             masm.branchTestPtr(Assembler::Zero, objreg, objreg, emulatesUndefined);
    7394             : 
    7395             :         branchTestObjectEmulatesUndefined(objreg, emulatesUndefined, doesntEmulateUndefined,
    7396           0 :                                           output, ool);
    7397             : 
    7398           0 :         Label done;
    7399             : 
    7400           0 :         masm.move32(Imm32(op == JSOP_NE), output);
    7401           0 :         masm.jump(&done);
    7402             : 
    7403           0 :         masm.bind(emulatesUndefined);
    7404           0 :         masm.move32(Imm32(op == JSOP_EQ), output);
    7405           0 :         masm.bind(&done);
    7406             :     } else {
    7407           0 :         MOZ_ASSERT(lhsType == MIRType::ObjectOrNull);
    7408             : 
    7409           0 :         Label isNull, done;
    7410             : 
    7411           0 :         masm.branchTestPtr(Assembler::Zero, objreg, objreg, &isNull);
    7412             : 
    7413           0 :         masm.move32(Imm32(op == JSOP_NE || op == JSOP_STRICTNE), output);
    7414           0 :         masm.jump(&done);
    7415             : 
    7416           0 :         masm.bind(&isNull);
    7417           0 :         masm.move32(Imm32(op == JSOP_EQ || op == JSOP_STRICTEQ), output);
    7418             : 
    7419           0 :         masm.bind(&done);
    7420             :     }
    7421           0 : }
    7422             : 
    7423             : void
    7424           0 : CodeGenerator::visitIsNullOrLikeUndefinedAndBranchT(LIsNullOrLikeUndefinedAndBranchT* lir)
    7425             : {
    7426           0 :     DebugOnly<MCompare::CompareType> compareType = lir->cmpMir()->compareType();
    7427           0 :     MOZ_ASSERT(compareType == MCompare::Compare_Undefined ||
    7428             :                compareType == MCompare::Compare_Null);
    7429             : 
    7430           0 :     MIRType lhsType = lir->cmpMir()->lhs()->type();
    7431           0 :     MOZ_ASSERT(lhsType == MIRType::Object || lhsType == MIRType::ObjectOrNull);
    7432             : 
    7433           0 :     JSOp op = lir->cmpMir()->jsop();
    7434           0 :     MOZ_ASSERT(lhsType == MIRType::ObjectOrNull || op == JSOP_EQ || op == JSOP_NE,
    7435             :                "Strict equality should have been folded");
    7436             : 
    7437           0 :     MOZ_ASSERT(lhsType == MIRType::ObjectOrNull || lir->cmpMir()->operandMightEmulateUndefined(),
    7438             :                "If the object couldn't emulate undefined, this should have been folded.");
    7439             : 
    7440             :     MBasicBlock* ifTrue;
    7441             :     MBasicBlock* ifFalse;
    7442             : 
    7443           0 :     if (op == JSOP_EQ || op == JSOP_STRICTEQ) {
    7444           0 :         ifTrue = lir->ifTrue();
    7445           0 :         ifFalse = lir->ifFalse();
    7446             :     } else {
    7447             :         // Swap branches.
    7448           0 :         ifTrue = lir->ifFalse();
    7449           0 :         ifFalse = lir->ifTrue();
    7450             :     }
    7451             : 
    7452           0 :     Register input = ToRegister(lir->getOperand(0));
    7453             : 
    7454           0 :     if ((op == JSOP_EQ || op == JSOP_NE) && lir->cmpMir()->operandMightEmulateUndefined()) {
    7455           0 :         OutOfLineTestObject* ool = new(alloc()) OutOfLineTestObject();
    7456           0 :         addOutOfLineCode(ool, lir->cmpMir());
    7457             : 
    7458           0 :         Label* ifTrueLabel = getJumpLabelForBranch(ifTrue);
    7459           0 :         Label* ifFalseLabel = getJumpLabelForBranch(ifFalse);
    7460             : 
    7461           0 :         if (lhsType == MIRType::ObjectOrNull)
    7462           0 :             masm.branchTestPtr(Assembler::Zero, input, input, ifTrueLabel);
    7463             : 
    7464             :         // Objects that emulate undefined are loosely equal to null/undefined.
    7465           0 :         Register scratch = ToRegister(lir->temp());
    7466           0 :         testObjectEmulatesUndefined(input, ifTrueLabel, ifFalseLabel, scratch, ool);
    7467             :     } else {
    7468           0 :         MOZ_ASSERT(lhsType == MIRType::ObjectOrNull);
    7469           0 :         testZeroEmitBranch(Assembler::Equal, input, ifTrue, ifFalse);
    7470             :     }
    7471           0 : }
    7472             : 
    7473             : typedef JSString* (*ConcatStringsFn)(JSContext*, HandleString, HandleString);
    7474           3 : static const VMFunction ConcatStringsInfo =
    7475           6 :     FunctionInfo<ConcatStringsFn>(ConcatStrings<CanGC>, "ConcatStrings");
    7476             : 
    7477             : void
    7478          12 : CodeGenerator::emitConcat(LInstruction* lir, Register lhs, Register rhs, Register output)
    7479             : {
    7480          24 :     OutOfLineCode* ool = oolCallVM(ConcatStringsInfo, lir, ArgList(lhs, rhs),
    7481          36 :                                    StoreRegisterTo(output));
    7482             : 
    7483          12 :     JitCode* stringConcatStub = gen->compartment->jitCompartment()->stringConcatStubNoBarrier();
    7484          12 :     masm.call(stringConcatStub);
    7485          12 :     masm.branchTestPtr(Assembler::Zero, output, output, ool->entry());
    7486             : 
    7487          12 :     masm.bind(ool->rejoin());
    7488          12 : }
    7489             : 
    7490             : void
    7491          12 : CodeGenerator::visitConcat(LConcat* lir)
    7492             : {
    7493          12 :     Register lhs = ToRegister(lir->lhs());
    7494          12 :     Register rhs = ToRegister(lir->rhs());
    7495             : 
    7496          12 :     Register output = ToRegister(lir->output());
    7497             : 
    7498          12 :     MOZ_ASSERT(lhs == CallTempReg0);
    7499          12 :     MOZ_ASSERT(rhs == CallTempReg1);
    7500          12 :     MOZ_ASSERT(ToRegister(lir->temp1()) == CallTempReg0);
    7501          12 :     MOZ_ASSERT(ToRegister(lir->temp2()) == CallTempReg1);
    7502          12 :     MOZ_ASSERT(ToRegister(lir->temp3()) == CallTempReg2);
    7503          12 :     MOZ_ASSERT(ToRegister(lir->temp4()) == CallTempReg3);
    7504          12 :     MOZ_ASSERT(ToRegister(lir->temp5()) == CallTempReg4);
    7505          12 :     MOZ_ASSERT(output == CallTempReg5);
    7506             : 
    7507          12 :     emitConcat(lir, lhs, rhs, output);
    7508          12 : }
    7509             : 
    7510             : static void
    7511          24 : CopyStringChars(MacroAssembler& masm, Register to, Register from, Register len,
    7512             :                 Register byteOpScratch, size_t fromWidth, size_t toWidth)
    7513             : {
    7514             :     // Copy |len| char16_t code units from |from| to |to|. Assumes len > 0
    7515             :     // (checked below in debug builds), and when done |to| must point to the
    7516             :     // next available char.
    7517             : 
    7518             : #ifdef DEBUG
    7519          48 :     Label ok;
    7520          24 :     masm.branch32(Assembler::GreaterThan, len, Imm32(0), &ok);
    7521          24 :     masm.assumeUnreachable("Length should be greater than 0.");
    7522          24 :     masm.bind(&ok);
    7523             : #endif
    7524             : 
    7525          24 :     MOZ_ASSERT(fromWidth == 1 || fromWidth == 2);
    7526          24 :     MOZ_ASSERT(toWidth == 1 || toWidth == 2);
    7527          24 :     MOZ_ASSERT_IF(toWidth == 1, fromWidth == 1);
    7528             : 
    7529          48 :     Label start;
    7530          24 :     masm.bind(&start);
    7531          24 :     if (fromWidth == 2)
    7532           8 :         masm.load16ZeroExtend(Address(from, 0), byteOpScratch);
    7533             :     else
    7534          16 :         masm.load8ZeroExtend(Address(from, 0), byteOpScratch);
    7535          24 :     if (toWidth == 2)
    7536          16 :         masm.store16(byteOpScratch, Address(to, 0));
    7537             :     else
    7538           8 :         masm.store8(byteOpScratch, Address(to, 0));
    7539          24 :     masm.addPtr(Imm32(fromWidth), from);
    7540          24 :     masm.addPtr(Imm32(toWidth), to);
    7541          24 :     masm.branchSub32(Assembler::NonZero, Imm32(1), len, &start);
    7542          24 : }
    7543             : 
    7544             : static void
    7545           8 : CopyStringCharsMaybeInflate(MacroAssembler& masm, Register input, Register destChars,
    7546             :                             Register temp1, Register temp2)
    7547             : {
    7548             :     // destChars is TwoByte and input is a Latin1 or TwoByte string, so we may
    7549             :     // have to inflate.
    7550             : 
    7551          16 :     Label isLatin1, done;
    7552           8 :     masm.loadStringLength(input, temp1);
    7553           8 :     masm.branchLatin1String(input, &isLatin1);
    7554             :     {
    7555           8 :         masm.loadStringChars(input, input);
    7556           8 :         CopyStringChars(masm, destChars, input, temp1, temp2, sizeof(char16_t), sizeof(char16_t));
    7557           8 :         masm.jump(&done);
    7558             :     }
    7559           8 :     masm.bind(&isLatin1);
    7560             :     {
    7561           8 :         masm.loadStringChars(input, input);
    7562           8 :         CopyStringChars(masm, destChars, input, temp1, temp2, sizeof(char), sizeof(char16_t));
    7563             :     }
    7564           8 :     masm.bind(&done);
    7565           8 : }
    7566             : 
    7567             : static void
    7568           8 : ConcatInlineString(MacroAssembler& masm, Register lhs, Register rhs, Register output,
    7569             :                    Register temp1, Register temp2, Register temp3,
    7570             :                    Label* failure, Label* failurePopTemps, bool isTwoByte)
    7571             : {
    7572             :     // State: result length in temp2.
    7573             : 
    7574             :     // Ensure both strings are linear.
    7575           8 :     masm.branchIfRope(lhs, failure);
    7576           8 :     masm.branchIfRope(rhs, failure);
    7577             : 
    7578             :     // Allocate a JSThinInlineString or JSFatInlineString.
    7579             :     size_t maxThinInlineLength;
    7580           8 :     if (isTwoByte)
    7581           4 :         maxThinInlineLength = JSThinInlineString::MAX_LENGTH_TWO_BYTE;
    7582             :     else
    7583           4 :         maxThinInlineLength = JSThinInlineString::MAX_LENGTH_LATIN1;
    7584             : 
    7585          16 :     Label isFat, allocDone;
    7586           8 :     masm.branch32(Assembler::Above, temp2, Imm32(maxThinInlineLength), &isFat);
    7587             :     {
    7588           8 :         uint32_t flags = JSString::INIT_THIN_INLINE_FLAGS;
    7589           8 :         if (!isTwoByte)
    7590           4 :             flags |= JSString::LATIN1_CHARS_BIT;
    7591           8 :         masm.newGCString(output, temp1, failure);
    7592           8 :         masm.store32(Imm32(flags), Address(output, JSString::offsetOfFlags()));
    7593           8 :         masm.jump(&allocDone);
    7594             :     }
    7595           8 :     masm.bind(&isFat);
    7596             :     {
    7597           8 :         uint32_t flags = JSString::INIT_FAT_INLINE_FLAGS;
    7598           8 :         if (!isTwoByte)
    7599           4 :             flags |= JSString::LATIN1_CHARS_BIT;
    7600           8 :         masm.newGCFatInlineString(output, temp1, failure);
    7601           8 :         masm.store32(Imm32(flags), Address(output, JSString::offsetOfFlags()));
    7602             :     }
    7603           8 :     masm.bind(&allocDone);
    7604             : 
    7605             :     // Store length.
    7606           8 :     masm.store32(temp2, Address(output, JSString::offsetOfLength()));
    7607             : 
    7608             :     // Load chars pointer in temp2.
    7609           8 :     masm.computeEffectiveAddress(Address(output, JSInlineString::offsetOfInlineStorage()), temp2);
    7610             : 
    7611             :     {
    7612             :         // Copy lhs chars. Note that this advances temp2 to point to the next
    7613             :         // char. This also clobbers the lhs register.
    7614           8 :         if (isTwoByte) {
    7615           4 :             CopyStringCharsMaybeInflate(masm, lhs, temp2, temp1, temp3);
    7616             :         } else {
    7617           4 :             masm.loadStringLength(lhs, temp3);
    7618           4 :             masm.loadStringChars(lhs, lhs);
    7619           4 :             CopyStringChars(masm, temp2, lhs, temp3, temp1, sizeof(char), sizeof(char));
    7620             :         }
    7621             : 
    7622             :         // Copy rhs chars. Clobbers the rhs register.
    7623           8 :         if (isTwoByte) {
    7624           4 :             CopyStringCharsMaybeInflate(masm, rhs, temp2, temp1, temp3);
    7625             :         } else {
    7626           4 :             masm.loadStringLength(rhs, temp3);
    7627           4 :             masm.loadStringChars(rhs, rhs);
    7628           4 :             CopyStringChars(masm, temp2, rhs, temp3, temp1, sizeof(char), sizeof(char));
    7629             :         }
    7630             : 
    7631             :         // Null-terminate.
    7632           8 :         if (isTwoByte)
    7633           4 :             masm.store16(Imm32(0), Address(temp2, 0));
    7634             :         else
    7635           4 :             masm.store8(Imm32(0), Address(temp2, 0));
    7636             :     }
    7637             : 
    7638           8 :     masm.ret();
    7639           8 : }
    7640             : 
    7641             : typedef JSString* (*SubstringKernelFn)(JSContext* cx, HandleString str, int32_t begin, int32_t len);
    7642           3 : static const VMFunction SubstringKernelInfo =
    7643           6 :     FunctionInfo<SubstringKernelFn>(SubstringKernel, "SubstringKernel");
    7644             : 
    7645             : void
    7646           0 : CodeGenerator::visitSubstr(LSubstr* lir)
    7647             : {
    7648           0 :     Register string = ToRegister(lir->string());
    7649           0 :     Register begin = ToRegister(lir->begin());
    7650           0 :     Register length = ToRegister(lir->length());
    7651           0 :     Register output = ToRegister(lir->output());
    7652           0 :     Register temp = ToRegister(lir->temp());
    7653           0 :     Register temp3 = ToRegister(lir->temp3());
    7654             : 
    7655             :     // On x86 there are not enough registers. In that case reuse the string
    7656             :     // register as temporary.
    7657           0 :     Register temp2 = lir->temp2()->isBogusTemp() ? string : ToRegister(lir->temp2());
    7658             : 
    7659           0 :     Address stringFlags(string, JSString::offsetOfFlags());
    7660             : 
    7661           0 :     Label isLatin1, notInline, nonZero, isInlinedLatin1;
    7662             : 
    7663             :     // For every edge case use the C++ variant.
    7664             :     // Note: we also use this upon allocation failure in newGCString and
    7665             :     // newGCFatInlineString. To squeeze out even more performance those failures
    7666             :     // can be handled by allocate in ool code and returning to jit code to fill
    7667             :     // in all data.
    7668           0 :     OutOfLineCode* ool = oolCallVM(SubstringKernelInfo, lir,
    7669           0 :                                    ArgList(string, begin, length),
    7670           0 :                                    StoreRegisterTo(output));
    7671           0 :     Label* slowPath = ool->entry();
    7672           0 :     Label* done = ool->rejoin();
    7673             : 
    7674             :     // Zero length, return emptystring.
    7675           0 :     masm.branchTest32(Assembler::NonZero, length, length, &nonZero);
    7676           0 :     const JSAtomState& names = GetJitContext()->runtime->names();
    7677           0 :     masm.movePtr(ImmGCPtr(names.empty), output);
    7678           0 :     masm.jump(done);
    7679             : 
    7680             :     // Use slow path for ropes.
    7681           0 :     masm.bind(&nonZero);
    7682           0 :     masm.branchIfRopeOrExternal(string, temp, slowPath);
    7683             : 
    7684             :     // Handle inlined strings by creating a FatInlineString.
    7685           0 :     masm.branchTest32(Assembler::Zero, stringFlags, Imm32(JSString::INLINE_CHARS_BIT), &notInline);
    7686           0 :     masm.newGCFatInlineString(output, temp, slowPath);
    7687           0 :     masm.store32(length, Address(output, JSString::offsetOfLength()));
    7688           0 :     Address stringStorage(string, JSInlineString::offsetOfInlineStorage());
    7689           0 :     Address outputStorage(output, JSInlineString::offsetOfInlineStorage());
    7690             : 
    7691           0 :     masm.branchLatin1String(string, &isInlinedLatin1);
    7692             :     {
    7693           0 :         masm.store32(Imm32(JSString::INIT_FAT_INLINE_FLAGS),
    7694           0 :                      Address(output, JSString::offsetOfFlags()));
    7695           0 :         masm.computeEffectiveAddress(stringStorage, temp);
    7696           0 :         if (temp2 == string)
    7697           0 :             masm.push(string);
    7698           0 :         BaseIndex chars(temp, begin, ScaleFromElemWidth(sizeof(char16_t)));
    7699           0 :         masm.computeEffectiveAddress(chars, temp2);
    7700           0 :         masm.computeEffectiveAddress(outputStorage, temp);
    7701           0 :         CopyStringChars(masm, temp, temp2, length, temp3, sizeof(char16_t), sizeof(char16_t));
    7702           0 :         masm.load32(Address(output, JSString::offsetOfLength()), length);
    7703           0 :         masm.store16(Imm32(0), Address(temp, 0));
    7704           0 :         if (temp2 == string)
    7705           0 :             masm.pop(string);
    7706           0 :         masm.jump(done);
    7707             :     }
    7708           0 :     masm.bind(&isInlinedLatin1);
    7709             :     {
    7710           0 :         masm.store32(Imm32(JSString::INIT_FAT_INLINE_FLAGS | JSString::LATIN1_CHARS_BIT),
    7711           0 :                      Address(output, JSString::offsetOfFlags()));
    7712           0 :         if (temp2 == string)
    7713           0 :             masm.push(string);
    7714           0 :         masm.computeEffectiveAddress(stringStorage, temp2);
    7715             :         static_assert(sizeof(char) == 1, "begin index shouldn't need scaling");
    7716           0 :         masm.addPtr(begin, temp2);
    7717           0 :         masm.computeEffectiveAddress(outputStorage, temp);
    7718           0 :         CopyStringChars(masm, temp, temp2, length, temp3, sizeof(char), sizeof(char));
    7719           0 :         masm.load32(Address(output, JSString::offsetOfLength()), length);
    7720           0 :         masm.store8(Imm32(0), Address(temp, 0));
    7721           0 :         if (temp2 == string)
    7722           0 :             masm.pop(string);
    7723           0 :         masm.jump(done);
    7724             :     }
    7725             : 
    7726             :     // Handle other cases with a DependentString.
    7727           0 :     masm.bind(&notInline);
    7728           0 :     masm.newGCString(output, temp, slowPath);
    7729           0 :     masm.store32(length, Address(output, JSString::offsetOfLength()));
    7730           0 :     masm.storePtr(string, Address(output, JSDependentString::offsetOfBase()));
    7731             : 
    7732           0 :     masm.branchLatin1String(string, &isLatin1);
    7733             :     {
    7734           0 :         masm.store32(Imm32(JSString::DEPENDENT_FLAGS), Address(output, JSString::offsetOfFlags()));
    7735           0 :         masm.loadPtr(Address(string, JSString::offsetOfNonInlineChars()), temp);
    7736           0 :         BaseIndex chars(temp, begin, ScaleFromElemWidth(sizeof(char16_t)));
    7737           0 :         masm.computeEffectiveAddress(chars, temp);
    7738           0 :         masm.storePtr(temp, Address(output, JSString::offsetOfNonInlineChars()));
    7739           0 :         masm.jump(done);
    7740             :     }
    7741           0 :     masm.bind(&isLatin1);
    7742             :     {
    7743           0 :         masm.store32(Imm32(JSString::DEPENDENT_FLAGS | JSString::LATIN1_CHARS_BIT),
    7744           0 :                      Address(output, JSString::offsetOfFlags()));
    7745           0 :         masm.loadPtr(Address(string, JSString::offsetOfNonInlineChars()), temp);
    7746             :         static_assert(sizeof(char) == 1, "begin index shouldn't need scaling");
    7747           0 :         masm.addPtr(begin, temp);
    7748           0 :         masm.storePtr(temp, Address(output, JSString::offsetOfNonInlineChars()));
    7749           0 :         masm.jump(done);
    7750             :     }
    7751             : 
    7752           0 :     masm.bind(done);
    7753           0 : }
    7754             : 
    7755             : JitCode*
    7756           4 : JitCompartment::generateStringConcatStub(JSContext* cx)
    7757             : {
    7758           8 :     MacroAssembler masm(cx);
    7759             : 
    7760           4 :     Register lhs = CallTempReg0;
    7761           4 :     Register rhs = CallTempReg1;
    7762           4 :     Register temp1 = CallTempReg2;
    7763           4 :     Register temp2 = CallTempReg3;
    7764           4 :     Register temp3 = CallTempReg4;
    7765           4 :     Register output = CallTempReg5;
    7766             : 
    7767           8 :     Label failure, failurePopTemps;
    7768             : #ifdef JS_USE_LINK_REGISTER
    7769             :     masm.pushReturnAddress();
    7770             : #endif
    7771             :     // If lhs is empty, return rhs.
    7772           8 :     Label leftEmpty;
    7773           4 :     masm.loadStringLength(lhs, temp1);
    7774           4 :     masm.branchTest32(Assembler::Zero, temp1, temp1, &leftEmpty);
    7775             : 
    7776             :     // If rhs is empty, return lhs.
    7777           8 :     Label rightEmpty;
    7778           4 :     masm.loadStringLength(rhs, temp2);
    7779           4 :     masm.branchTest32(Assembler::Zero, temp2, temp2, &rightEmpty);
    7780             : 
    7781           4 :     masm.add32(temp1, temp2);
    7782             : 
    7783             :     // Check if we can use a JSFatInlineString. The result is a Latin1 string if
    7784             :     // lhs and rhs are both Latin1, so we AND the flags.
    7785           8 :     Label isFatInlineTwoByte, isFatInlineLatin1;
    7786           4 :     masm.load32(Address(lhs, JSString::offsetOfFlags()), temp1);
    7787           4 :     masm.and32(Address(rhs, JSString::offsetOfFlags()), temp1);
    7788             : 
    7789           8 :     Label isLatin1, notInline;
    7790           4 :     masm.branchTest32(Assembler::NonZero, temp1, Imm32(JSString::LATIN1_CHARS_BIT), &isLatin1);
    7791             :     {
    7792           8 :         masm.branch32(Assembler::BelowOrEqual, temp2, Imm32(JSFatInlineString::MAX_LENGTH_TWO_BYTE),
    7793           4 :                       &isFatInlineTwoByte);
    7794           4 :         masm.jump(&notInline);
    7795             :     }
    7796           4 :     masm.bind(&isLatin1);
    7797             :     {
    7798           8 :         masm.branch32(Assembler::BelowOrEqual, temp2, Imm32(JSFatInlineString::MAX_LENGTH_LATIN1),
    7799           4 :                       &isFatInlineLatin1);
    7800             :     }
    7801           4 :     masm.bind(&notInline);
    7802             : 
    7803             :     // Keep AND'ed flags in temp1.
    7804             : 
    7805             :     // Ensure result length <= JSString::MAX_LENGTH.
    7806           4 :     masm.branch32(Assembler::Above, temp2, Imm32(JSString::MAX_LENGTH), &failure);
    7807             : 
    7808             :     // Allocate a new rope.
    7809           4 :     masm.newGCString(output, temp3, &failure);
    7810             : 
    7811             :     // Store rope length and flags. temp1 still holds the result of AND'ing the
    7812             :     // lhs and rhs flags, so we just have to clear the other flags to get our
    7813             :     // rope flags (Latin1 if both lhs and rhs are Latin1).
    7814             :     static_assert(JSString::ROPE_FLAGS == 0, "Rope flags must be 0");
    7815           4 :     masm.and32(Imm32(JSString::LATIN1_CHARS_BIT), temp1);
    7816           4 :     masm.store32(temp1, Address(output, JSString::offsetOfFlags()));
    7817           4 :     masm.store32(temp2, Address(output, JSString::offsetOfLength()));
    7818             : 
    7819             :     // Store left and right nodes.
    7820           4 :     masm.storePtr(lhs, Address(output, JSRope::offsetOfLeft()));
    7821           4 :     masm.storePtr(rhs, Address(output, JSRope::offsetOfRight()));
    7822           4 :     masm.ret();
    7823             : 
    7824           4 :     masm.bind(&leftEmpty);
    7825           4 :     masm.mov(rhs, output);
    7826           4 :     masm.ret();
    7827             : 
    7828           4 :     masm.bind(&rightEmpty);
    7829           4 :     masm.mov(lhs, output);
    7830           4 :     masm.ret();
    7831             : 
    7832           4 :     masm.bind(&isFatInlineTwoByte);
    7833             :     ConcatInlineString(masm, lhs, rhs, output, temp1, temp2, temp3,
    7834           4 :                        &failure, &failurePopTemps, true);
    7835             : 
    7836           4 :     masm.bind(&isFatInlineLatin1);
    7837             :     ConcatInlineString(masm, lhs, rhs, output, temp1, temp2, temp3,
    7838           4 :                        &failure, &failurePopTemps, false);
    7839             : 
    7840           4 :     masm.bind(&failurePopTemps);
    7841           4 :     masm.pop(temp2);
    7842           4 :     masm.pop(temp1);
    7843             : 
    7844           4 :     masm.bind(&failure);
    7845           4 :     masm.movePtr(ImmPtr(nullptr), output);
    7846           4 :     masm.ret();
    7847             : 
    7848           8 :     Linker linker(masm);
    7849           8 :     AutoFlushICache afc("StringConcatStub");
    7850           4 :     JitCode* code = linker.newCode<CanGC>(cx, OTHER_CODE);
    7851             : 
    7852             : #ifdef JS_ION_PERF
    7853             :     writePerfSpewerJitCodeProfile(code, "StringConcatStub");
    7854             : #endif
    7855             : #ifdef MOZ_VTUNE
    7856           4 :     vtune::MarkStub(code, "StringConcatStub");
    7857             : #endif
    7858             : 
    7859           8 :     return code;
    7860             : }
    7861             : 
    7862             : JitCode*
    7863           4 : JitRuntime::generateMallocStub(JSContext* cx)
    7864             : {
    7865           4 :     const Register regReturn = CallTempReg0;
    7866           4 :     const Register regNBytes = CallTempReg0;
    7867             : 
    7868           8 :     MacroAssembler masm(cx);
    7869             : 
    7870           4 :     AllocatableRegisterSet regs(RegisterSet::Volatile());
    7871             : #ifdef JS_USE_LINK_REGISTER
    7872             :     masm.pushReturnAddress();
    7873             : #endif
    7874           4 :     regs.takeUnchecked(regNBytes);
    7875           4 :     LiveRegisterSet save(regs.asLiveSet());
    7876           4 :     masm.PushRegsInMask(save);
    7877             : 
    7878           4 :     const Register regTemp = regs.takeAnyGeneral();
    7879           4 :     const Register regRuntime = regTemp;
    7880           4 :     MOZ_ASSERT(regTemp != regNBytes);
    7881             : 
    7882           4 :     masm.setupUnalignedABICall(regTemp);
    7883           4 :     masm.movePtr(ImmPtr(cx->runtime()), regRuntime);
    7884           4 :     masm.passABIArg(regRuntime);
    7885           4 :     masm.passABIArg(regNBytes);
    7886           4 :     masm.callWithABI(JS_FUNC_TO_DATA_PTR(void*, MallocWrapper));
    7887           4 :     masm.storeCallWordResult(regReturn);
    7888             : 
    7889           4 :     masm.PopRegsInMask(save);
    7890           4 :     masm.ret();
    7891             : 
    7892           8 :     Linker linker(masm);
    7893           8 :     AutoFlushICache afc("MallocStub");
    7894           4 :     JitCode* code = linker.newCode<NoGC>(cx, OTHER_CODE);
    7895             : 
    7896             : #ifdef JS_ION_PERF
    7897             :     writePerfSpewerJitCodeProfile(code, "MallocStub");
    7898             : #endif
    7899             : #ifdef MOZ_VTUNE
    7900           4 :     vtune::MarkStub(code, "MallocStub");
    7901             : #endif
    7902             : 
    7903           8 :     return code;
    7904             : }
    7905             : 
    7906             : JitCode*
    7907           4 : JitRuntime::generateFreeStub(JSContext* cx)
    7908             : {
    7909           4 :     const Register regSlots = CallTempReg0;
    7910             : 
    7911           8 :     MacroAssembler masm(cx);
    7912             : #ifdef JS_USE_LINK_REGISTER
    7913             :     masm.pushReturnAddress();
    7914             : #endif
    7915           4 :     AllocatableRegisterSet regs(RegisterSet::Volatile());
    7916           4 :     regs.takeUnchecked(regSlots);
    7917           4 :     LiveRegisterSet save(regs.asLiveSet());
    7918           4 :     masm.PushRegsInMask(save);
    7919             : 
    7920           4 :     const Register regTemp = regs.takeAnyGeneral();
    7921           4 :     MOZ_ASSERT(regTemp != regSlots);
    7922             : 
    7923           4 :     masm.setupUnalignedABICall(regTemp);
    7924           4 :     masm.passABIArg(regSlots);
    7925           4 :     masm.callWithABI(JS_FUNC_TO_DATA_PTR(void*, js_free));
    7926             : 
    7927           4 :     masm.PopRegsInMask(save);
    7928             : 
    7929           4 :     masm.ret();
    7930             : 
    7931           8 :     Linker linker(masm);
    7932           8 :     AutoFlushICache afc("FreeStub");
    7933           4 :     JitCode* code = linker.newCode<NoGC>(cx, OTHER_CODE);
    7934             : 
    7935             : #ifdef JS_ION_PERF
    7936             :     writePerfSpewerJitCodeProfile(code, "FreeStub");
    7937             : #endif
    7938             : #ifdef MOZ_VTUNE
    7939           4 :     vtune::MarkStub(code, "FreeStub");
    7940             : #endif
    7941             : 
    7942           8 :     return code;
    7943             : }
    7944             : 
    7945             : 
    7946             : JitCode*
    7947           4 : JitRuntime::generateLazyLinkStub(JSContext* cx)
    7948             : {
    7949           8 :     MacroAssembler masm(cx);
    7950             : #ifdef JS_USE_LINK_REGISTER
    7951             :     masm.pushReturnAddress();
    7952             : #endif
    7953             : 
    7954           4 :     AllocatableGeneralRegisterSet regs(GeneralRegisterSet::Volatile());
    7955           4 :     Register temp0 = regs.takeAny();
    7956             : 
    7957           4 :     masm.loadJSContext(temp0);
    7958           4 :     masm.enterFakeExitFrame(temp0, temp0, LazyLinkExitFrameLayoutToken);
    7959           4 :     masm.PushStubCode();
    7960             : 
    7961           4 :     masm.setupUnalignedABICall(temp0);
    7962           4 :     masm.passABIArg(temp0);
    7963           4 :     masm.callWithABI(JS_FUNC_TO_DATA_PTR(void*, LazyLinkTopActivation));
    7964             : 
    7965           4 :     masm.leaveExitFrame(/* stub code */ sizeof(JitCode*));
    7966             : 
    7967             : #ifdef JS_USE_LINK_REGISTER
    7968             :     // Restore the return address such that the emitPrologue function of the
    7969             :     // CodeGenerator can push it back on the stack with pushReturnAddress.
    7970             :     masm.popReturnAddress();
    7971             : #endif
    7972           4 :     masm.jump(ReturnReg);
    7973             : 
    7974           8 :     Linker linker(masm);
    7975           8 :     AutoFlushICache afc("LazyLinkStub");
    7976           4 :     JitCode* code = linker.newCode<NoGC>(cx, OTHER_CODE);
    7977             : 
    7978             : #ifdef JS_ION_PERF
    7979             :     writePerfSpewerJitCodeProfile(code, "LazyLinkStub");
    7980             : #endif
    7981             : #ifdef MOZ_VTUNE
    7982           4 :     vtune::MarkStub(code, "LazyLinkStub");
    7983             : #endif
    7984           8 :     return code;
    7985             : }
    7986             : 
    7987             : bool
    7988        2072 : JitRuntime::generateTLEventVM(JSContext* cx, MacroAssembler& masm, const VMFunction& f,
    7989             :                               bool enter)
    7990             : {
    7991             : #ifdef JS_TRACE_LOGGING
    7992        2072 :     bool vmEventEnabled = TraceLogTextIdEnabled(TraceLogger_VM);
    7993        2072 :     bool vmSpecificEventEnabled = TraceLogTextIdEnabled(TraceLogger_VMSpecific);
    7994             : 
    7995        2072 :     if (vmEventEnabled || vmSpecificEventEnabled) {
    7996           0 :         AllocatableRegisterSet regs(RegisterSet::Volatile());
    7997           0 :         Register loggerReg = regs.takeAnyGeneral();
    7998           0 :         masm.Push(loggerReg);
    7999           0 :         masm.loadTraceLogger(loggerReg);
    8000             : 
    8001           0 :         if (vmEventEnabled) {
    8002           0 :             if (enter)
    8003           0 :                 masm.tracelogStartId(loggerReg, TraceLogger_VM, /* force = */ true);
    8004             :             else
    8005           0 :                 masm.tracelogStopId(loggerReg, TraceLogger_VM, /* force = */ true);
    8006             :         }
    8007           0 :         if (vmSpecificEventEnabled) {
    8008           0 :             TraceLoggerEvent event(f.name());
    8009           0 :             if (!event.hasTextId())
    8010           0 :                 return false;
    8011             : 
    8012           0 :             if (enter)
    8013           0 :                 masm.tracelogStartId(loggerReg, event.textId(), /* force = */ true);
    8014             :             else
    8015           0 :                 masm.tracelogStopId(loggerReg, event.textId(), /* force = */ true);
    8016             :         }
    8017             : 
    8018           0 :         masm.Pop(loggerReg);
    8019             :     }
    8020             : #endif
    8021             : 
    8022        2072 :     return true;
    8023             : }
    8024             : 
    8025             : typedef bool (*CharCodeAtFn)(JSContext*, HandleString, int32_t, uint32_t*);
    8026           3 : static const VMFunction CharCodeAtInfo =
    8027           6 :     FunctionInfo<CharCodeAtFn>(jit::CharCodeAt, "CharCodeAt");
    8028             : 
    8029             : void
    8030           2 : CodeGenerator::visitCharCodeAt(LCharCodeAt* lir)
    8031             : {
    8032           2 :     Register str = ToRegister(lir->str());
    8033           2 :     Register index = ToRegister(lir->index());
    8034           2 :     Register output = ToRegister(lir->output());
    8035             : 
    8036           2 :     OutOfLineCode* ool = oolCallVM(CharCodeAtInfo, lir, ArgList(str, index), StoreRegisterTo(output));
    8037           2 :     masm.loadStringChar(str, index, output, ool->entry());
    8038           2 :     masm.bind(ool->rejoin());
    8039           2 : }
    8040             : 
    8041             : typedef JSFlatString* (*StringFromCharCodeFn)(JSContext*, int32_t);
    8042           3 : static const VMFunction StringFromCharCodeInfo =
    8043           6 :     FunctionInfo<StringFromCharCodeFn>(jit::StringFromCharCode, "StringFromCharCode");
    8044             : 
    8045             : void
    8046           2 : CodeGenerator::visitFromCharCode(LFromCharCode* lir)
    8047             : {
    8048           2 :     Register code = ToRegister(lir->code());
    8049           2 :     Register output = ToRegister(lir->output());
    8050             : 
    8051           2 :     OutOfLineCode* ool = oolCallVM(StringFromCharCodeInfo, lir, ArgList(code), StoreRegisterTo(output));
    8052             : 
    8053             :     // OOL path if code >= UNIT_STATIC_LIMIT.
    8054           4 :     masm.branch32(Assembler::AboveOrEqual, code, Imm32(StaticStrings::UNIT_STATIC_LIMIT),
    8055           2 :                   ool->entry());
    8056             : 
    8057           2 :     masm.movePtr(ImmPtr(&GetJitContext()->runtime->staticStrings().unitStaticTable), output);
    8058           2 :     masm.loadPtr(BaseIndex(output, code, ScalePointer), output);
    8059             : 
    8060           2 :     masm.bind(ool->rejoin());
    8061           2 : }
    8062             : 
    8063             : typedef JSString* (*StringFromCodePointFn)(JSContext*, int32_t);
    8064           3 : static const VMFunction StringFromCodePointInfo =
    8065           6 :     FunctionInfo<StringFromCodePointFn>(jit::StringFromCodePoint, "StringFromCodePoint");
    8066             : 
    8067             : void
    8068           0 : CodeGenerator::visitFromCodePoint(LFromCodePoint* lir)
    8069             : {
    8070           0 :     Register codePoint = ToRegister(lir->codePoint());
    8071           0 :     Register output = ToRegister(lir->output());
    8072           0 :     Register temp1 = ToRegister(lir->temp1());
    8073           0 :     Register temp2 = ToRegister(lir->temp2());
    8074           0 :     LSnapshot* snapshot = lir->snapshot();
    8075             : 
    8076             :     // The OOL path is only taken when we can't allocate the inline string.
    8077           0 :     OutOfLineCode* ool = oolCallVM(StringFromCodePointInfo, lir, ArgList(codePoint),
    8078           0 :                                    StoreRegisterTo(output));
    8079             : 
    8080           0 :     Label isTwoByte;
    8081           0 :     Label* done = ool->rejoin();
    8082             : 
    8083             :     static_assert(StaticStrings::UNIT_STATIC_LIMIT -1 == JSString::MAX_LATIN1_CHAR,
    8084             :                   "Latin-1 strings can be loaded from static strings");
    8085           0 :     masm.branch32(Assembler::AboveOrEqual, codePoint, Imm32(StaticStrings::UNIT_STATIC_LIMIT),
    8086           0 :                   &isTwoByte);
    8087             :     {
    8088           0 :         masm.movePtr(ImmPtr(&GetJitContext()->runtime->staticStrings().unitStaticTable), output);
    8089           0 :         masm.loadPtr(BaseIndex(output, codePoint, ScalePointer), output);
    8090           0 :         masm.jump(done);
    8091             :     }
    8092           0 :     masm.bind(&isTwoByte);
    8093             :     {
    8094             :         // Use a bailout if the input is not a valid code point, because
    8095             :         // MFromCodePoint is movable and it'd be observable when a moved
    8096             :         // fromCodePoint throws an exception before its actual call site.
    8097           0 :         bailoutCmp32(Assembler::Above, codePoint, Imm32(unicode::NonBMPMax), snapshot);
    8098             : 
    8099             :         // Allocate a JSThinInlineString.
    8100             :         {
    8101             :             static_assert(JSThinInlineString::MAX_LENGTH_TWO_BYTE >= 2,
    8102             :                           "JSThinInlineString can hold a supplementary code point");
    8103             : 
    8104           0 :             uint32_t flags = JSString::INIT_THIN_INLINE_FLAGS;
    8105           0 :             masm.newGCString(output, temp1, ool->entry());
    8106           0 :             masm.store32(Imm32(flags), Address(output, JSString::offsetOfFlags()));
    8107             :         }
    8108             : 
    8109           0 :         Label isSupplementary;
    8110           0 :         masm.branch32(Assembler::AboveOrEqual, codePoint, Imm32(unicode::NonBMPMin),
    8111           0 :                       &isSupplementary);
    8112             :         {
    8113             :             // Store length.
    8114           0 :             masm.store32(Imm32(1), Address(output, JSString::offsetOfLength()));
    8115             : 
    8116             :             // Load chars pointer in temp1.
    8117           0 :             masm.computeEffectiveAddress(Address(output, JSInlineString::offsetOfInlineStorage()),
    8118           0 :                                          temp1);
    8119             : 
    8120           0 :             masm.store16(codePoint, Address(temp1, 0));
    8121             : 
    8122             :             // Null-terminate.
    8123           0 :             masm.store16(Imm32(0), Address(temp1, sizeof(char16_t)));
    8124             : 
    8125           0 :             masm.jump(done);
    8126             :         }
    8127           0 :         masm.bind(&isSupplementary);
    8128             :         {
    8129             :             // Store length.
    8130           0 :             masm.store32(Imm32(2), Address(output, JSString::offsetOfLength()));
    8131             : 
    8132             :             // Load chars pointer in temp1.
    8133           0 :             masm.computeEffectiveAddress(Address(output, JSInlineString::offsetOfInlineStorage()),
    8134           0 :                                          temp1);
    8135             : 
    8136             :             // Inlined unicode::LeadSurrogate(uint32_t).
    8137           0 :             masm.move32(codePoint, temp2);
    8138           0 :             masm.rshift32(Imm32(10), temp2);
    8139           0 :             masm.add32(Imm32(unicode::LeadSurrogateMin - (unicode::NonBMPMin >> 10)), temp2);
    8140             : 
    8141           0 :             masm.store16(temp2, Address(temp1, 0));
    8142             : 
    8143             :             // Inlined unicode::TrailSurrogate(uint32_t).
    8144           0 :             masm.move32(codePoint, temp2);
    8145           0 :             masm.and32(Imm32(0x3FF), temp2);
    8146           0 :             masm.or32(Imm32(unicode::TrailSurrogateMin), temp2);
    8147             : 
    8148           0 :             masm.store16(temp2, Address(temp1, sizeof(char16_t)));
    8149             : 
    8150             :             // Null-terminate.
    8151           0 :             masm.store16(Imm32(0), Address(temp1, 2 * sizeof(char16_t)));
    8152             :         }
    8153             :     }
    8154             : 
    8155           0 :     masm.bind(done);
    8156           0 : }
    8157             : 
    8158             : void
    8159           0 : CodeGenerator::visitSinCos(LSinCos *lir)
    8160             : {
    8161           0 :     Register temp = ToRegister(lir->temp());
    8162           0 :     Register params = ToRegister(lir->temp2());
    8163           0 :     FloatRegister input = ToFloatRegister(lir->input());
    8164           0 :     FloatRegister outputSin = ToFloatRegister(lir->outputSin());
    8165           0 :     FloatRegister outputCos = ToFloatRegister(lir->outputCos());
    8166             : 
    8167           0 :     masm.reserveStack(sizeof(double) * 2);
    8168           0 :     masm.movePtr(masm.getStackPointer(), params);
    8169             : 
    8170           0 :     const MathCache* mathCache = lir->mir()->cache();
    8171             : 
    8172           0 :     masm.setupUnalignedABICall(temp);
    8173           0 :     if (mathCache) {
    8174           0 :         masm.movePtr(ImmPtr(mathCache), temp);
    8175           0 :         masm.passABIArg(temp);
    8176             :     }
    8177             : 
    8178             : #define MAYBE_CACHED_(fcn) (mathCache ? (void*)fcn ## _impl : (void*)fcn ## _uncached)
    8179             : 
    8180           0 :     masm.passABIArg(input, MoveOp::DOUBLE);
    8181           0 :     masm.passABIArg(MoveOperand(params, sizeof(double), MoveOperand::EFFECTIVE_ADDRESS),
    8182           0 :                                 MoveOp::GENERAL);
    8183           0 :     masm.passABIArg(MoveOperand(params, 0, MoveOperand::EFFECTIVE_ADDRESS),
    8184           0 :                                 MoveOp::GENERAL);
    8185             : 
    8186           0 :     masm.callWithABI(JS_FUNC_TO_DATA_PTR(void*, MAYBE_CACHED_(js::math_sincos)));
    8187             : #undef MAYBE_CACHED_
    8188             : 
    8189           0 :     masm.loadDouble(Address(masm.getStackPointer(), 0), outputCos);
    8190           0 :     masm.loadDouble(Address(masm.getStackPointer(), sizeof(double)), outputSin);
    8191           0 :     masm.freeStack(sizeof(double) * 2);
    8192           0 : }
    8193             : 
    8194             : typedef JSObject* (*StringSplitFn)(JSContext*, HandleObjectGroup, HandleString, HandleString, uint32_t);
    8195           3 : static const VMFunction StringSplitInfo =
    8196           6 :     FunctionInfo<StringSplitFn>(js::str_split_string, "str_split_string");
    8197             : 
    8198             : void
    8199           0 : CodeGenerator::visitStringSplit(LStringSplit* lir)
    8200             : {
    8201           0 :     pushArg(Imm32(INT32_MAX));
    8202           0 :     pushArg(ToRegister(lir->separator()));
    8203           0 :     pushArg(ToRegister(lir->string()));
    8204           0 :     pushArg(ImmGCPtr(lir->mir()->group()));
    8205             : 
    8206           0 :     callVM(StringSplitInfo, lir);
    8207           0 : }
    8208             : 
    8209             : void
    8210           1 : CodeGenerator::visitInitializedLength(LInitializedLength* lir)
    8211             : {
    8212           1 :     Address initLength(ToRegister(lir->elements()), ObjectElements::offsetOfInitializedLength());
    8213           1 :     masm.load32(initLength, ToRegister(lir->output()));
    8214           1 : }
    8215             : 
    8216             : void
    8217           4 : CodeGenerator::visitSetInitializedLength(LSetInitializedLength* lir)
    8218             : {
    8219           4 :     Address initLength(ToRegister(lir->elements()), ObjectElements::offsetOfInitializedLength());
    8220           4 :     RegisterOrInt32Constant index = ToRegisterOrInt32Constant(lir->index());
    8221             : 
    8222           4 :     masm.inc32(&index);
    8223           4 :     masm.store32(index, initLength);
    8224             :     // Restore register value if it is used/captured after.
    8225           4 :     masm.dec32(&index);
    8226           4 : }
    8227             : 
    8228             : void
    8229           0 : CodeGenerator::visitUnboxedArrayLength(LUnboxedArrayLength* lir)
    8230             : {
    8231           0 :     Register obj = ToRegister(lir->object());
    8232           0 :     Register result = ToRegister(lir->output());
    8233           0 :     masm.load32(Address(obj, UnboxedArrayObject::offsetOfLength()), result);
    8234           0 : }
    8235             : 
    8236             : void
    8237           0 : CodeGenerator::visitUnboxedArrayInitializedLength(LUnboxedArrayInitializedLength* lir)
    8238             : {
    8239           0 :     Register obj = ToRegister(lir->object());
    8240           0 :     Register result = ToRegister(lir->output());
    8241           0 :     masm.load32(Address(obj, UnboxedArrayObject::offsetOfCapacityIndexAndInitializedLength()), result);
    8242           0 :     masm.and32(Imm32(UnboxedArrayObject::InitializedLengthMask), result);
    8243           0 : }
    8244             : 
    8245             : void
    8246           0 : CodeGenerator::visitIncrementUnboxedArrayInitializedLength(LIncrementUnboxedArrayInitializedLength* lir)
    8247             : {
    8248           0 :     Register obj = ToRegister(lir->object());
    8249           0 :     masm.add32(Imm32(1), Address(obj, UnboxedArrayObject::offsetOfCapacityIndexAndInitializedLength()));
    8250           0 : }
    8251             : 
    8252             : void
    8253           0 : CodeGenerator::visitSetUnboxedArrayInitializedLength(LSetUnboxedArrayInitializedLength* lir)
    8254             : {
    8255           0 :     Register obj = ToRegister(lir->object());
    8256           0 :     RegisterOrInt32Constant key = ToRegisterOrInt32Constant(lir->length());
    8257           0 :     Register temp = ToRegister(lir->temp());
    8258             : 
    8259           0 :     Address initLengthAddr(obj, UnboxedArrayObject::offsetOfCapacityIndexAndInitializedLength());
    8260           0 :     masm.load32(initLengthAddr, temp);
    8261           0 :     masm.and32(Imm32(UnboxedArrayObject::CapacityMask), temp);
    8262             : 
    8263           0 :     if (key.isRegister())
    8264           0 :         masm.or32(key.reg(), temp);
    8265             :     else
    8266           0 :         masm.or32(Imm32(key.constant()), temp);
    8267             : 
    8268           0 :     masm.store32(temp, initLengthAddr);
    8269           0 : }
    8270             : 
    8271             : void
    8272           0 : CodeGenerator::visitNotO(LNotO* lir)
    8273             : {
    8274           0 :     MOZ_ASSERT(lir->mir()->operandMightEmulateUndefined(),
    8275             :                "This should be constant-folded if the object can't emulate undefined.");
    8276             : 
    8277           0 :     OutOfLineTestObjectWithLabels* ool = new(alloc()) OutOfLineTestObjectWithLabels();
    8278           0 :     addOutOfLineCode(ool, lir->mir());
    8279             : 
    8280           0 :     Label* ifEmulatesUndefined = ool->label1();
    8281           0 :     Label* ifDoesntEmulateUndefined = ool->label2();
    8282             : 
    8283           0 :     Register objreg = ToRegister(lir->input());
    8284           0 :     Register output = ToRegister(lir->output());
    8285             :     branchTestObjectEmulatesUndefined(objreg, ifEmulatesUndefined, ifDoesntEmulateUndefined,
    8286           0 :                                       output, ool);
    8287             :     // fall through
    8288             : 
    8289           0 :     Label join;
    8290             : 
    8291           0 :     masm.move32(Imm32(0), output);
    8292           0 :     masm.jump(&join);
    8293             : 
    8294           0 :     masm.bind(ifEmulatesUndefined);
    8295           0 :     masm.move32(Imm32(1), output);
    8296             : 
    8297           0 :     masm.bind(&join);
    8298           0 : }
    8299             : 
    8300             : void
    8301           2 : CodeGenerator::visitNotV(LNotV* lir)
    8302             : {
    8303           4 :     Maybe<Label> ifTruthyLabel, ifFalsyLabel;
    8304             :     Label* ifTruthy;
    8305             :     Label* ifFalsy;
    8306             : 
    8307           2 :     OutOfLineTestObjectWithLabels* ool = nullptr;
    8308           2 :     MDefinition* operand = lir->mir()->input();
    8309             :     // Unfortunately, it's possible that someone (e.g. phi elimination) switched
    8310             :     // out our operand after we did cacheOperandMightEmulateUndefined.  So we
    8311             :     // might think it can emulate undefined _and_ know that it can't be an
    8312             :     // object.
    8313           2 :     if (lir->mir()->operandMightEmulateUndefined() && operand->mightBeType(MIRType::Object)) {
    8314           0 :         ool = new(alloc()) OutOfLineTestObjectWithLabels();
    8315           0 :         addOutOfLineCode(ool, lir->mir());
    8316           0 :         ifTruthy = ool->label1();
    8317           0 :         ifFalsy = ool->label2();
    8318             :     } else {
    8319           2 :         ifTruthyLabel.emplace();
    8320           2 :         ifFalsyLabel.emplace();
    8321           2 :         ifTruthy = ifTruthyLabel.ptr();
    8322           2 :         ifFalsy = ifFalsyLabel.ptr();
    8323             :     }
    8324             : 
    8325           4 :     testValueTruthyKernel(ToValue(lir, LNotV::Input), lir->temp1(), lir->temp2(),
    8326             :                           ToFloatRegister(lir->tempFloat()),
    8327           2 :                           ifTruthy, ifFalsy, ool, operand);
    8328             : 
    8329           4 :     Label join;
    8330           2 :     Register output = ToRegister(lir->output());
    8331             : 
    8332             :     // Note that the testValueTruthyKernel call above may choose to fall through
    8333             :     // to ifTruthy instead of branching there.
    8334           2 :     masm.bind(ifTruthy);
    8335           2 :     masm.move32(Imm32(0), output);
    8336           2 :     masm.jump(&join);
    8337             : 
    8338           2 :     masm.bind(ifFalsy);
    8339           2 :     masm.move32(Imm32(1), output);
    8340             : 
    8341             :     // both branches meet here.
    8342           2 :     masm.bind(&join);
    8343           2 : }
    8344             : 
    8345             : void
    8346           1 : CodeGenerator::visitBoundsCheck(LBoundsCheck* lir)
    8347             : {
    8348           1 :     const LAllocation* index = lir->index();
    8349           1 :     const LAllocation* length = lir->length();
    8350           1 :     LSnapshot* snapshot = lir->snapshot();
    8351             : 
    8352           1 :     if (index->isConstant()) {
    8353             :         // Use uint32 so that the comparison is unsigned.
    8354           0 :         uint32_t idx = ToInt32(index);
    8355           0 :         if (length->isConstant()) {
    8356           0 :             uint32_t len = ToInt32(lir->length());
    8357           0 :             if (idx < len)
    8358           0 :                 return;
    8359           0 :             bailout(snapshot);
    8360           0 :             return;
    8361             :         }
    8362             : 
    8363           0 :         if (length->isRegister())
    8364           0 :             bailoutCmp32(Assembler::BelowOrEqual, ToRegister(length), Imm32(idx), snapshot);
    8365             :         else
    8366           0 :             bailoutCmp32(Assembler::BelowOrEqual, ToAddress(length), Imm32(idx), snapshot);
    8367           0 :         return;
    8368             :     }
    8369             : 
    8370           1 :     Register indexReg = ToRegister(index);
    8371           1 :     if (length->isConstant())
    8372           0 :         bailoutCmp32(Assembler::AboveOrEqual, indexReg, Imm32(ToInt32(length)), snapshot);
    8373           1 :     else if (length->isRegister())
    8374           1 :         bailoutCmp32(Assembler::BelowOrEqual, ToRegister(length), indexReg, snapshot);
    8375             :     else
    8376           0 :         bailoutCmp32(Assembler::BelowOrEqual, ToAddress(length), indexReg, snapshot);
    8377             : }
    8378             : 
    8379             : void
    8380           0 : CodeGenerator::visitBoundsCheckRange(LBoundsCheckRange* lir)
    8381             : {
    8382           0 :     int32_t min = lir->mir()->minimum();
    8383           0 :     int32_t max = lir->mir()->maximum();
    8384           0 :     MOZ_ASSERT(max >= min);
    8385             : 
    8386           0 :     const LAllocation* length = lir->length();
    8387           0 :     LSnapshot* snapshot = lir->snapshot();
    8388           0 :     Register temp = ToRegister(lir->getTemp(0));
    8389           0 :     if (lir->index()->isConstant()) {
    8390             :         int32_t nmin, nmax;
    8391           0 :         int32_t index = ToInt32(lir->index());
    8392           0 :         if (SafeAdd(index, min, &nmin) && SafeAdd(index, max, &nmax) && nmin >= 0) {
    8393           0 :             if (length->isRegister())
    8394           0 :                 bailoutCmp32(Assembler::BelowOrEqual, ToRegister(length), Imm32(nmax), snapshot);
    8395             :             else
    8396           0 :                 bailoutCmp32(Assembler::BelowOrEqual, ToAddress(length), Imm32(nmax), snapshot);
    8397           0 :             return;
    8398             :         }
    8399           0 :         masm.mov(ImmWord(index), temp);
    8400             :     } else {
    8401           0 :         masm.mov(ToRegister(lir->index()), temp);
    8402             :     }
    8403             : 
    8404             :     // If the minimum and maximum differ then do an underflow check first.
    8405             :     // If the two are the same then doing an unsigned comparison on the
    8406             :     // length will also catch a negative index.
    8407           0 :     if (min != max) {
    8408           0 :         if (min != 0) {
    8409           0 :             Label bail;
    8410           0 :             masm.branchAdd32(Assembler::Overflow, Imm32(min), temp, &bail);
    8411           0 :             bailoutFrom(&bail, snapshot);
    8412             :         }
    8413             : 
    8414           0 :         bailoutCmp32(Assembler::LessThan, temp, Imm32(0), snapshot);
    8415             : 
    8416           0 :         if (min != 0) {
    8417             :             int32_t diff;
    8418           0 :             if (SafeSub(max, min, &diff))
    8419           0 :                 max = diff;
    8420             :             else
    8421           0 :                 masm.sub32(Imm32(min), temp);
    8422             :         }
    8423             :     }
    8424             : 
    8425             :     // Compute the maximum possible index. No overflow check is needed when
    8426             :     // max > 0. We can only wraparound to a negative number, which will test as
    8427             :     // larger than all nonnegative numbers in the unsigned comparison, and the
    8428             :     // length is required to be nonnegative (else testing a negative length
    8429             :     // would succeed on any nonnegative index).
    8430           0 :     if (max != 0) {
    8431           0 :         if (max < 0) {
    8432           0 :             Label bail;
    8433           0 :             masm.branchAdd32(Assembler::Overflow, Imm32(max), temp, &bail);
    8434           0 :             bailoutFrom(&bail, snapshot);
    8435             :         } else {
    8436           0 :             masm.add32(Imm32(max), temp);
    8437             :         }
    8438             :     }
    8439             : 
    8440           0 :     if (length->isRegister())
    8441           0 :         bailoutCmp32(Assembler::BelowOrEqual, ToRegister(length), temp, snapshot);
    8442             :     else
    8443           0 :         bailoutCmp32(Assembler::BelowOrEqual, ToAddress(length), temp, snapshot);
    8444             : }
    8445             : 
    8446             : void
    8447           2 : CodeGenerator::visitBoundsCheckLower(LBoundsCheckLower* lir)
    8448             : {
    8449           2 :     int32_t min = lir->mir()->minimum();
    8450           4 :     bailoutCmp32(Assembler::LessThan, ToRegister(lir->index()), Imm32(min),
    8451           2 :                  lir->snapshot());
    8452           2 : }
    8453             : 
    8454             : class OutOfLineStoreElementHole : public OutOfLineCodeBase<CodeGenerator>
    8455             : {
    8456             :     LInstruction* ins_;
    8457             :     Label rejoinStore_;
    8458             : 
    8459             :   public:
    8460           1 :     explicit OutOfLineStoreElementHole(LInstruction* ins)
    8461           1 :       : ins_(ins)
    8462             :     {
    8463           1 :         MOZ_ASSERT(ins->isStoreElementHoleV() || ins->isStoreElementHoleT() ||
    8464             :                    ins->isFallibleStoreElementV() || ins->isFallibleStoreElementT());
    8465           1 :     }
    8466             : 
    8467           1 :     void accept(CodeGenerator* codegen) {
    8468           1 :         codegen->visitOutOfLineStoreElementHole(this);
    8469           1 :     }
    8470           1 :     LInstruction* ins() const {
    8471           1 :         return ins_;
    8472             :     }
    8473           1 :     Label* rejoinStore() {
    8474           1 :         return &rejoinStore_;
    8475             :     }
    8476             : };
    8477             : 
    8478             : void
    8479           0 : CodeGenerator::emitStoreHoleCheck(Register elements, const LAllocation* index,
    8480             :                                   int32_t offsetAdjustment, LSnapshot* snapshot)
    8481             : {
    8482           0 :     Label bail;
    8483           0 :     if (index->isConstant()) {
    8484           0 :         Address dest(elements, ToInt32(index) * sizeof(js::Value) + offsetAdjustment);
    8485           0 :         masm.branchTestMagic(Assembler::Equal, dest, &bail);
    8486             :     } else {
    8487           0 :         BaseIndex dest(elements, ToRegister(index), TimesEight, offsetAdjustment);
    8488           0 :         masm.branchTestMagic(Assembler::Equal, dest, &bail);
    8489             :     }
    8490           0 :     bailoutFrom(&bail, snapshot);
    8491           0 : }
    8492             : 
    8493             : static ConstantOrRegister
    8494           6 : ToConstantOrRegister(const LAllocation* value, MIRType valueType)
    8495             : {
    8496           6 :     if (value->isConstant())
    8497           0 :         return ConstantOrRegister(value->toConstant()->toJSValue());
    8498           6 :     return TypedOrValueRegister(valueType, ToAnyRegister(value));
    8499             : }
    8500             : 
    8501             : void
    8502           6 : CodeGenerator::emitStoreElementTyped(const LAllocation* value,
    8503             :                                      MIRType valueType, MIRType elementType,
    8504             :                                      Register elements, const LAllocation* index,
    8505             :                                      int32_t offsetAdjustment)
    8506             : {
    8507           6 :     ConstantOrRegister v = ToConstantOrRegister(value, valueType);
    8508           6 :     if (index->isConstant()) {
    8509           4 :         Address dest(elements, ToInt32(index) * sizeof(js::Value) + offsetAdjustment);
    8510           4 :         masm.storeUnboxedValue(v, valueType, dest, elementType);
    8511             :     } else {
    8512           2 :         BaseIndex dest(elements, ToRegister(index), TimesEight, offsetAdjustment);
    8513           2 :         masm.storeUnboxedValue(v, valueType, dest, elementType);
    8514             :     }
    8515           6 : }
    8516             : 
    8517             : void
    8518           4 : CodeGenerator::visitStoreElementT(LStoreElementT* store)
    8519             : {
    8520           4 :     Register elements = ToRegister(store->elements());
    8521           4 :     const LAllocation* index = store->index();
    8522             : 
    8523           4 :     if (store->mir()->needsBarrier())
    8524           0 :         emitPreBarrier(elements, index, store->mir()->offsetAdjustment());
    8525             : 
    8526           4 :     if (store->mir()->needsHoleCheck())
    8527           0 :         emitStoreHoleCheck(elements, index, store->mir()->offsetAdjustment(), store->snapshot());
    8528             : 
    8529           8 :     emitStoreElementTyped(store->value(),
    8530           4 :                           store->mir()->value()->type(), store->mir()->elementType(),
    8531           4 :                           elements, index, store->mir()->offsetAdjustment());
    8532           4 : }
    8533             : 
    8534             : void
    8535           0 : CodeGenerator::visitStoreElementV(LStoreElementV* lir)
    8536             : {
    8537           0 :     const ValueOperand value = ToValue(lir, LStoreElementV::Value);
    8538           0 :     Register elements = ToRegister(lir->elements());
    8539           0 :     const LAllocation* index = lir->index();
    8540             : 
    8541           0 :     if (lir->mir()->needsBarrier())
    8542           0 :         emitPreBarrier(elements, index, lir->mir()->offsetAdjustment());
    8543             : 
    8544           0 :     if (lir->mir()->needsHoleCheck())
    8545           0 :         emitStoreHoleCheck(elements, index, lir->mir()->offsetAdjustment(), lir->snapshot());
    8546             : 
    8547           0 :     if (lir->index()->isConstant()) {
    8548             :         Address dest(elements,
    8549           0 :                      ToInt32(lir->index()) * sizeof(js::Value) + lir->mir()->offsetAdjustment());
    8550           0 :         masm.storeValue(value, dest);
    8551             :     } else {
    8552             :         BaseIndex dest(elements, ToRegister(lir->index()), TimesEight,
    8553           0 :                        lir->mir()->offsetAdjustment());
    8554           0 :         masm.storeValue(value, dest);
    8555             :     }
    8556           0 : }
    8557             : 
    8558             : template <typename T> void
    8559           1 : CodeGenerator::emitStoreElementHoleT(T* lir)
    8560             : {
    8561             :     static_assert(std::is_same<T, LStoreElementHoleT>::value || std::is_same<T, LFallibleStoreElementT>::value,
    8562             :                   "emitStoreElementHoleT called with unexpected argument type");
    8563             : 
    8564           1 :     OutOfLineStoreElementHole* ool = new(alloc()) OutOfLineStoreElementHole(lir);
    8565           1 :     addOutOfLineCode(ool, lir->mir());
    8566             : 
    8567           1 :     Register obj = ToRegister(lir->object());
    8568           1 :     Register elements = ToRegister(lir->elements());
    8569           1 :     const LAllocation* index = lir->index();
    8570           1 :     RegisterOrInt32Constant key = ToRegisterOrInt32Constant(index);
    8571             : 
    8572           1 :     JSValueType unboxedType = lir->mir()->unboxedType();
    8573           1 :     if (unboxedType == JSVAL_TYPE_MAGIC) {
    8574           1 :         Address initLength(elements, ObjectElements::offsetOfInitializedLength());
    8575           1 :         masm.branch32(Assembler::BelowOrEqual, initLength, key, ool->entry());
    8576             : 
    8577           1 :         if (lir->mir()->needsBarrier())
    8578           1 :             emitPreBarrier(elements, index, 0);
    8579             : 
    8580           1 :         masm.bind(ool->rejoinStore());
    8581           1 :         emitStoreElementTyped(lir->value(), lir->mir()->value()->type(), lir->mir()->elementType(),
    8582             :                               elements, index, 0);
    8583             :     } else {
    8584           0 :         Register temp = ToRegister(lir->getTemp(0));
    8585           0 :         Address initLength(obj, UnboxedArrayObject::offsetOfCapacityIndexAndInitializedLength());
    8586           0 :         masm.load32(initLength, temp);
    8587           0 :         masm.and32(Imm32(UnboxedArrayObject::InitializedLengthMask), temp);
    8588           0 :         masm.branch32(Assembler::BelowOrEqual, temp, key, ool->entry());
    8589             : 
    8590           0 :         ConstantOrRegister v = ToConstantOrRegister(lir->value(), lir->mir()->value()->type());
    8591             : 
    8592           0 :         if (index->isConstant()) {
    8593           0 :             Address address(elements, ToInt32(index) * UnboxedTypeSize(unboxedType));
    8594           0 :             EmitUnboxedPreBarrier(masm, address, unboxedType);
    8595             : 
    8596           0 :             masm.bind(ool->rejoinStore());
    8597           0 :             masm.storeUnboxedProperty(address, unboxedType, v, nullptr);
    8598             :         } else {
    8599             :             BaseIndex address(elements, ToRegister(index),
    8600           0 :                               ScaleFromElemWidth(UnboxedTypeSize(unboxedType)));
    8601           0 :             EmitUnboxedPreBarrier(masm, address, unboxedType);
    8602             : 
    8603           0 :             masm.bind(ool->rejoinStore());
    8604           0 :             masm.storeUnboxedProperty(address, unboxedType, v, nullptr);
    8605             :         }
    8606             :     }
    8607             : 
    8608           1 :     masm.bind(ool->rejoin());
    8609           1 : }
    8610             : 
    8611             : void
    8612           1 : CodeGenerator::visitStoreElementHoleT(LStoreElementHoleT* lir)
    8613             : {
    8614           1 :     emitStoreElementHoleT(lir);
    8615           1 : }
    8616             : 
    8617             : template <typename T> void
    8618           0 : CodeGenerator::emitStoreElementHoleV(T* lir)
    8619             : {
    8620             :     static_assert(std::is_same<T, LStoreElementHoleV>::value || std::is_same<T, LFallibleStoreElementV>::value,
    8621             :                   "emitStoreElementHoleV called with unexpected parameter type");
    8622             : 
    8623           0 :     OutOfLineStoreElementHole* ool = new(alloc()) OutOfLineStoreElementHole(lir);
    8624           0 :     addOutOfLineCode(ool, lir->mir());
    8625             : 
    8626           0 :     Register obj = ToRegister(lir->object());
    8627           0 :     Register elements = ToRegister(lir->elements());
    8628           0 :     const LAllocation* index = lir->index();
    8629           0 :     const ValueOperand value = ToValue(lir, T::Value);
    8630           0 :     RegisterOrInt32Constant key = ToRegisterOrInt32Constant(index);
    8631             : 
    8632           0 :     JSValueType unboxedType = lir->mir()->unboxedType();
    8633           0 :     if (unboxedType == JSVAL_TYPE_MAGIC) {
    8634           0 :         Address initLength(elements, ObjectElements::offsetOfInitializedLength());
    8635           0 :         masm.branch32(Assembler::BelowOrEqual, initLength, key, ool->entry());
    8636             : 
    8637           0 :         if (lir->mir()->needsBarrier())
    8638           0 :             emitPreBarrier(elements, index, 0);
    8639             : 
    8640           0 :         masm.bind(ool->rejoinStore());
    8641           0 :         if (index->isConstant())
    8642           0 :             masm.storeValue(value, Address(elements, ToInt32(index) * sizeof(js::Value)));
    8643             :         else
    8644           0 :             masm.storeValue(value, BaseIndex(elements, ToRegister(index), TimesEight));
    8645             :     } else {
    8646           0 :         Register temp = ToRegister(lir->getTemp(0));
    8647           0 :         Address initLength(obj, UnboxedArrayObject::offsetOfCapacityIndexAndInitializedLength());
    8648           0 :         masm.load32(initLength, temp);
    8649           0 :         masm.and32(Imm32(UnboxedArrayObject::InitializedLengthMask), temp);
    8650           0 :         masm.branch32(Assembler::BelowOrEqual, temp, key, ool->entry());
    8651             : 
    8652           0 :         if (index->isConstant()) {
    8653           0 :             Address address(elements, ToInt32(index) * UnboxedTypeSize(unboxedType));
    8654           0 :             EmitUnboxedPreBarrier(masm, address, unboxedType);
    8655             : 
    8656           0 :             masm.bind(ool->rejoinStore());
    8657           0 :             masm.storeUnboxedProperty(address, unboxedType, ConstantOrRegister(value), nullptr);
    8658             :         } else {
    8659             :             BaseIndex address(elements, ToRegister(index),
    8660           0 :                               ScaleFromElemWidth(UnboxedTypeSize(unboxedType)));
    8661           0 :             EmitUnboxedPreBarrier(masm, address, unboxedType);
    8662             : 
    8663           0 :             masm.bind(ool->rejoinStore());
    8664           0 :             masm.storeUnboxedProperty(address, unboxedType, ConstantOrRegister(value), nullptr);
    8665             :         }
    8666             :     }
    8667             : 
    8668           0 :     masm.bind(ool->rejoin());
    8669           0 : }
    8670             : 
    8671             : void
    8672           0 : CodeGenerator::visitStoreElementHoleV(LStoreElementHoleV* lir)
    8673             : {
    8674           0 :     emitStoreElementHoleV(lir);
    8675           0 : }
    8676             : 
    8677             : typedef bool (*ThrowReadOnlyFn)(JSContext*, HandleObject, int32_t);
    8678           3 : static const VMFunction ThrowReadOnlyInfo =
    8679           6 :     FunctionInfo<ThrowReadOnlyFn>(ThrowReadOnlyError, "ThrowReadOnlyError");
    8680             : 
    8681             : void
    8682           0 : CodeGenerator::visitFallibleStoreElementT(LFallibleStoreElementT* lir)
    8683             : {
    8684           0 :     Register elements = ToRegister(lir->elements());
    8685             : 
    8686             :     // Handle frozen objects
    8687           0 :     Label isFrozen;
    8688           0 :     Address flags(elements, ObjectElements::offsetOfFlags());
    8689           0 :     if (!lir->mir()->strict()) {
    8690           0 :         masm.branchTest32(Assembler::NonZero, flags, Imm32(ObjectElements::FROZEN), &isFrozen);
    8691             :     } else {
    8692           0 :         Register object = ToRegister(lir->object());
    8693           0 :         const LAllocation* index = lir->index();
    8694             :         OutOfLineCode* ool;
    8695           0 :         if (index->isConstant()) {
    8696           0 :             ool = oolCallVM(ThrowReadOnlyInfo, lir,
    8697           0 :                             ArgList(object, Imm32(ToInt32(index))), StoreNothing());
    8698             :         } else {
    8699           0 :             ool = oolCallVM(ThrowReadOnlyInfo, lir,
    8700           0 :                             ArgList(object, ToRegister(index)), StoreNothing());
    8701             :         }
    8702           0 :         masm.branchTest32(Assembler::NonZero, flags, Imm32(ObjectElements::FROZEN), ool->entry());
    8703             :         // This OOL code should have thrown an exception, so will never return.
    8704             :         // So, do not bind ool->rejoin() anywhere, so that it implicitly (and without the cost
    8705             :         // of a jump) does a masm.assumeUnreachable().
    8706             :     }
    8707             : 
    8708           0 :     emitStoreElementHoleT(lir);
    8709             : 
    8710           0 :     masm.bind(&isFrozen);
    8711           0 : }
    8712             : 
    8713             : void
    8714           0 : CodeGenerator::visitFallibleStoreElementV(LFallibleStoreElementV* lir)
    8715             : {
    8716           0 :     Register elements = ToRegister(lir->elements());
    8717             : 
    8718             :     // Handle frozen objects
    8719           0 :     Label isFrozen;
    8720           0 :     Address flags(elements, ObjectElements::offsetOfFlags());
    8721           0 :     if (!lir->mir()->strict()) {
    8722           0 :         masm.branchTest32(Assembler::NonZero, flags, Imm32(ObjectElements::FROZEN), &isFrozen);
    8723             :     } else {
    8724           0 :         Register object = ToRegister(lir->object());
    8725           0 :         const LAllocation* index = lir->index();
    8726             :         OutOfLineCode* ool;
    8727           0 :         if (index->isConstant()) {
    8728           0 :             ool = oolCallVM(ThrowReadOnlyInfo, lir,
    8729           0 :                             ArgList(object, Imm32(ToInt32(index))), StoreNothing());
    8730             :         } else {
    8731           0 :             ool = oolCallVM(ThrowReadOnlyInfo, lir,
    8732           0 :                             ArgList(object, ToRegister(index)), StoreNothing());
    8733             :         }
    8734           0 :         masm.branchTest32(Assembler::NonZero, flags, Imm32(ObjectElements::FROZEN), ool->entry());
    8735             :         // This OOL code should have thrown an exception, so will never return.
    8736             :         // So, do not bind ool->rejoin() anywhere, so that it implicitly (and without the cost
    8737             :         // of a jump) does a masm.assumeUnreachable().
    8738             :     }
    8739             : 
    8740           0 :     emitStoreElementHoleV(lir);
    8741             : 
    8742           0 :     masm.bind(&isFrozen);
    8743           0 : }
    8744             : 
    8745             : typedef bool (*SetDenseOrUnboxedArrayElementFn)(JSContext*, HandleObject, int32_t,
    8746             :                                                 HandleValue, bool strict);
    8747           3 : static const VMFunction SetDenseOrUnboxedArrayElementInfo =
    8748           6 :     FunctionInfo<SetDenseOrUnboxedArrayElementFn>(SetDenseOrUnboxedArrayElement,
    8749             :                                                   "SetDenseOrUnboxedArrayElement");
    8750             : 
    8751             : void
    8752           1 : CodeGenerator::visitOutOfLineStoreElementHole(OutOfLineStoreElementHole* ool)
    8753             : {
    8754           1 :     Register object, elements;
    8755           1 :     LInstruction* ins = ool->ins();
    8756             :     const LAllocation* index;
    8757             :     MIRType valueType;
    8758           1 :     ConstantOrRegister value;
    8759             :     JSValueType unboxedType;
    8760           1 :     LDefinition *temp = nullptr;
    8761             : 
    8762           1 :     if (ins->isStoreElementHoleV()) {
    8763           0 :         LStoreElementHoleV* store = ins->toStoreElementHoleV();
    8764           0 :         object = ToRegister(store->object());
    8765           0 :         elements = ToRegister(store->elements());
    8766           0 :         index = store->index();
    8767           0 :         valueType = store->mir()->value()->type();
    8768           0 :         value = TypedOrValueRegister(ToValue(store, LStoreElementHoleV::Value));
    8769           0 :         unboxedType = store->mir()->unboxedType();
    8770           0 :         temp = store->getTemp(0);
    8771           1 :     } else if (ins->isFallibleStoreElementV()) {
    8772           0 :         LFallibleStoreElementV* store = ins->toFallibleStoreElementV();
    8773           0 :         object = ToRegister(store->object());
    8774           0 :         elements = ToRegister(store->elements());
    8775           0 :         index = store->index();
    8776           0 :         valueType = store->mir()->value()->type();
    8777           0 :         value = TypedOrValueRegister(ToValue(store, LFallibleStoreElementV::Value));
    8778           0 :         unboxedType = store->mir()->unboxedType();
    8779           0 :         temp = store->getTemp(0);
    8780           1 :     } else if (ins->isStoreElementHoleT()) {
    8781           1 :         LStoreElementHoleT* store = ins->toStoreElementHoleT();
    8782           1 :         object = ToRegister(store->object());
    8783           1 :         elements = ToRegister(store->elements());
    8784           1 :         index = store->index();
    8785           1 :         valueType = store->mir()->value()->type();
    8786           1 :         if (store->value()->isConstant())
    8787           0 :             value = ConstantOrRegister(store->value()->toConstant()->toJSValue());
    8788             :         else
    8789           1 :             value = TypedOrValueRegister(valueType, ToAnyRegister(store->value()));
    8790           1 :         unboxedType = store->mir()->unboxedType();
    8791           1 :         temp = store->getTemp(0);
    8792             :     } else { // ins->isFallibleStoreElementT()
    8793           0 :         LFallibleStoreElementT* store = ins->toFallibleStoreElementT();
    8794           0 :         object = ToRegister(store->object());
    8795           0 :         elements = ToRegister(store->elements());
    8796           0 :         index = store->index();
    8797           0 :         valueType = store->mir()->value()->type();
    8798           0 :         if (store->value()->isConstant())
    8799           0 :             value = ConstantOrRegister(store->value()->toConstant()->toJSValue());
    8800             :         else
    8801           0 :             value = TypedOrValueRegister(valueType, ToAnyRegister(store->value()));
    8802           0 :         unboxedType = store->mir()->unboxedType();
    8803           0 :         temp = store->getTemp(0);
    8804             :     }
    8805             : 
    8806           1 :     RegisterOrInt32Constant key = ToRegisterOrInt32Constant(index);
    8807             : 
    8808             :     // If index == initializedLength, try to bump the initialized length inline.
    8809             :     // If index > initializedLength, call a stub. Note that this relies on the
    8810             :     // condition flags sticking from the incoming branch.
    8811           2 :     Label callStub;
    8812             : #if defined(JS_CODEGEN_MIPS32) || defined(JS_CODEGEN_MIPS64)
    8813             :     // Had to reimplement for MIPS because there are no flags.
    8814             :     if (unboxedType == JSVAL_TYPE_MAGIC) {
    8815             :         Address initLength(elements, ObjectElements::offsetOfInitializedLength());
    8816             :         masm.branch32(Assembler::NotEqual, initLength, key, &callStub);
    8817             :     } else {
    8818             :         Address initLength(object, UnboxedArrayObject::offsetOfCapacityIndexAndInitializedLength());
    8819             :         masm.load32(initLength, ToRegister(temp));
    8820             :         masm.and32(Imm32(UnboxedArrayObject::InitializedLengthMask), ToRegister(temp));
    8821             :         masm.branch32(Assembler::NotEqual, ToRegister(temp), key, &callStub);
    8822             :     }
    8823             : #else
    8824           1 :     masm.j(Assembler::NotEqual, &callStub);
    8825             : #endif
    8826             : 
    8827           1 :     if (unboxedType == JSVAL_TYPE_MAGIC) {
    8828             :         // Check array capacity.
    8829           2 :         masm.branch32(Assembler::BelowOrEqual, Address(elements, ObjectElements::offsetOfCapacity()),
    8830           1 :                       key, &callStub);
    8831             : 
    8832             :         // Update initialized length. The capacity guard above ensures this won't overflow,
    8833             :         // due to MAX_DENSE_ELEMENTS_COUNT.
    8834           1 :         masm.inc32(&key);
    8835           1 :         masm.store32(key, Address(elements, ObjectElements::offsetOfInitializedLength()));
    8836             : 
    8837             :         // Update length if length < initializedLength.
    8838           2 :         Label dontUpdate;
    8839           2 :         masm.branch32(Assembler::AboveOrEqual, Address(elements, ObjectElements::offsetOfLength()),
    8840           1 :                       key, &dontUpdate);
    8841           1 :         masm.store32(key, Address(elements, ObjectElements::offsetOfLength()));
    8842           1 :         masm.bind(&dontUpdate);
    8843             : 
    8844           1 :         masm.dec32(&key);
    8845             :     } else {
    8846             :         // Check array capacity.
    8847           0 :         masm.checkUnboxedArrayCapacity(object, key, ToRegister(temp), &callStub);
    8848             : 
    8849             :         // Update initialized length.
    8850           0 :         masm.add32(Imm32(1), Address(object, UnboxedArrayObject::offsetOfCapacityIndexAndInitializedLength()));
    8851             : 
    8852             :         // Update length if length < initializedLength.
    8853           0 :         Address lengthAddr(object, UnboxedArrayObject::offsetOfLength());
    8854           0 :         Label dontUpdate;
    8855           0 :         masm.branch32(Assembler::Above, lengthAddr, key, &dontUpdate);
    8856           0 :         masm.add32(Imm32(1), lengthAddr);
    8857           0 :         masm.bind(&dontUpdate);
    8858             :     }
    8859             : 
    8860           2 :     if ((ins->isStoreElementHoleT() || ins->isFallibleStoreElementT()) &&
    8861           2 :         unboxedType == JSVAL_TYPE_MAGIC && valueType != MIRType::Double)
    8862             :     {
    8863             :         // The inline path for StoreElementHoleT and FallibleStoreElementT does not always store
    8864             :         // the type tag, so we do the store on the OOL path. We use MIRType::None for the element
    8865             :         // type so that storeElementTyped will always store the type tag.
    8866           1 :         if (ins->isStoreElementHoleT()) {
    8867           1 :             emitStoreElementTyped(ins->toStoreElementHoleT()->value(), valueType, MIRType::None,
    8868           1 :                                   elements, index, 0);
    8869           1 :             masm.jump(ool->rejoin());
    8870           0 :         } else if (ins->isFallibleStoreElementT()) {
    8871           0 :             emitStoreElementTyped(ins->toFallibleStoreElementT()->value(), valueType,
    8872           0 :                                   MIRType::None, elements, index, 0);
    8873           0 :             masm.jump(ool->rejoin());
    8874             :         }
    8875             :     } else {
    8876             :         // Jump to the inline path where we will store the value.
    8877           0 :         masm.jump(ool->rejoinStore());
    8878             :     }
    8879             : 
    8880           1 :     masm.bind(&callStub);
    8881           1 :     saveLive(ins);
    8882             : 
    8883           1 :     pushArg(Imm32(current->mir()->strict()));
    8884           1 :     pushArg(value);
    8885           1 :     if (index->isConstant())
    8886           0 :         pushArg(Imm32(ToInt32(index)));
    8887             :     else
    8888           1 :         pushArg(ToRegister(index));
    8889           1 :     pushArg(object);
    8890           1 :     callVM(SetDenseOrUnboxedArrayElementInfo, ins);
    8891             : 
    8892           1 :     restoreLive(ins);
    8893           1 :     masm.jump(ool->rejoin());
    8894           1 : }
    8895             : 
    8896             : template <typename T>
    8897             : static void
    8898           0 : StoreUnboxedPointer(MacroAssembler& masm, T address, MIRType type, const LAllocation* value,
    8899             :                     bool preBarrier)
    8900             : {
    8901           0 :     if (preBarrier)
    8902           0 :         masm.guardedCallPreBarrier(address, type);
    8903           0 :     if (value->isConstant()) {
    8904           0 :         Value v = value->toConstant()->toJSValue();
    8905           0 :         if (v.isGCThing()) {
    8906           0 :             masm.storePtr(ImmGCPtr(v.toGCThing()), address);
    8907             :         } else {
    8908           0 :             MOZ_ASSERT(v.isNull());
    8909           0 :             masm.storePtr(ImmWord(0), address);
    8910             :         }
    8911             :     } else {
    8912           0 :         masm.storePtr(ToRegister(value), address);
    8913             :     }
    8914           0 : }
    8915             : 
    8916             : void
    8917           0 : CodeGenerator::visitStoreUnboxedPointer(LStoreUnboxedPointer* lir)
    8918             : {
    8919             :     MIRType type;
    8920             :     int32_t offsetAdjustment;
    8921             :     bool preBarrier;
    8922           0 :     if (lir->mir()->isStoreUnboxedObjectOrNull()) {
    8923           0 :         type = MIRType::Object;
    8924           0 :         offsetAdjustment = lir->mir()->toStoreUnboxedObjectOrNull()->offsetAdjustment();
    8925           0 :         preBarrier = lir->mir()->toStoreUnboxedObjectOrNull()->preBarrier();
    8926           0 :     } else if (lir->mir()->isStoreUnboxedString()) {
    8927           0 :         type = MIRType::String;
    8928           0 :         offsetAdjustment = lir->mir()->toStoreUnboxedString()->offsetAdjustment();
    8929           0 :         preBarrier = lir->mir()->toStoreUnboxedString()->preBarrier();
    8930             :     } else {
    8931           0 :         MOZ_CRASH();
    8932             :     }
    8933             : 
    8934           0 :     Register elements = ToRegister(lir->elements());
    8935           0 :     const LAllocation* index = lir->index();
    8936           0 :     const LAllocation* value = lir->value();
    8937             : 
    8938           0 :     if (index->isConstant()) {
    8939           0 :         Address address(elements, ToInt32(index) * sizeof(uintptr_t) + offsetAdjustment);
    8940           0 :         StoreUnboxedPointer(masm, address, type, value, preBarrier);
    8941             :     } else {
    8942           0 :         BaseIndex address(elements, ToRegister(index), ScalePointer, offsetAdjustment);
    8943           0 :         StoreUnboxedPointer(masm, address, type, value, preBarrier);
    8944             :     }
    8945           0 : }
    8946             : 
    8947             : typedef bool (*ConvertUnboxedObjectToNativeFn)(JSContext*, JSObject*);
    8948           3 : static const VMFunction ConvertUnboxedPlainObjectToNativeInfo =
    8949           6 :     FunctionInfo<ConvertUnboxedObjectToNativeFn>(UnboxedPlainObject::convertToNative,
    8950             :                                                  "UnboxedPlainObject::convertToNative");
    8951           3 : static const VMFunction ConvertUnboxedArrayObjectToNativeInfo =
    8952           6 :     FunctionInfo<ConvertUnboxedObjectToNativeFn>(UnboxedArrayObject::convertToNative,
    8953             :                                                  "UnboxedArrayObject::convertToNative");
    8954             : 
    8955             : void
    8956           0 : CodeGenerator::visitConvertUnboxedObjectToNative(LConvertUnboxedObjectToNative* lir)
    8957             : {
    8958           0 :     Register object = ToRegister(lir->getOperand(0));
    8959             : 
    8960           0 :     OutOfLineCode* ool = oolCallVM(lir->mir()->group()->unboxedLayoutDontCheckGeneration().isArray()
    8961             :                                    ? ConvertUnboxedArrayObjectToNativeInfo
    8962             :                                    : ConvertUnboxedPlainObjectToNativeInfo,
    8963           0 :                                    lir, ArgList(object), StoreNothing());
    8964             : 
    8965           0 :     masm.branchPtr(Assembler::Equal, Address(object, JSObject::offsetOfGroup()),
    8966           0 :                    ImmGCPtr(lir->mir()->group()), ool->entry());
    8967           0 :     masm.bind(ool->rejoin());
    8968           0 : }
    8969             : 
    8970             : typedef bool (*ArrayPopShiftFn)(JSContext*, HandleObject, MutableHandleValue);
    8971           3 : static const VMFunction ArrayPopDenseInfo =
    8972           6 :     FunctionInfo<ArrayPopShiftFn>(jit::ArrayPopDense, "ArrayPopDense");
    8973           3 : static const VMFunction ArrayShiftDenseInfo =
    8974           6 :     FunctionInfo<ArrayPopShiftFn>(jit::ArrayShiftDense, "ArrayShiftDense");
    8975             : 
    8976             : void
    8977           0 : CodeGenerator::emitArrayPopShift(LInstruction* lir, const MArrayPopShift* mir, Register obj,
    8978             :                                  Register elementsTemp, Register lengthTemp, TypedOrValueRegister out)
    8979             : {
    8980             :     OutOfLineCode* ool;
    8981             : 
    8982           0 :     if (mir->mode() == MArrayPopShift::Pop) {
    8983           0 :         ool = oolCallVM(ArrayPopDenseInfo, lir, ArgList(obj), StoreValueTo(out));
    8984             :     } else {
    8985           0 :         MOZ_ASSERT(mir->mode() == MArrayPopShift::Shift);
    8986           0 :         ool = oolCallVM(ArrayShiftDenseInfo, lir, ArgList(obj), StoreValueTo(out));
    8987             :     }
    8988             : 
    8989             :     // VM call if a write barrier is necessary.
    8990           0 :     masm.branchTestNeedsIncrementalBarrier(Assembler::NonZero, ool->entry());
    8991             : 
    8992             :     // Load elements and length, and VM call if length != initializedLength.
    8993           0 :     RegisterOrInt32Constant key = RegisterOrInt32Constant(lengthTemp);
    8994           0 :     if (mir->unboxedType() == JSVAL_TYPE_MAGIC) {
    8995           0 :         masm.loadPtr(Address(obj, NativeObject::offsetOfElements()), elementsTemp);
    8996           0 :         masm.load32(Address(elementsTemp, ObjectElements::offsetOfLength()), lengthTemp);
    8997             : 
    8998           0 :         Address initLength(elementsTemp, ObjectElements::offsetOfInitializedLength());
    8999           0 :         masm.branch32(Assembler::NotEqual, initLength, key, ool->entry());
    9000             :     } else {
    9001           0 :         masm.loadPtr(Address(obj, UnboxedArrayObject::offsetOfElements()), elementsTemp);
    9002           0 :         masm.load32(Address(obj, UnboxedArrayObject::offsetOfCapacityIndexAndInitializedLength()), lengthTemp);
    9003           0 :         masm.and32(Imm32(UnboxedArrayObject::InitializedLengthMask), lengthTemp);
    9004             : 
    9005           0 :         Address lengthAddr(obj, UnboxedArrayObject::offsetOfLength());
    9006           0 :         masm.branch32(Assembler::NotEqual, lengthAddr, key, ool->entry());
    9007             :     }
    9008             : 
    9009             :     // Test for length != 0. On zero length either take a VM call or generate
    9010             :     // an undefined value, depending on whether the call is known to produce
    9011             :     // undefined.
    9012           0 :     Label done;
    9013           0 :     if (mir->maybeUndefined()) {
    9014           0 :         Label notEmpty;
    9015           0 :         masm.branchTest32(Assembler::NonZero, lengthTemp, lengthTemp, &notEmpty);
    9016             : 
    9017             :         // According to the spec we need to set the length 0 (which is already 0).
    9018             :         // This is observable when the array length is made non-writable.
    9019             :         // Handle this case in the OOL. When freezing an unboxed array it is converted
    9020             :         // to an normal array.
    9021           0 :         if (mir->unboxedType() == JSVAL_TYPE_MAGIC) {
    9022           0 :             Address elementFlags(elementsTemp, ObjectElements::offsetOfFlags());
    9023           0 :             Imm32 bit(ObjectElements::NONWRITABLE_ARRAY_LENGTH);
    9024           0 :             masm.branchTest32(Assembler::NonZero, elementFlags, bit, ool->entry());
    9025             :         }
    9026             : 
    9027           0 :         masm.moveValue(UndefinedValue(), out.valueReg());
    9028           0 :         masm.jump(&done);
    9029           0 :         masm.bind(&notEmpty);
    9030             :     } else {
    9031           0 :         masm.branchTest32(Assembler::Zero, lengthTemp, lengthTemp, ool->entry());
    9032             :     }
    9033             : 
    9034           0 :     masm.dec32(&key);
    9035             : 
    9036           0 :     if (mir->mode() == MArrayPopShift::Pop) {
    9037           0 :         if (mir->unboxedType() == JSVAL_TYPE_MAGIC) {
    9038           0 :             BaseIndex addr(elementsTemp, lengthTemp, TimesEight);
    9039           0 :             masm.loadElementTypedOrValue(addr, out, mir->needsHoleCheck(), ool->entry());
    9040             :         } else {
    9041           0 :             size_t elemSize = UnboxedTypeSize(mir->unboxedType());
    9042           0 :             BaseIndex addr(elementsTemp, lengthTemp, ScaleFromElemWidth(elemSize));
    9043           0 :             masm.loadUnboxedProperty(addr, mir->unboxedType(), out);
    9044             :         }
    9045             :     } else {
    9046           0 :         MOZ_ASSERT(mir->mode() == MArrayPopShift::Shift);
    9047           0 :         Address addr(elementsTemp, 0);
    9048           0 :         if (mir->unboxedType() == JSVAL_TYPE_MAGIC)
    9049           0 :             masm.loadElementTypedOrValue(addr, out, mir->needsHoleCheck(), ool->entry());
    9050             :         else
    9051           0 :             masm.loadUnboxedProperty(addr, mir->unboxedType(), out);
    9052             :     }
    9053             : 
    9054           0 :     if (mir->unboxedType() == JSVAL_TYPE_MAGIC) {
    9055             :         // Handle the failure case when the array length is non-writable in the
    9056             :         // OOL path.  (Unlike in the adding-an-element cases, we can't rely on the
    9057             :         // capacity <= length invariant for such arrays to avoid an explicit
    9058             :         // check.)
    9059           0 :         Address elementFlags(elementsTemp, ObjectElements::offsetOfFlags());
    9060           0 :         Imm32 bit(ObjectElements::NONWRITABLE_ARRAY_LENGTH);
    9061           0 :         masm.branchTest32(Assembler::NonZero, elementFlags, bit, ool->entry());
    9062             :     }
    9063             : 
    9064           0 :     if (mir->mode() == MArrayPopShift::Shift) {
    9065             :         // Don't save the elementsTemp register.
    9066           0 :         LiveRegisterSet temps;
    9067           0 :         temps.add(elementsTemp);
    9068             : 
    9069           0 :         saveVolatile(temps);
    9070           0 :         masm.setupUnalignedABICall(elementsTemp);
    9071           0 :         masm.passABIArg(obj);
    9072           0 :         masm.callWithABI(JS_FUNC_TO_DATA_PTR(void*, js::ArrayShiftMoveElements));
    9073           0 :         restoreVolatile(temps);
    9074             : 
    9075           0 :         if (mir->unboxedType() == JSVAL_TYPE_MAGIC) {
    9076             :             // Reload elementsTemp as ArrayShiftMoveElements may have moved it.
    9077           0 :             masm.loadPtr(Address(obj, NativeObject::offsetOfElements()), elementsTemp);
    9078             :         }
    9079             :     }
    9080             : 
    9081           0 :     if (mir->unboxedType() == JSVAL_TYPE_MAGIC) {
    9082             :         // Now adjust length and initializedLength.
    9083           0 :         masm.store32(lengthTemp, Address(elementsTemp, ObjectElements::offsetOfLength()));
    9084           0 :         masm.store32(lengthTemp, Address(elementsTemp, ObjectElements::offsetOfInitializedLength()));
    9085             :     } else {
    9086             :         // Unboxed arrays always have writable lengths. Adjust length and
    9087             :         // initializedLength.
    9088           0 :         masm.store32(lengthTemp, Address(obj, UnboxedArrayObject::offsetOfLength()));
    9089           0 :         masm.add32(Imm32(-1), Address(obj, UnboxedArrayObject::offsetOfCapacityIndexAndInitializedLength()));
    9090             :     }
    9091             : 
    9092           0 :     masm.bind(&done);
    9093           0 :     masm.bind(ool->rejoin());
    9094           0 : }
    9095             : 
    9096             : void
    9097           0 : CodeGenerator::visitArrayPopShiftV(LArrayPopShiftV* lir)
    9098             : {
    9099           0 :     Register obj = ToRegister(lir->object());
    9100           0 :     Register elements = ToRegister(lir->temp0());
    9101           0 :     Register length = ToRegister(lir->temp1());
    9102           0 :     TypedOrValueRegister out(ToOutValue(lir));
    9103           0 :     emitArrayPopShift(lir, lir->mir(), obj, elements, length, out);
    9104           0 : }
    9105             : 
    9106             : void
    9107           0 : CodeGenerator::visitArrayPopShiftT(LArrayPopShiftT* lir)
    9108             : {
    9109           0 :     Register obj = ToRegister(lir->object());
    9110           0 :     Register elements = ToRegister(lir->temp0());
    9111           0 :     Register length = ToRegister(lir->temp1());
    9112           0 :     TypedOrValueRegister out(lir->mir()->type(), ToAnyRegister(lir->output()));
    9113           0 :     emitArrayPopShift(lir, lir->mir(), obj, elements, length, out);
    9114           0 : }
    9115             : 
    9116             : typedef bool (*ArrayPushDenseFn)(JSContext*, HandleObject, HandleValue, uint32_t*);
    9117           3 : static const VMFunction ArrayPushDenseInfo =
    9118           6 :     FunctionInfo<ArrayPushDenseFn>(jit::ArrayPushDense, "ArrayPushDense");
    9119             : 
    9120             : void
    9121           1 : CodeGenerator::emitArrayPush(LInstruction* lir, const MArrayPush* mir, Register obj,
    9122             :                              const ConstantOrRegister& value, Register elementsTemp, Register length)
    9123             : {
    9124           1 :     OutOfLineCode* ool = oolCallVM(ArrayPushDenseInfo, lir, ArgList(obj, value), StoreRegisterTo(length));
    9125             : 
    9126           1 :     RegisterOrInt32Constant key = RegisterOrInt32Constant(length);
    9127           1 :     if (mir->unboxedType() == JSVAL_TYPE_MAGIC) {
    9128             :         // Load elements and length.
    9129           1 :         masm.loadPtr(Address(obj, NativeObject::offsetOfElements()), elementsTemp);
    9130           1 :         masm.load32(Address(elementsTemp, ObjectElements::offsetOfLength()), length);
    9131             : 
    9132             :         // Guard length == initializedLength.
    9133           1 :         Address initLength(elementsTemp, ObjectElements::offsetOfInitializedLength());
    9134           1 :         masm.branch32(Assembler::NotEqual, initLength, key, ool->entry());
    9135             : 
    9136             :         // Guard length < capacity.
    9137           1 :         Address capacity(elementsTemp, ObjectElements::offsetOfCapacity());
    9138           1 :         masm.branch32(Assembler::BelowOrEqual, capacity, key, ool->entry());
    9139             : 
    9140             :         // Do the store.
    9141           1 :         masm.storeConstantOrRegister(value, BaseIndex(elementsTemp, length, TimesEight));
    9142             :     } else {
    9143             :         // Load initialized length.
    9144           0 :         masm.load32(Address(obj, UnboxedArrayObject::offsetOfCapacityIndexAndInitializedLength()), length);
    9145           0 :         masm.and32(Imm32(UnboxedArrayObject::InitializedLengthMask), length);
    9146             : 
    9147             :         // Guard length == initializedLength.
    9148           0 :         Address lengthAddr(obj, UnboxedArrayObject::offsetOfLength());
    9149           0 :         masm.branch32(Assembler::NotEqual, lengthAddr, key, ool->entry());
    9150             : 
    9151             :         // Guard length < capacity.
    9152           0 :         masm.checkUnboxedArrayCapacity(obj, key, elementsTemp, ool->entry());
    9153             : 
    9154             :         // Load elements and do the store.
    9155           0 :         masm.loadPtr(Address(obj, UnboxedArrayObject::offsetOfElements()), elementsTemp);
    9156           0 :         size_t elemSize = UnboxedTypeSize(mir->unboxedType());
    9157           0 :         BaseIndex addr(elementsTemp, length, ScaleFromElemWidth(elemSize));
    9158           0 :         masm.storeUnboxedProperty(addr, mir->unboxedType(), value, nullptr);
    9159             :     }
    9160             : 
    9161           1 :     masm.inc32(&key);
    9162             : 
    9163             :     // Update length and initialized length.
    9164           1 :     if (mir->unboxedType() == JSVAL_TYPE_MAGIC) {
    9165           1 :         masm.store32(length, Address(elementsTemp, ObjectElements::offsetOfLength()));
    9166           1 :         masm.store32(length, Address(elementsTemp, ObjectElements::offsetOfInitializedLength()));
    9167             :     } else {
    9168           0 :         masm.store32(length, Address(obj, UnboxedArrayObject::offsetOfLength()));
    9169           0 :         masm.add32(Imm32(1), Address(obj, UnboxedArrayObject::offsetOfCapacityIndexAndInitializedLength()));
    9170             :     }
    9171             : 
    9172           1 :     masm.bind(ool->rejoin());
    9173           1 : }
    9174             : 
    9175             : void
    9176           0 : CodeGenerator::visitArrayPushV(LArrayPushV* lir)
    9177             : {
    9178           0 :     Register obj = ToRegister(lir->object());
    9179           0 :     Register elementsTemp = ToRegister(lir->temp());
    9180           0 :     Register length = ToRegister(lir->output());
    9181           0 :     ConstantOrRegister value = TypedOrValueRegister(ToValue(lir, LArrayPushV::Value));
    9182           0 :     emitArrayPush(lir, lir->mir(), obj, value, elementsTemp, length);
    9183           0 : }
    9184             : 
    9185             : void
    9186           1 : CodeGenerator::visitArrayPushT(LArrayPushT* lir)
    9187             : {
    9188           1 :     Register obj = ToRegister(lir->object());
    9189           1 :     Register elementsTemp = ToRegister(lir->temp());
    9190           1 :     Register length = ToRegister(lir->output());
    9191           1 :     ConstantOrRegister value;
    9192           1 :     if (lir->value()->isConstant())
    9193           0 :         value = ConstantOrRegister(lir->value()->toConstant()->toJSValue());
    9194             :     else
    9195           1 :         value = TypedOrValueRegister(lir->mir()->value()->type(), ToAnyRegister(lir->value()));
    9196           1 :     emitArrayPush(lir, lir->mir(), obj, value, elementsTemp, length);
    9197           1 : }
    9198             : 
    9199             : typedef JSObject* (*ArraySliceDenseFn)(JSContext*, HandleObject, int32_t, int32_t, HandleObject);
    9200           3 : static const VMFunction ArraySliceDenseInfo =
    9201           6 :     FunctionInfo<ArraySliceDenseFn>(array_slice_dense, "array_slice_dense");
    9202             : 
    9203             : void
    9204           0 : CodeGenerator::visitArraySlice(LArraySlice* lir)
    9205             : {
    9206           0 :     Register object = ToRegister(lir->object());
    9207           0 :     Register begin = ToRegister(lir->begin());
    9208           0 :     Register end = ToRegister(lir->end());
    9209           0 :     Register temp1 = ToRegister(lir->temp1());
    9210           0 :     Register temp2 = ToRegister(lir->temp2());
    9211             : 
    9212           0 :     Label call, fail;
    9213             : 
    9214             :     // Try to allocate an object.
    9215           0 :     masm.createGCObject(temp1, temp2, lir->mir()->templateObj(), lir->mir()->initialHeap(), &fail);
    9216             : 
    9217             :     // Fixup the group of the result in case it doesn't match the template object.
    9218           0 :     masm.loadPtr(Address(object, JSObject::offsetOfGroup()), temp2);
    9219           0 :     masm.storePtr(temp2, Address(temp1, JSObject::offsetOfGroup()));
    9220             : 
    9221           0 :     masm.jump(&call);
    9222             :     {
    9223           0 :         masm.bind(&fail);
    9224           0 :         masm.movePtr(ImmPtr(nullptr), temp1);
    9225             :     }
    9226           0 :     masm.bind(&call);
    9227             : 
    9228           0 :     pushArg(temp1);
    9229           0 :     pushArg(end);
    9230           0 :     pushArg(begin);
    9231           0 :     pushArg(object);
    9232           0 :     callVM(ArraySliceDenseInfo, lir);
    9233           0 : }
    9234             : 
    9235             : typedef JSString* (*ArrayJoinFn)(JSContext*, HandleObject, HandleString);
    9236           3 : static const VMFunction ArrayJoinInfo = FunctionInfo<ArrayJoinFn>(jit::ArrayJoin, "ArrayJoin");
    9237             : 
    9238             : void
    9239           1 : CodeGenerator::visitArrayJoin(LArrayJoin* lir)
    9240             : {
    9241           1 :     pushArg(ToRegister(lir->separator()));
    9242           1 :     pushArg(ToRegister(lir->array()));
    9243             : 
    9244           1 :     callVM(ArrayJoinInfo, lir);
    9245           1 : }
    9246             : 
    9247             : typedef JSObject* (*ValueToIteratorFn)(JSContext*, uint32_t, HandleValue);
    9248           3 : static const VMFunction ValueToIteratorInfo =
    9249           6 :     FunctionInfo<ValueToIteratorFn>(ValueToIterator, "ValueToIterator");
    9250             : 
    9251             : void
    9252           0 : CodeGenerator::visitCallIteratorStartV(LCallIteratorStartV* lir)
    9253             : {
    9254           0 :     pushArg(ToValue(lir, LCallIteratorStartV::Value));
    9255           0 :     pushArg(Imm32(lir->mir()->flags()));
    9256           0 :     callVM(ValueToIteratorInfo, lir);
    9257           0 : }
    9258             : 
    9259             : typedef JSObject* (*GetIteratorFn)(JSContext*, HandleObject, uint32_t);
    9260           3 : static const VMFunction GetIteratorInfo =
    9261           6 :     FunctionInfo<GetIteratorFn>(GetIterator, "GetIterator");
    9262             : 
    9263             : void
    9264           0 : CodeGenerator::visitCallIteratorStartO(LCallIteratorStartO* lir)
    9265             : {
    9266           0 :     pushArg(Imm32(lir->mir()->flags()));
    9267           0 :     pushArg(ToRegister(lir->object()));
    9268           0 :     callVM(GetIteratorInfo, lir);
    9269           0 : }
    9270             : 
    9271             : void
    9272           0 : CodeGenerator::branchIfNotEmptyObjectElements(Register obj, Label* target)
    9273             : {
    9274           0 :     Label emptyObj;
    9275           0 :     masm.branchPtr(Assembler::Equal,
    9276           0 :                    Address(obj, NativeObject::offsetOfElements()),
    9277             :                    ImmPtr(js::emptyObjectElements),
    9278           0 :                    &emptyObj);
    9279           0 :     masm.branchPtr(Assembler::NotEqual,
    9280           0 :                    Address(obj, NativeObject::offsetOfElements()),
    9281             :                    ImmPtr(js::emptyObjectElementsShared),
    9282           0 :                    target);
    9283           0 :     masm.bind(&emptyObj);
    9284           0 : }
    9285             : 
    9286             : void
    9287           0 : CodeGenerator::visitIteratorStartO(LIteratorStartO* lir)
    9288             : {
    9289           0 :     const Register obj = ToRegister(lir->object());
    9290           0 :     const Register output = ToRegister(lir->output());
    9291             : 
    9292           0 :     uint32_t flags = lir->mir()->flags();
    9293             : 
    9294           0 :     OutOfLineCode* ool = oolCallVM(GetIteratorInfo, lir,
    9295           0 :                                    ArgList(obj, Imm32(flags)), StoreRegisterTo(output));
    9296             : 
    9297           0 :     const Register temp1 = ToRegister(lir->temp1());
    9298           0 :     const Register temp2 = ToRegister(lir->temp2());
    9299           0 :     const Register niTemp = ToRegister(lir->temp3()); // Holds the NativeIterator object.
    9300             : 
    9301             :     // Iterators other than for-in should use LCallIteratorStart.
    9302           0 :     MOZ_ASSERT(flags == JSITER_ENUMERATE);
    9303             : 
    9304             :     // Fetch the most recent iterator and ensure it's not nullptr.
    9305           0 :     masm.loadPtr(AbsoluteAddress(gen->compartment->addressOfLastCachedNativeIterator()), output);
    9306           0 :     masm.branchTestPtr(Assembler::Zero, output, output, ool->entry());
    9307             : 
    9308             :     // Load NativeIterator.
    9309           0 :     masm.loadObjPrivate(output, JSObject::ITER_CLASS_NFIXED_SLOTS, niTemp);
    9310             : 
    9311             :     // Ensure the |active| and |unreusable| bits are not set.
    9312           0 :     masm.branchTest32(Assembler::NonZero, Address(niTemp, offsetof(NativeIterator, flags)),
    9313           0 :                       Imm32(JSITER_ACTIVE|JSITER_UNREUSABLE), ool->entry());
    9314             : 
    9315             :     // Load the iterator's receiver guard array.
    9316           0 :     masm.loadPtr(Address(niTemp, offsetof(NativeIterator, guard_array)), temp2);
    9317             : 
    9318             :     // Compare object with the first receiver guard. The last iterator can only
    9319             :     // match for native objects and unboxed objects.
    9320             :     {
    9321           0 :         Address groupAddr(temp2, offsetof(ReceiverGuard, group));
    9322           0 :         Address shapeAddr(temp2, offsetof(ReceiverGuard, shape));
    9323           0 :         Label guardDone, unboxedObject, noExpando;
    9324             :         // This is a guard for an unboxed object.
    9325           0 :         masm.branchPtr(Assembler::NotEqual, groupAddr, ImmWord(0), &unboxedObject);
    9326             : 
    9327             :         // Guard for a normal object, make sure the shape matches.
    9328           0 :         masm.loadObjShape(obj, temp1);
    9329           0 :         masm.branchPtr(Assembler::NotEqual, shapeAddr, temp1, ool->entry());
    9330             : 
    9331             :         // Ensure the object does not have any elements. The presence of dense
    9332             :         // elements is not captured by the shape tests above.
    9333           0 :         branchIfNotEmptyObjectElements(obj, ool->entry());
    9334           0 :         masm.jump(&guardDone);
    9335             : 
    9336           0 :         masm.bind(&unboxedObject);
    9337           0 :         masm.loadObjGroup(obj, temp1);
    9338           0 :         masm.branchPtr(Assembler::NotEqual, groupAddr, temp1, ool->entry());
    9339           0 :         masm.loadPtr(Address(obj, UnboxedPlainObject::offsetOfExpando()), temp1);
    9340           0 :         masm.branchTestPtr(Assembler::Zero, temp1, temp1, &noExpando);
    9341           0 :         branchIfNotEmptyObjectElements(temp1, ool->entry());
    9342           0 :         masm.loadObjShape(temp1, temp1);
    9343           0 :         masm.bind(&noExpando);
    9344           0 :         masm.branchPtr(Assembler::NotEqual, shapeAddr, temp1, ool->entry());
    9345           0 :         masm.bind(&guardDone);
    9346             :     }
    9347             : 
    9348             :     // Compare shape of object's prototype with the second shape. The prototype
    9349             :     // must be native, as unboxed objects cannot be prototypes (they cannot
    9350             :     // have the delegate flag set). Also check for the absence of dense elements.
    9351           0 :     Address prototypeShapeAddr(temp2, sizeof(ReceiverGuard) + offsetof(ReceiverGuard, shape));
    9352           0 :     masm.loadObjProto(obj, temp1);
    9353           0 :     branchIfNotEmptyObjectElements(temp1, ool->entry());
    9354           0 :     masm.loadObjShape(temp1, temp1);
    9355           0 :     masm.branchPtr(Assembler::NotEqual, prototypeShapeAddr, temp1, ool->entry());
    9356             : 
    9357             :     // Ensure the object's prototype's prototype is nullptr. The last native
    9358             :     // iterator will always have a prototype chain length of one (i.e. it must
    9359             :     // be a plain object), so we do not need to generate a loop here.
    9360           0 :     masm.loadObjProto(obj, temp1);
    9361           0 :     masm.loadObjProto(temp1, temp1);
    9362           0 :     masm.branchTestPtr(Assembler::NonZero, temp1, temp1, ool->entry());
    9363             : 
    9364             :     // Pre-write barrier for store to 'obj'.
    9365           0 :     masm.guardedCallPreBarrier(Address(niTemp, offsetof(NativeIterator, obj)), MIRType::Object);
    9366             : 
    9367             :     // Mark iterator as active.
    9368           0 :     masm.storePtr(obj, Address(niTemp, offsetof(NativeIterator, obj)));
    9369           0 :     masm.or32(Imm32(JSITER_ACTIVE), Address(niTemp, offsetof(NativeIterator, flags)));
    9370             : 
    9371             :     // Post-write barrier for stores to 'obj'. The iterator JSObject is never
    9372             :     // nursery allocated. Put this in the whole cell buffer is we wrote a
    9373             :     // nursery pointer into it.
    9374             :     {
    9375           0 :         Label skipBarrier;
    9376           0 :         masm.branchPtrInNurseryChunk(Assembler::NotEqual, obj, temp1, &skipBarrier);
    9377             : 
    9378           0 :         LiveRegisterSet temps;
    9379           0 :         temps.add(temp1);
    9380           0 :         temps.add(temp2);
    9381           0 :         saveVolatile(temps);
    9382           0 :         emitPostWriteBarrier(output);
    9383           0 :         restoreVolatile(temps);
    9384           0 :         masm.bind(&skipBarrier);
    9385             :     }
    9386             : 
    9387             :     // Chain onto the active iterator stack.
    9388           0 :     masm.loadPtr(AbsoluteAddress(gen->compartment->addressOfEnumerators()), temp1);
    9389             : 
    9390             :     // ni->next = list
    9391           0 :     masm.storePtr(temp1, Address(niTemp, NativeIterator::offsetOfNext()));
    9392             : 
    9393             :     // ni->prev = list->prev
    9394           0 :     masm.loadPtr(Address(temp1, NativeIterator::offsetOfPrev()), temp2);
    9395           0 :     masm.storePtr(temp2, Address(niTemp, NativeIterator::offsetOfPrev()));
    9396             : 
    9397             :     // list->prev->next = ni
    9398           0 :     masm.storePtr(niTemp, Address(temp2, NativeIterator::offsetOfNext()));
    9399             : 
    9400             :     // list->prev = ni
    9401           0 :     masm.storePtr(niTemp, Address(temp1, NativeIterator::offsetOfPrev()));
    9402             : 
    9403           0 :     masm.bind(ool->rejoin());
    9404           0 : }
    9405             : 
    9406             : static void
    9407           0 : LoadNativeIterator(MacroAssembler& masm, Register obj, Register dest, Label* failures)
    9408             : {
    9409           0 :     MOZ_ASSERT(obj != dest);
    9410             : 
    9411             :     // Test class.
    9412           0 :     masm.branchTestObjClass(Assembler::NotEqual, obj, dest, &PropertyIteratorObject::class_, failures);
    9413             : 
    9414             :     // Load NativeIterator object.
    9415           0 :     masm.loadObjPrivate(obj, JSObject::ITER_CLASS_NFIXED_SLOTS, dest);
    9416           0 : }
    9417             : 
    9418             : typedef bool (*IteratorMoreFn)(JSContext*, HandleObject, MutableHandleValue);
    9419           3 : static const VMFunction IteratorMoreInfo =
    9420           6 :     FunctionInfo<IteratorMoreFn>(IteratorMore, "IteratorMore");
    9421             : 
    9422             : void
    9423           0 : CodeGenerator::visitIteratorMore(LIteratorMore* lir)
    9424             : {
    9425           0 :     const Register obj = ToRegister(lir->object());
    9426           0 :     const ValueOperand output = ToOutValue(lir);
    9427           0 :     const Register temp = ToRegister(lir->temp());
    9428             : 
    9429           0 :     OutOfLineCode* ool = oolCallVM(IteratorMoreInfo, lir, ArgList(obj), StoreValueTo(output));
    9430             : 
    9431           0 :     Register outputScratch = output.scratchReg();
    9432           0 :     LoadNativeIterator(masm, obj, outputScratch, ool->entry());
    9433             : 
    9434           0 :     masm.branchTest32(Assembler::NonZero, Address(outputScratch, offsetof(NativeIterator, flags)),
    9435           0 :                       Imm32(JSITER_FOREACH), ool->entry());
    9436             : 
    9437             :     // If props_cursor < props_end, load the next string and advance the cursor.
    9438             :     // Else, return MagicValue(JS_NO_ITER_VALUE).
    9439           0 :     Label iterDone;
    9440           0 :     Address cursorAddr(outputScratch, offsetof(NativeIterator, props_cursor));
    9441           0 :     Address cursorEndAddr(outputScratch, offsetof(NativeIterator, props_end));
    9442           0 :     masm.loadPtr(cursorAddr, temp);
    9443           0 :     masm.branchPtr(Assembler::BelowOrEqual, cursorEndAddr, temp, &iterDone);
    9444             : 
    9445             :     // Get next string.
    9446           0 :     masm.loadPtr(Address(temp, 0), temp);
    9447             : 
    9448             :     // Increase the cursor.
    9449           0 :     masm.addPtr(Imm32(sizeof(JSString*)), cursorAddr);
    9450             : 
    9451           0 :     masm.tagValue(JSVAL_TYPE_STRING, temp, output);
    9452           0 :     masm.jump(ool->rejoin());
    9453             : 
    9454           0 :     masm.bind(&iterDone);
    9455           0 :     masm.moveValue(MagicValue(JS_NO_ITER_VALUE), output);
    9456             : 
    9457           0 :     masm.bind(ool->rejoin());
    9458           0 : }
    9459             : 
    9460             : void
    9461           0 : CodeGenerator::visitIsNoIterAndBranch(LIsNoIterAndBranch* lir)
    9462             : {
    9463           0 :     ValueOperand input = ToValue(lir, LIsNoIterAndBranch::Input);
    9464           0 :     Label* ifTrue = getJumpLabelForBranch(lir->ifTrue());
    9465           0 :     Label* ifFalse = getJumpLabelForBranch(lir->ifFalse());
    9466             : 
    9467           0 :     masm.branchTestMagic(Assembler::Equal, input, ifTrue);
    9468             : 
    9469           0 :     if (!isNextBlock(lir->ifFalse()->lir()))
    9470           0 :         masm.jump(ifFalse);
    9471           0 : }
    9472             : 
    9473             : typedef bool (*CloseIteratorFn)(JSContext*, HandleObject);
    9474           3 : static const VMFunction CloseIteratorInfo =
    9475           6 :     FunctionInfo<CloseIteratorFn>(CloseIterator, "CloseIterator");
    9476             : 
    9477             : void
    9478           0 : CodeGenerator::visitIteratorEnd(LIteratorEnd* lir)
    9479             : {
    9480           0 :     const Register obj = ToRegister(lir->object());
    9481           0 :     const Register temp1 = ToRegister(lir->temp1());
    9482           0 :     const Register temp2 = ToRegister(lir->temp2());
    9483           0 :     const Register temp3 = ToRegister(lir->temp3());
    9484             : 
    9485           0 :     OutOfLineCode* ool = oolCallVM(CloseIteratorInfo, lir, ArgList(obj), StoreNothing());
    9486             : 
    9487           0 :     LoadNativeIterator(masm, obj, temp1, ool->entry());
    9488             : 
    9489           0 :     masm.branchTest32(Assembler::Zero, Address(temp1, offsetof(NativeIterator, flags)),
    9490           0 :                       Imm32(JSITER_ENUMERATE), ool->entry());
    9491             : 
    9492             :     // Clear active bit.
    9493           0 :     masm.and32(Imm32(~JSITER_ACTIVE), Address(temp1, offsetof(NativeIterator, flags)));
    9494             : 
    9495             :     // Reset property cursor.
    9496           0 :     masm.loadPtr(Address(temp1, offsetof(NativeIterator, props_array)), temp2);
    9497           0 :     masm.storePtr(temp2, Address(temp1, offsetof(NativeIterator, props_cursor)));
    9498             : 
    9499             :     // Unlink from the iterator list.
    9500           0 :     const Register next = temp2;
    9501           0 :     const Register prev = temp3;
    9502           0 :     masm.loadPtr(Address(temp1, NativeIterator::offsetOfNext()), next);
    9503           0 :     masm.loadPtr(Address(temp1, NativeIterator::offsetOfPrev()), prev);
    9504           0 :     masm.storePtr(prev, Address(next, NativeIterator::offsetOfPrev()));
    9505           0 :     masm.storePtr(next, Address(prev, NativeIterator::offsetOfNext()));
    9506             : #ifdef DEBUG
    9507           0 :     masm.storePtr(ImmPtr(nullptr), Address(temp1, NativeIterator::offsetOfNext()));
    9508           0 :     masm.storePtr(ImmPtr(nullptr), Address(temp1, NativeIterator::offsetOfPrev()));
    9509             : #endif
    9510             : 
    9511           0 :     masm.bind(ool->rejoin());
    9512           0 : }
    9513             : 
    9514             : void
    9515           2 : CodeGenerator::visitArgumentsLength(LArgumentsLength* lir)
    9516             : {
    9517             :     // read number of actual arguments from the JS frame.
    9518           2 :     Register argc = ToRegister(lir->output());
    9519           2 :     Address ptr(masm.getStackPointer(), frameSize() + JitFrameLayout::offsetOfNumActualArgs());
    9520             : 
    9521           2 :     masm.loadPtr(ptr, argc);
    9522           2 : }
    9523             : 
    9524             : void
    9525           1 : CodeGenerator::visitGetFrameArgument(LGetFrameArgument* lir)
    9526             : {
    9527           1 :     ValueOperand result = GetValueOutput(lir);
    9528           1 :     const LAllocation* index = lir->index();
    9529           1 :     size_t argvOffset = frameSize() + JitFrameLayout::offsetOfActualArgs();
    9530             : 
    9531           1 :     if (index->isConstant()) {
    9532           1 :         int32_t i = index->toConstant()->toInt32();
    9533           1 :         Address argPtr(masm.getStackPointer(), sizeof(Value) * i + argvOffset);
    9534           1 :         masm.loadValue(argPtr, result);
    9535             :     } else {
    9536           0 :         Register i = ToRegister(index);
    9537           0 :         BaseValueIndex argPtr(masm.getStackPointer(), i, argvOffset);
    9538           0 :         masm.loadValue(argPtr, result);
    9539             :     }
    9540           1 : }
    9541             : 
    9542             : void
    9543           0 : CodeGenerator::visitSetFrameArgumentT(LSetFrameArgumentT* lir)
    9544             : {
    9545           0 :     size_t argOffset = frameSize() + JitFrameLayout::offsetOfActualArgs() +
    9546           0 :                        (sizeof(Value) * lir->mir()->argno());
    9547             : 
    9548           0 :     MIRType type = lir->mir()->value()->type();
    9549             : 
    9550           0 :     if (type == MIRType::Double) {
    9551             :         // Store doubles directly.
    9552           0 :         FloatRegister input = ToFloatRegister(lir->input());
    9553           0 :         masm.storeDouble(input, Address(masm.getStackPointer(), argOffset));
    9554             : 
    9555             :     } else {
    9556           0 :         Register input = ToRegister(lir->input());
    9557           0 :         masm.storeValue(ValueTypeFromMIRType(type), input, Address(masm.getStackPointer(), argOffset));
    9558             :     }
    9559           0 : }
    9560             : 
    9561             : void
    9562           0 : CodeGenerator:: visitSetFrameArgumentC(LSetFrameArgumentC* lir)
    9563             : {
    9564           0 :     size_t argOffset = frameSize() + JitFrameLayout::offsetOfActualArgs() +
    9565           0 :                        (sizeof(Value) * lir->mir()->argno());
    9566           0 :     masm.storeValue(lir->val(), Address(masm.getStackPointer(), argOffset));
    9567           0 : }
    9568             : 
    9569             : void
    9570           0 : CodeGenerator:: visitSetFrameArgumentV(LSetFrameArgumentV* lir)
    9571             : {
    9572           0 :     const ValueOperand val = ToValue(lir, LSetFrameArgumentV::Input);
    9573           0 :     size_t argOffset = frameSize() + JitFrameLayout::offsetOfActualArgs() +
    9574           0 :                        (sizeof(Value) * lir->mir()->argno());
    9575           0 :     masm.storeValue(val, Address(masm.getStackPointer(), argOffset));
    9576           0 : }
    9577             : 
    9578             : typedef bool (*RunOnceScriptPrologueFn)(JSContext*, HandleScript);
    9579           3 : static const VMFunction RunOnceScriptPrologueInfo =
    9580           6 :     FunctionInfo<RunOnceScriptPrologueFn>(js::RunOnceScriptPrologue, "RunOnceScriptPrologue");
    9581             : 
    9582             : void
    9583           0 : CodeGenerator::visitRunOncePrologue(LRunOncePrologue* lir)
    9584             : {
    9585           0 :     pushArg(ImmGCPtr(lir->mir()->block()->info().script()));
    9586           0 :     callVM(RunOnceScriptPrologueInfo, lir);
    9587           0 : }
    9588             : 
    9589             : typedef JSObject* (*InitRestParameterFn)(JSContext*, uint32_t, Value*, HandleObject,
    9590             :                                          HandleObject);
    9591           3 : static const VMFunction InitRestParameterInfo =
    9592           6 :     FunctionInfo<InitRestParameterFn>(InitRestParameter, "InitRestParameter");
    9593             : 
    9594             : void
    9595           1 : CodeGenerator::emitRest(LInstruction* lir, Register array, Register numActuals,
    9596             :                         Register temp0, Register temp1, unsigned numFormals,
    9597             :                         JSObject* templateObject, bool saveAndRestore, Register resultreg)
    9598             : {
    9599             :     // Compute actuals() + numFormals.
    9600           1 :     size_t actualsOffset = frameSize() + JitFrameLayout::offsetOfActualArgs();
    9601           1 :     masm.moveStackPtrTo(temp1);
    9602           1 :     masm.addPtr(Imm32(sizeof(Value) * numFormals + actualsOffset), temp1);
    9603             : 
    9604             :     // Compute numActuals - numFormals.
    9605           2 :     Label emptyLength, joinLength;
    9606           1 :     masm.movePtr(numActuals, temp0);
    9607           1 :     masm.branch32(Assembler::LessThanOrEqual, temp0, Imm32(numFormals), &emptyLength);
    9608           1 :     masm.sub32(Imm32(numFormals), temp0);
    9609           1 :     masm.jump(&joinLength);
    9610             :     {
    9611           1 :         masm.bind(&emptyLength);
    9612           1 :         masm.move32(Imm32(0), temp0);
    9613             :     }
    9614           1 :     masm.bind(&joinLength);
    9615             : 
    9616           1 :     if (saveAndRestore)
    9617           0 :         saveLive(lir);
    9618             : 
    9619           1 :     pushArg(array);
    9620           1 :     pushArg(ImmGCPtr(templateObject));
    9621           1 :     pushArg(temp1);
    9622           1 :     pushArg(temp0);
    9623             : 
    9624           1 :     callVM(InitRestParameterInfo, lir);
    9625             : 
    9626           1 :     if (saveAndRestore) {
    9627           0 :         storeResultTo(resultreg);
    9628           0 :         restoreLive(lir);
    9629             :     }
    9630           1 : }
    9631             : 
    9632             : void
    9633           1 : CodeGenerator::visitRest(LRest* lir)
    9634             : {
    9635           1 :     Register numActuals = ToRegister(lir->numActuals());
    9636           1 :     Register temp0 = ToRegister(lir->getTemp(0));
    9637           1 :     Register temp1 = ToRegister(lir->getTemp(1));
    9638           1 :     Register temp2 = ToRegister(lir->getTemp(2));
    9639           1 :     unsigned numFormals = lir->mir()->numFormals();
    9640           1 :     ArrayObject* templateObject = lir->mir()->templateObject();
    9641             : 
    9642           2 :     Label joinAlloc, failAlloc;
    9643           1 :     masm.createGCObject(temp2, temp0, templateObject, gc::DefaultHeap, &failAlloc);
    9644           1 :     masm.jump(&joinAlloc);
    9645             :     {
    9646           1 :         masm.bind(&failAlloc);
    9647           1 :         masm.movePtr(ImmPtr(nullptr), temp2);
    9648             :     }
    9649           1 :     masm.bind(&joinAlloc);
    9650             : 
    9651           1 :     emitRest(lir, temp2, numActuals, temp0, temp1, numFormals, templateObject, false, ToRegister(lir->output()));
    9652           1 : }
    9653             : 
    9654             : bool
    9655           0 : CodeGenerator::generateWasm(wasm::SigIdDesc sigId, wasm::BytecodeOffset trapOffset,
    9656             :                             wasm::FuncOffsets* offsets)
    9657             : {
    9658           0 :     JitSpew(JitSpew_Codegen, "# Emitting wasm code");
    9659             : 
    9660           0 :     wasm::GenerateFunctionPrologue(masm, frameSize(), sigId, offsets);
    9661             : 
    9662             :     // Overflow checks are omitted by CodeGenerator in some cases (leaf
    9663             :     // functions with small framePushed). Perform overflow-checking after
    9664             :     // pushing framePushed to catch cases with really large frames.
    9665           0 :     Label onOverflow;
    9666           0 :     if (!omitOverRecursedCheck())
    9667           0 :         masm.wasmEmitStackCheck(masm.getStackPointer(), ABINonArgReg0, &onOverflow);
    9668             : 
    9669           0 :     if (!generateBody())
    9670           0 :         return false;
    9671             : 
    9672           0 :     masm.bind(&returnLabel_);
    9673           0 :     wasm::GenerateFunctionEpilogue(masm, frameSize(), offsets);
    9674             : 
    9675           0 :     if (!omitOverRecursedCheck()) {
    9676             :         // Since we just overflowed the stack, to be on the safe side, pop the
    9677             :         // stack so that, when the trap exit stub executes, it is a safe
    9678             :         // distance away from the end of the native stack.
    9679           0 :         wasm::TrapDesc trap(trapOffset, wasm::Trap::StackOverflow, /* framePushed = */ 0);
    9680           0 :         if (frameSize() > 0) {
    9681           0 :             masm.bind(&onOverflow);
    9682           0 :             masm.addToStackPtr(Imm32(frameSize()));
    9683           0 :             masm.jump(trap);
    9684             :         } else {
    9685           0 :             masm.bindLater(&onOverflow, trap);
    9686             :         }
    9687             :     }
    9688             : 
    9689             : #if defined(JS_ION_PERF)
    9690             :     // Note the end of the inline code and start of the OOL code.
    9691             :     gen->perfSpewer().noteEndInlineCode(masm);
    9692             : #endif
    9693             : 
    9694           0 :     if (!generateOutOfLineCode())
    9695           0 :         return false;
    9696             : 
    9697           0 :     masm.wasmEmitTrapOutOfLineCode();
    9698             : 
    9699           0 :     masm.flush();
    9700           0 :     if (masm.oom())
    9701           0 :         return false;
    9702             : 
    9703           0 :     offsets->end = masm.currentOffset();
    9704             : 
    9705           0 :     MOZ_ASSERT(!masm.failureLabel()->used());
    9706           0 :     MOZ_ASSERT(snapshots_.listSize() == 0);
    9707           0 :     MOZ_ASSERT(snapshots_.RVATableSize() == 0);
    9708           0 :     MOZ_ASSERT(recovers_.size() == 0);
    9709           0 :     MOZ_ASSERT(bailouts_.empty());
    9710           0 :     MOZ_ASSERT(graph.numConstants() == 0);
    9711           0 :     MOZ_ASSERT(safepointIndices_.empty());
    9712           0 :     MOZ_ASSERT(osiIndices_.empty());
    9713           0 :     MOZ_ASSERT(icList_.empty());
    9714           0 :     MOZ_ASSERT(safepoints_.size() == 0);
    9715           0 :     MOZ_ASSERT(!scriptCounts_);
    9716           0 :     return true;
    9717             : }
    9718             : 
    9719             : bool
    9720           8 : CodeGenerator::generate()
    9721             : {
    9722          16 :     JitSpew(JitSpew_Codegen, "# Emitting code for script %s:%" PRIuSIZE,
    9723           8 :             gen->info().script()->filename(),
    9724          16 :             gen->info().script()->lineno());
    9725             : 
    9726             :     // Initialize native code table with an entry to the start of
    9727             :     // top-level script.
    9728           8 :     InlineScriptTree* tree = gen->info().inlineScriptTree();
    9729           8 :     jsbytecode* startPC = tree->script()->code();
    9730           8 :     BytecodeSite* startSite = new(gen->alloc()) BytecodeSite(tree, startPC);
    9731           8 :     if (!addNativeToBytecodeEntry(startSite))
    9732           0 :         return false;
    9733             : 
    9734           8 :     if (!snapshots_.init())
    9735           0 :         return false;
    9736             : 
    9737           8 :     if (!safepoints_.init(gen->alloc()))
    9738           0 :         return false;
    9739             : 
    9740           8 :     if (!generatePrologue())
    9741           0 :         return false;
    9742             : 
    9743             :     // Before generating any code, we generate type checks for all parameters.
    9744             :     // This comes before deoptTable_, because we can't use deopt tables without
    9745             :     // creating the actual frame.
    9746           8 :     generateArgumentsChecks();
    9747             : 
    9748           8 :     if (frameClass_ != FrameSizeClass::None()) {
    9749           0 :         deoptTable_ = gen->jitRuntime()->getBailoutTable(frameClass_);
    9750           0 :         if (!deoptTable_)
    9751           0 :             return false;
    9752             :     }
    9753             : 
    9754             :     // Skip over the alternative entry to IonScript code.
    9755          16 :     Label skipPrologue;
    9756           8 :     masm.jump(&skipPrologue);
    9757             : 
    9758             :     // An alternative entry to the IonScript code, which doesn't test the
    9759             :     // arguments.
    9760           8 :     masm.flushBuffer();
    9761           8 :     setSkipArgCheckEntryOffset(masm.size());
    9762           8 :     masm.setFramePushed(0);
    9763           8 :     if (!generatePrologue())
    9764           0 :         return false;
    9765             : 
    9766           8 :     masm.bind(&skipPrologue);
    9767             : 
    9768             : #ifdef DEBUG
    9769             :     // Assert that the argument types are correct.
    9770           8 :     generateArgumentsChecks(/* bailout = */ false);
    9771             : #endif
    9772             : 
    9773             :     // Reset native => bytecode map table with top-level script and startPc.
    9774           8 :     if (!addNativeToBytecodeEntry(startSite))
    9775           0 :         return false;
    9776             : 
    9777           8 :     if (!generateBody())
    9778           0 :         return false;
    9779             : 
    9780             :     // Reset native => bytecode map table with top-level script and startPc.
    9781           8 :     if (!addNativeToBytecodeEntry(startSite))
    9782           0 :         return false;
    9783             : 
    9784           8 :     if (!generateEpilogue())
    9785           0 :         return false;
    9786             : 
    9787             :     // Reset native => bytecode map table with top-level script and startPc.
    9788           8 :     if (!addNativeToBytecodeEntry(startSite))
    9789           0 :         return false;
    9790             : 
    9791           8 :     generateInvalidateEpilogue();
    9792             : #if defined(JS_ION_PERF)
    9793             :     // Note the end of the inline code and start of the OOL code.
    9794             :     perfSpewer_.noteEndInlineCode(masm);
    9795             : #endif
    9796             : 
    9797             :     // native => bytecode entries for OOL code will be added
    9798             :     // by CodeGeneratorShared::generateOutOfLineCode
    9799           8 :     if (!generateOutOfLineCode())
    9800           0 :         return false;
    9801             : 
    9802             :     // Add terminal entry.
    9803           8 :     if (!addNativeToBytecodeEntry(startSite))
    9804           0 :         return false;
    9805             : 
    9806             :     // Dump Native to bytecode entries to spew.
    9807           8 :     dumpNativeToBytecodeEntries();
    9808             : 
    9809           8 :     return !masm.oom();
    9810             : }
    9811             : 
    9812             : bool
    9813           7 : CodeGenerator::linkSharedStubs(JSContext* cx)
    9814             : {
    9815           7 :     for (uint32_t i = 0; i < sharedStubs_.length(); i++) {
    9816           0 :         ICStub *stub = nullptr;
    9817             : 
    9818           0 :         switch (sharedStubs_[i].kind) {
    9819             :           case ICStub::Kind::BinaryArith_Fallback: {
    9820           0 :             ICBinaryArith_Fallback::Compiler stubCompiler(cx, ICStubCompiler::Engine::IonSharedIC);
    9821           0 :             stub = stubCompiler.getStub(&stubSpace_);
    9822           0 :             break;
    9823             :           }
    9824             :           case ICStub::Kind::UnaryArith_Fallback: {
    9825           0 :             ICUnaryArith_Fallback::Compiler stubCompiler(cx, ICStubCompiler::Engine::IonSharedIC);
    9826           0 :             stub = stubCompiler.getStub(&stubSpace_);
    9827           0 :             break;
    9828             :           }
    9829             :           case ICStub::Kind::Compare_Fallback: {
    9830           0 :             ICCompare_Fallback::Compiler stubCompiler(cx, ICStubCompiler::Engine::IonSharedIC);
    9831           0 :             stub = stubCompiler.getStub(&stubSpace_);
    9832           0 :             break;
    9833             :           }
    9834             :           case ICStub::Kind::GetProp_Fallback: {
    9835           0 :             ICGetProp_Fallback::Compiler stubCompiler(cx, ICStubCompiler::Engine::IonSharedIC);
    9836           0 :             stub = stubCompiler.getStub(&stubSpace_);
    9837           0 :             break;
    9838             :           }
    9839             :           case ICStub::Kind::NewArray_Fallback: {
    9840           0 :             JSScript* script = sharedStubs_[i].entry.script();
    9841           0 :             jsbytecode* pc = sharedStubs_[i].entry.pc(script);
    9842           0 :             ObjectGroup* group = ObjectGroup::allocationSiteGroup(cx, script, pc, JSProto_Array);
    9843           0 :             if (!group)
    9844           0 :                 return false;
    9845             : 
    9846           0 :             ICNewArray_Fallback::Compiler stubCompiler(cx, group, ICStubCompiler::Engine::IonSharedIC);
    9847           0 :             stub = stubCompiler.getStub(&stubSpace_);
    9848           0 :             break;
    9849             :           }
    9850             :           case ICStub::Kind::NewObject_Fallback: {
    9851           0 :             ICNewObject_Fallback::Compiler stubCompiler(cx, ICStubCompiler::Engine::IonSharedIC);
    9852           0 :             stub = stubCompiler.getStub(&stubSpace_);
    9853           0 :             break;
    9854             :           }
    9855             :           default:
    9856           0 :             MOZ_CRASH("Unsupported shared stub.");
    9857             :         }
    9858             : 
    9859           0 :         if (!stub)
    9860           0 :             return false;
    9861             : 
    9862           0 :         sharedStubs_[i].entry.setFirstStub(stub);
    9863             :     }
    9864           7 :     return true;
    9865             : }
    9866             : 
    9867             : bool
    9868           7 : CodeGenerator::link(JSContext* cx, CompilerConstraintList* constraints)
    9869             : {
    9870          14 :     RootedScript script(cx, gen->info().script());
    9871           7 :     OptimizationLevel optimizationLevel = gen->optimizationInfo().level();
    9872             : 
    9873             :     // Capture the SIMD template objects which are used during the
    9874             :     // compilation. This iterates over the template objects, using read-barriers
    9875             :     // to let the GC know that the generated code relies on these template
    9876             :     // objects.
    9877           7 :     captureSimdTemplate(cx);
    9878             : 
    9879             :     // We finished the new IonScript. Invalidate the current active IonScript,
    9880             :     // so we can replace it with this new (probably higher optimized) version.
    9881           7 :     if (script->hasIonScript()) {
    9882           0 :         MOZ_ASSERT(script->ionScript()->isRecompiling());
    9883             :         // Do a normal invalidate, except don't cancel offThread compilations,
    9884             :         // since that will cancel this compilation too.
    9885           0 :         Invalidate(cx, script, /* resetUses */ false, /* cancelOffThread*/ false);
    9886             :     }
    9887             : 
    9888           7 :     if (scriptCounts_ && !script->hasScriptCounts() && !script->initScriptCounts(cx))
    9889           0 :         return false;
    9890             : 
    9891           7 :     if (!linkSharedStubs(cx))
    9892           0 :         return false;
    9893             : 
    9894             :     // Check to make sure we didn't have a mid-build invalidation. If so, we
    9895             :     // will trickle to jit::Compile() and return Method_Skipped.
    9896           7 :     uint32_t warmUpCount = script->getWarmUpCount();
    9897             : 
    9898             :     // Record constraints. If an error occured, returns false and potentially
    9899             :     // prevent future compilations. Otherwise, if an invalidation occured, then
    9900             :     // skip the current compilation.
    9901           7 :     RecompileInfo recompileInfo;
    9902           7 :     bool validRecompiledInfo = false;
    9903           7 :     if (!FinishCompilation(cx, script, constraints, &recompileInfo, &validRecompiledInfo))
    9904           0 :         return false;
    9905           7 :     if (!validRecompiledInfo)
    9906           2 :         return true;
    9907           0 :     auto guardRecordedConstraints = mozilla::MakeScopeExit([&] {
    9908             :         // In case of error, invalidate the current recompileInfo.
    9909           0 :         recompileInfo.compilerOutput(cx->zone()->types)->invalidate();
    9910          10 :     });
    9911             : 
    9912             :     // IonMonkey could have inferred better type information during
    9913             :     // compilation. Since adding the new information to the actual type
    9914             :     // information can reset the usecount, increase it back to what it was
    9915             :     // before.
    9916           5 :     if (warmUpCount > script->getWarmUpCount())
    9917           0 :         script->incWarmUpCounter(warmUpCount - script->getWarmUpCount());
    9918             : 
    9919           5 :     uint32_t argumentSlots = (gen->info().nargs() + 1) * sizeof(Value);
    9920          10 :     uint32_t scriptFrameSize = frameClass_ == FrameSizeClass::None()
    9921           5 :                            ? frameDepth_
    9922           5 :                            : FrameSizeClass::FromDepth(frameDepth_).frameSize();
    9923             : 
    9924             :     // We encode safepoints after the OSI-point offsets have been determined.
    9925           5 :     if (!encodeSafepoints())
    9926           0 :         return false;
    9927             : 
    9928             :     IonScript* ionScript =
    9929          15 :         IonScript::New(cx, recompileInfo,
    9930           5 :                        graph.totalSlotCount(), argumentSlots, scriptFrameSize,
    9931             :                        snapshots_.listSize(), snapshots_.RVATableSize(),
    9932           5 :                        recovers_.size(), bailouts_.length(), graph.numConstants(),
    9933             :                        safepointIndices_.length(), osiIndices_.length(),
    9934             :                        icList_.length(), runtimeData_.length(),
    9935             :                        safepoints_.size(), patchableBackedges_.length(),
    9936           5 :                        sharedStubs_.length(), optimizationLevel);
    9937           5 :     if (!ionScript)
    9938           0 :         return false;
    9939           0 :     auto guardIonScript = mozilla::MakeScopeExit([&ionScript] {
    9940             :         // Use js_free instead of IonScript::Destroy: the cache list and
    9941             :         // backedge list are still uninitialized.
    9942           0 :         js_free(ionScript);
    9943          10 :     });
    9944             : 
    9945             :     // Also, note that creating the code here during an incremental GC will
    9946             :     // trace the code and mark all GC things it refers to. This captures any
    9947             :     // read barriers which were skipped while compiling the script off thread.
    9948          10 :     Linker linker(masm);
    9949          10 :     AutoFlushICache afc("IonLink");
    9950           5 :     JitCode* code = linker.newCode<CanGC>(cx, ION_CODE, !patchableBackedges_.empty());
    9951           5 :     if (!code)
    9952           0 :         return false;
    9953             : 
    9954             :     // Encode native to bytecode map if profiling is enabled.
    9955           5 :     if (isProfilerInstrumentationEnabled()) {
    9956             :         // Generate native-to-bytecode main table.
    9957           0 :         if (!generateCompactNativeToBytecodeMap(cx, code))
    9958           0 :             return false;
    9959             : 
    9960           0 :         uint8_t* ionTableAddr = ((uint8_t*) nativeToBytecodeMap_) + nativeToBytecodeTableOffset_;
    9961           0 :         JitcodeIonTable* ionTable = (JitcodeIonTable*) ionTableAddr;
    9962             : 
    9963             :         // Construct the IonEntry that will go into the global table.
    9964             :         JitcodeGlobalEntry::IonEntry entry;
    9965           0 :         if (!ionTable->makeIonEntry(cx, code, nativeToBytecodeScriptListLength_,
    9966             :                                     nativeToBytecodeScriptList_, entry))
    9967             :         {
    9968           0 :             js_free(nativeToBytecodeScriptList_);
    9969           0 :             js_free(nativeToBytecodeMap_);
    9970           0 :             return false;
    9971             :         }
    9972             : 
    9973             :         // nativeToBytecodeScriptList_ is no longer needed.
    9974           0 :         js_free(nativeToBytecodeScriptList_);
    9975             : 
    9976             :         // Generate the tracked optimizations map.
    9977           0 :         if (isOptimizationTrackingEnabled()) {
    9978             :             // Treat OOMs and failures as if optimization tracking were turned off.
    9979           0 :             IonTrackedTypeVector* allTypes = cx->new_<IonTrackedTypeVector>();
    9980           0 :             if (allTypes && generateCompactTrackedOptimizationsMap(cx, code, allTypes)) {
    9981           0 :                 const uint8_t* optsRegionTableAddr = trackedOptimizationsMap_ +
    9982           0 :                                                      trackedOptimizationsRegionTableOffset_;
    9983             :                 const IonTrackedOptimizationsRegionTable* optsRegionTable =
    9984           0 :                     (const IonTrackedOptimizationsRegionTable*) optsRegionTableAddr;
    9985           0 :                 const uint8_t* optsTypesTableAddr = trackedOptimizationsMap_ +
    9986           0 :                                                     trackedOptimizationsTypesTableOffset_;
    9987             :                 const IonTrackedOptimizationsTypesTable* optsTypesTable =
    9988           0 :                     (const IonTrackedOptimizationsTypesTable*) optsTypesTableAddr;
    9989           0 :                 const uint8_t* optsAttemptsTableAddr = trackedOptimizationsMap_ +
    9990           0 :                                                        trackedOptimizationsAttemptsTableOffset_;
    9991             :                 const IonTrackedOptimizationsAttemptsTable* optsAttemptsTable =
    9992           0 :                     (const IonTrackedOptimizationsAttemptsTable*) optsAttemptsTableAddr;
    9993             :                 entry.initTrackedOptimizations(optsRegionTable, optsTypesTable, optsAttemptsTable,
    9994           0 :                                                allTypes);
    9995             :             } else {
    9996           0 :                 cx->recoverFromOutOfMemory();
    9997             :             }
    9998             :         }
    9999             : 
   10000             :         // Add entry to the global table.
   10001           0 :         JitcodeGlobalTable* globalTable = cx->runtime()->jitRuntime()->getJitcodeGlobalTable();
   10002           0 :         if (!globalTable->addEntry(entry, cx->runtime())) {
   10003             :             // Memory may have been allocated for the entry.
   10004           0 :             entry.destroy();
   10005           0 :             return false;
   10006             :         }
   10007             : 
   10008             :         // Mark the jitcode as having a bytecode map.
   10009           0 :         code->setHasBytecodeMap();
   10010             :     } else {
   10011             :         // Add a dumy jitcodeGlobalTable entry.
   10012             :         JitcodeGlobalEntry::DummyEntry entry;
   10013           5 :         entry.init(code, code->raw(), code->rawEnd());
   10014             : 
   10015             :         // Add entry to the global table.
   10016           5 :         JitcodeGlobalTable* globalTable = cx->runtime()->jitRuntime()->getJitcodeGlobalTable();
   10017           5 :         if (!globalTable->addEntry(entry, cx->runtime())) {
   10018             :             // Memory may have been allocated for the entry.
   10019           0 :             entry.destroy();
   10020           0 :             return false;
   10021             :         }
   10022             : 
   10023             :         // Mark the jitcode as having a bytecode map.
   10024           5 :         code->setHasBytecodeMap();
   10025             :     }
   10026             : 
   10027           5 :     ionScript->setMethod(code);
   10028           5 :     ionScript->setSkipArgCheckEntryOffset(getSkipArgCheckEntryOffset());
   10029             : 
   10030             :     // If the Gecko Profiler is enabled, mark IonScript as having been
   10031             :     // instrumented accordingly.
   10032           5 :     if (isProfilerInstrumentationEnabled())
   10033           0 :         ionScript->setHasProfilingInstrumentation();
   10034             : 
   10035           5 :     script->setIonScript(cx->runtime(), ionScript);
   10036             : 
   10037             :     // Adopt fallback shared stubs from the compiler into the ion script.
   10038           5 :     ionScript->adoptFallbackStubs(&stubSpace_);
   10039             : 
   10040          10 :     Assembler::PatchDataWithValueCheck(CodeLocationLabel(code, invalidateEpilogueData_),
   10041             :                                        ImmPtr(ionScript),
   10042           5 :                                        ImmPtr((void*)-1));
   10043             : 
   10044         105 :     for (size_t i = 0; i < ionScriptLabels_.length(); i++) {
   10045         200 :         Assembler::PatchDataWithValueCheck(CodeLocationLabel(code, ionScriptLabels_[i]),
   10046             :                                            ImmPtr(ionScript),
   10047         100 :                                            ImmPtr((void*)-1));
   10048             :     }
   10049             : 
   10050             : #ifdef JS_TRACE_LOGGING
   10051           5 :     bool TLFailed = false;
   10052             : 
   10053           5 :     for (uint32_t i = 0; i < patchableTLEvents_.length(); i++) {
   10054           0 :         TraceLoggerEvent event(patchableTLEvents_[i].event);
   10055           0 :         if (!event.hasTextId() || !ionScript->addTraceLoggerEvent(event)) {
   10056           0 :             TLFailed = true;
   10057           0 :             break;
   10058             :         }
   10059           0 :         Assembler::PatchDataWithValueCheck(CodeLocationLabel(code, patchableTLEvents_[i].offset),
   10060           0 :                 ImmPtr((void*) uintptr_t(event.textId())),
   10061           0 :                 ImmPtr((void*)0));
   10062             :     }
   10063             : 
   10064           5 :     if (!TLFailed && patchableTLScripts_.length() > 0) {
   10065           0 :         MOZ_ASSERT(TraceLogTextIdEnabled(TraceLogger_Scripts));
   10066           0 :         TraceLoggerEvent event(TraceLogger_Scripts, script);
   10067           0 :         if (!event.hasTextId() || !ionScript->addTraceLoggerEvent(event))
   10068           0 :             TLFailed = true;
   10069           0 :         if (!TLFailed) {
   10070           0 :             uint32_t textId = event.textId();
   10071           0 :             for (uint32_t i = 0; i < patchableTLScripts_.length(); i++) {
   10072           0 :                 Assembler::PatchDataWithValueCheck(CodeLocationLabel(code, patchableTLScripts_[i]),
   10073           0 :                                                    ImmPtr((void*) uintptr_t(textId)),
   10074           0 :                                                    ImmPtr((void*)0));
   10075             :             }
   10076             :         }
   10077             :     }
   10078             : #endif
   10079             : 
   10080             :     // Patch shared stub IC loads using IC entries
   10081           5 :     for (size_t i = 0; i < sharedStubs_.length(); i++) {
   10082           0 :         CodeOffset label = sharedStubs_[i].label;
   10083             : 
   10084           0 :         IonICEntry& entry = ionScript->sharedStubList()[i];
   10085           0 :         entry = sharedStubs_[i].entry;
   10086           0 :         Assembler::PatchDataWithValueCheck(CodeLocationLabel(code, label),
   10087             :                                            ImmPtr(&entry),
   10088           0 :                                            ImmPtr((void*)-1));
   10089             : 
   10090           0 :         MOZ_ASSERT(entry.hasStub());
   10091           0 :         MOZ_ASSERT(entry.firstStub()->isFallback());
   10092             : 
   10093           0 :         entry.firstStub()->toFallbackStub()->fixupICEntry(&entry);
   10094             :     }
   10095             : 
   10096             :     // for generating inline caches during the execution.
   10097           5 :     if (runtimeData_.length())
   10098           4 :         ionScript->copyRuntimeData(&runtimeData_[0]);
   10099           5 :     if (icList_.length())
   10100           4 :         ionScript->copyICEntries(&icList_[0], masm);
   10101             : 
   10102          19 :     for (size_t i = 0; i < icInfo_.length(); i++) {
   10103          14 :         IonIC& ic = ionScript->getICFromIndex(i);
   10104          42 :         Assembler::PatchDataWithValueCheck(CodeLocationLabel(code, icInfo_[i].icOffsetForJump),
   10105          14 :                                            ImmPtr(ic.codeRawPtr()),
   10106          14 :                                            ImmPtr((void*)-1));
   10107          28 :         Assembler::PatchDataWithValueCheck(CodeLocationLabel(code, icInfo_[i].icOffsetForPush),
   10108             :                                            ImmPtr(&ic),
   10109          14 :                                            ImmPtr((void*)-1));
   10110             :     }
   10111             : 
   10112           5 :     JitSpew(JitSpew_Codegen, "Created IonScript %p (raw %p)",
   10113          10 :             (void*) ionScript, (void*) code->raw());
   10114             : 
   10115           5 :     ionScript->setInvalidationEpilogueDataOffset(invalidateEpilogueData_.offset());
   10116           5 :     ionScript->setOsrPc(gen->info().osrPc());
   10117           5 :     ionScript->setOsrEntryOffset(getOsrEntryOffset());
   10118           5 :     ionScript->setInvalidationEpilogueOffset(invalidate_.offset());
   10119             : 
   10120           5 :     ionScript->setDeoptTable(deoptTable_);
   10121             : 
   10122             : #if defined(JS_ION_PERF)
   10123             :     if (PerfEnabled())
   10124             :         perfSpewer_.writeProfile(script, code, masm);
   10125             : #endif
   10126             : 
   10127             : #ifdef MOZ_VTUNE
   10128           5 :     vtune::MarkScript(code, script, "ion");
   10129             : #endif
   10130             : 
   10131             :     // for marking during GC.
   10132           5 :     if (safepointIndices_.length())
   10133           4 :         ionScript->copySafepointIndices(&safepointIndices_[0], masm);
   10134           5 :     if (safepoints_.size())
   10135           4 :         ionScript->copySafepoints(&safepoints_);
   10136             : 
   10137             :     // for reconvering from an Ion Frame.
   10138           5 :     if (bailouts_.length())
   10139           0 :         ionScript->copyBailoutTable(&bailouts_[0]);
   10140           5 :     if (osiIndices_.length())
   10141           5 :         ionScript->copyOsiIndices(&osiIndices_[0], masm);
   10142           5 :     if (snapshots_.listSize())
   10143           5 :         ionScript->copySnapshots(&snapshots_);
   10144           5 :     MOZ_ASSERT_IF(snapshots_.listSize(), recovers_.size());
   10145           5 :     if (recovers_.size())
   10146           5 :         ionScript->copyRecovers(&recovers_);
   10147           5 :     if (graph.numConstants()) {
   10148           3 :         const Value* vp = graph.constantPool();
   10149           3 :         ionScript->copyConstants(vp);
   10150          18 :         for (size_t i = 0; i < graph.numConstants(); i++) {
   10151          15 :             const Value& v = vp[i];
   10152          15 :             if (v.isObject() && IsInsideNursery(&v.toObject())) {
   10153           0 :                 cx->zone()->group()->storeBuffer().putWholeCell(script);
   10154           0 :                 break;
   10155             :             }
   10156             :         }
   10157             :     }
   10158           5 :     if (patchableBackedges_.length() > 0)
   10159           0 :         ionScript->copyPatchableBackedges(cx, code, patchableBackedges_.begin(), masm);
   10160             : 
   10161             :     // Attach any generated script counts to the script.
   10162           5 :     if (IonScriptCounts* counts = extractScriptCounts())
   10163           0 :         script->addIonCounts(counts);
   10164             : 
   10165           5 :     guardIonScript.release();
   10166           5 :     guardRecordedConstraints.release();
   10167           5 :     return true;
   10168             : }
   10169             : 
   10170             : // An out-of-line path to convert a boxed int32 to either a float or double.
   10171             : class OutOfLineUnboxFloatingPoint : public OutOfLineCodeBase<CodeGenerator>
   10172             : {
   10173             :     LUnboxFloatingPoint* unboxFloatingPoint_;
   10174             : 
   10175             :   public:
   10176           0 :     explicit OutOfLineUnboxFloatingPoint(LUnboxFloatingPoint* unboxFloatingPoint)
   10177           0 :       : unboxFloatingPoint_(unboxFloatingPoint)
   10178           0 :     { }
   10179             : 
   10180           0 :     void accept(CodeGenerator* codegen) {
   10181           0 :         codegen->visitOutOfLineUnboxFloatingPoint(this);
   10182           0 :     }
   10183             : 
   10184           0 :     LUnboxFloatingPoint* unboxFloatingPoint() const {
   10185           0 :         return unboxFloatingPoint_;
   10186             :     }
   10187             : };
   10188             : 
   10189             : void
   10190           0 : CodeGenerator::visitUnboxFloatingPoint(LUnboxFloatingPoint* lir)
   10191             : {
   10192           0 :     const ValueOperand box = ToValue(lir, LUnboxFloatingPoint::Input);
   10193           0 :     const LDefinition* result = lir->output();
   10194             : 
   10195             :     // Out-of-line path to convert int32 to double or bailout
   10196             :     // if this instruction is fallible.
   10197           0 :     OutOfLineUnboxFloatingPoint* ool = new(alloc()) OutOfLineUnboxFloatingPoint(lir);
   10198           0 :     addOutOfLineCode(ool, lir->mir());
   10199             : 
   10200           0 :     FloatRegister resultReg = ToFloatRegister(result);
   10201           0 :     masm.branchTestDouble(Assembler::NotEqual, box, ool->entry());
   10202           0 :     masm.unboxDouble(box, resultReg);
   10203           0 :     if (lir->type() == MIRType::Float32)
   10204           0 :         masm.convertDoubleToFloat32(resultReg, resultReg);
   10205           0 :     masm.bind(ool->rejoin());
   10206           0 : }
   10207             : 
   10208             : void
   10209           0 : CodeGenerator::visitOutOfLineUnboxFloatingPoint(OutOfLineUnboxFloatingPoint* ool)
   10210             : {
   10211           0 :     LUnboxFloatingPoint* ins = ool->unboxFloatingPoint();
   10212           0 :     const ValueOperand value = ToValue(ins, LUnboxFloatingPoint::Input);
   10213             : 
   10214           0 :     if (ins->mir()->fallible()) {
   10215           0 :         Label bail;
   10216           0 :         masm.branchTestInt32(Assembler::NotEqual, value, &bail);
   10217           0 :         bailoutFrom(&bail, ins->snapshot());
   10218             :     }
   10219           0 :     masm.int32ValueToFloatingPoint(value, ToFloatRegister(ins->output()), ins->type());
   10220           0 :     masm.jump(ool->rejoin());
   10221           0 : }
   10222             : 
   10223             : typedef JSObject* (*BindVarFn)(JSContext*, HandleObject);
   10224           3 : static const VMFunction BindVarInfo = FunctionInfo<BindVarFn>(jit::BindVar, "BindVar");
   10225             : 
   10226             : void
   10227           0 : CodeGenerator::visitCallBindVar(LCallBindVar* lir)
   10228             : {
   10229           0 :     pushArg(ToRegister(lir->environmentChain()));
   10230           0 :     callVM(BindVarInfo, lir);
   10231           0 : }
   10232             : 
   10233             : typedef bool (*GetPropertyFn)(JSContext*, HandleValue, HandlePropertyName, MutableHandleValue);
   10234           3 : static const VMFunction GetPropertyInfo = FunctionInfo<GetPropertyFn>(GetProperty, "GetProperty");
   10235             : 
   10236             : void
   10237           3 : CodeGenerator::visitCallGetProperty(LCallGetProperty* lir)
   10238             : {
   10239           3 :     pushArg(ImmGCPtr(lir->mir()->name()));
   10240           3 :     pushArg(ToValue(lir, LCallGetProperty::Value));
   10241             : 
   10242           3 :     callVM(GetPropertyInfo, lir);
   10243           3 : }
   10244             : 
   10245             : typedef bool (*GetOrCallElementFn)(JSContext*, MutableHandleValue, HandleValue, MutableHandleValue);
   10246           3 : static const VMFunction GetElementInfo =
   10247           6 :     FunctionInfo<GetOrCallElementFn>(js::GetElement, "GetElement");
   10248           3 : static const VMFunction CallElementInfo =
   10249           6 :     FunctionInfo<GetOrCallElementFn>(js::CallElement, "CallElement");
   10250             : 
   10251             : void
   10252           0 : CodeGenerator::visitCallGetElement(LCallGetElement* lir)
   10253             : {
   10254           0 :     pushArg(ToValue(lir, LCallGetElement::RhsInput));
   10255           0 :     pushArg(ToValue(lir, LCallGetElement::LhsInput));
   10256             : 
   10257           0 :     JSOp op = JSOp(*lir->mir()->resumePoint()->pc());
   10258             : 
   10259           0 :     if (op == JSOP_GETELEM) {
   10260           0 :         callVM(GetElementInfo, lir);
   10261             :     } else {
   10262           0 :         MOZ_ASSERT(op == JSOP_CALLELEM);
   10263           0 :         callVM(CallElementInfo, lir);
   10264             :     }
   10265           0 : }
   10266             : 
   10267             : typedef bool (*SetObjectElementFn)(JSContext*, HandleObject, HandleValue, HandleValue,
   10268             :                                    bool strict);
   10269           3 : static const VMFunction SetObjectElementInfo =
   10270           6 :     FunctionInfo<SetObjectElementFn>(SetObjectElement, "SetObjectElement");
   10271             : 
   10272             : void
   10273           0 : CodeGenerator::visitCallSetElement(LCallSetElement* lir)
   10274             : {
   10275           0 :     pushArg(Imm32(lir->mir()->strict()));
   10276           0 :     pushArg(ToValue(lir, LCallSetElement::Value));
   10277           0 :     pushArg(ToValue(lir, LCallSetElement::Index));
   10278           0 :     pushArg(ToRegister(lir->getOperand(0)));
   10279           0 :     callVM(SetObjectElementInfo, lir);
   10280           0 : }
   10281             : 
   10282             : typedef bool (*InitElementArrayFn)(JSContext*, jsbytecode*, HandleObject, uint32_t, HandleValue);
   10283           3 : static const VMFunction InitElementArrayInfo =
   10284           6 :     FunctionInfo<InitElementArrayFn>(js::InitElementArray, "InitElementArray");
   10285             : 
   10286             : void
   10287           0 : CodeGenerator::visitCallInitElementArray(LCallInitElementArray* lir)
   10288             : {
   10289           0 :     pushArg(ToValue(lir, LCallInitElementArray::Value));
   10290           0 :     if (lir->index()->isConstant())
   10291           0 :         pushArg(Imm32(ToInt32(lir->index())));
   10292             :     else
   10293           0 :         pushArg(ToRegister(lir->index()));
   10294           0 :     pushArg(ToRegister(lir->object()));
   10295           0 :     pushArg(ImmPtr(lir->mir()->resumePoint()->pc()));
   10296           0 :     callVM(InitElementArrayInfo, lir);
   10297           0 : }
   10298             : 
   10299             : void
   10300          29 : CodeGenerator::visitLoadFixedSlotV(LLoadFixedSlotV* ins)
   10301             : {
   10302          29 :     const Register obj = ToRegister(ins->getOperand(0));
   10303          29 :     size_t slot = ins->mir()->slot();
   10304          29 :     ValueOperand result = GetValueOutput(ins);
   10305             : 
   10306          29 :     masm.loadValue(Address(obj, NativeObject::getFixedSlotOffset(slot)), result);
   10307          29 : }
   10308             : 
   10309             : void
   10310           5 : CodeGenerator::visitLoadFixedSlotT(LLoadFixedSlotT* ins)
   10311             : {
   10312           5 :     const Register obj = ToRegister(ins->getOperand(0));
   10313           5 :     size_t slot = ins->mir()->slot();
   10314           5 :     AnyRegister result = ToAnyRegister(ins->getDef(0));
   10315           5 :     MIRType type = ins->mir()->type();
   10316             : 
   10317           5 :     masm.loadUnboxedValue(Address(obj, NativeObject::getFixedSlotOffset(slot)), type, result);
   10318           5 : }
   10319             : 
   10320             : void
   10321           1 : CodeGenerator::visitLoadFixedSlotAndUnbox(LLoadFixedSlotAndUnbox* ins)
   10322             : {
   10323           1 :     const MLoadFixedSlotAndUnbox* mir = ins->mir();
   10324           1 :     MIRType type = mir->type();
   10325           1 :     const Register input = ToRegister(ins->getOperand(0));
   10326           1 :     AnyRegister result = ToAnyRegister(ins->output());
   10327           1 :     size_t slot = mir->slot();
   10328             : 
   10329           1 :     Address address(input, NativeObject::getFixedSlotOffset(slot));
   10330           2 :     Label bail;
   10331           1 :     if (type == MIRType::Double) {
   10332           0 :         MOZ_ASSERT(result.isFloat());
   10333           0 :         masm.ensureDouble(address, result.fpu(), &bail);
   10334           0 :         if (mir->fallible())
   10335           0 :             bailoutFrom(&bail, ins->snapshot());
   10336           0 :         return;
   10337             :     }
   10338           1 :     if (mir->fallible()) {
   10339           1 :         switch (type) {
   10340             :           case MIRType::Int32:
   10341           1 :             masm.branchTestInt32(Assembler::NotEqual, address, &bail);
   10342           1 :             break;
   10343             :           case MIRType::Boolean:
   10344           0 :             masm.branchTestBoolean(Assembler::NotEqual, address, &bail);
   10345           0 :             break;
   10346             :           default:
   10347           0 :             MOZ_CRASH("Given MIRType cannot be unboxed.");
   10348             :         }
   10349           1 :         bailoutFrom(&bail, ins->snapshot());
   10350             :     }
   10351           1 :     masm.loadUnboxedValue(address, type, result);
   10352             : }
   10353             : 
   10354             : void
   10355           1 : CodeGenerator::visitStoreFixedSlotV(LStoreFixedSlotV* ins)
   10356             : {
   10357           1 :     const Register obj = ToRegister(ins->getOperand(0));
   10358           1 :     size_t slot = ins->mir()->slot();
   10359             : 
   10360           1 :     const ValueOperand value = ToValue(ins, LStoreFixedSlotV::Value);
   10361             : 
   10362           1 :     Address address(obj, NativeObject::getFixedSlotOffset(slot));
   10363           1 :     if (ins->mir()->needsBarrier())
   10364           1 :         emitPreBarrier(address);
   10365             : 
   10366           1 :     masm.storeValue(value, address);
   10367           1 : }
   10368             : 
   10369             : void
   10370          31 : CodeGenerator::visitStoreFixedSlotT(LStoreFixedSlotT* ins)
   10371             : {
   10372          31 :     const Register obj = ToRegister(ins->getOperand(0));
   10373          31 :     size_t slot = ins->mir()->slot();
   10374             : 
   10375          31 :     const LAllocation* value = ins->value();
   10376          31 :     MIRType valueType = ins->mir()->value()->type();
   10377             : 
   10378          31 :     Address address(obj, NativeObject::getFixedSlotOffset(slot));
   10379          31 :     if (ins->mir()->needsBarrier())
   10380          22 :         emitPreBarrier(address);
   10381             : 
   10382          31 :     if (valueType == MIRType::ObjectOrNull) {
   10383           0 :         Register nvalue = ToRegister(value);
   10384           0 :         masm.storeObjectOrNull(nvalue, address);
   10385             :     } else {
   10386          31 :         ConstantOrRegister nvalue = value->isConstant()
   10387          71 :                                     ? ConstantOrRegister(value->toConstant()->toJSValue())
   10388          62 :                                     : TypedOrValueRegister(valueType, ToAnyRegister(value));
   10389          31 :         masm.storeConstantOrRegister(nvalue, address);
   10390             :     }
   10391          31 : }
   10392             : 
   10393             : void
   10394           4 : CodeGenerator::visitGetNameCache(LGetNameCache* ins)
   10395             : {
   10396           4 :     LiveRegisterSet liveRegs = ins->safepoint()->liveRegs();
   10397           4 :     Register envChain = ToRegister(ins->envObj());
   10398           4 :     ValueOperand output(GetValueOutput(ins));
   10399           4 :     Register temp = ToRegister(ins->temp());
   10400             : 
   10401           4 :     IonGetNameIC ic(liveRegs, envChain, output, temp);
   10402           4 :     addIC(ins, allocateIC(ic));
   10403           4 : }
   10404             : 
   10405             : void
   10406          23 : CodeGenerator::addGetPropertyCache(LInstruction* ins, LiveRegisterSet liveRegs,
   10407             :                                    TypedOrValueRegister value, const ConstantOrRegister& id,
   10408             :                                    TypedOrValueRegister output, Register maybeTemp,
   10409             :                                    bool monitoredResult, bool allowDoubleResult,
   10410             :                                    jsbytecode* profilerLeavePc)
   10411             : {
   10412          23 :     CacheKind kind = CacheKind::GetElem;
   10413          23 :     if (id.constant() && id.value().isString()) {
   10414          11 :         JSString* idString = id.value().toString();
   10415             :         uint32_t dummy;
   10416          11 :         if (idString->isAtom() && !idString->asAtom().isIndex(&dummy))
   10417          11 :             kind = CacheKind::GetProp;
   10418             :     }
   10419             :     IonGetPropertyIC cache(kind, liveRegs, value, id, output, maybeTemp, monitoredResult,
   10420          23 :                            allowDoubleResult);
   10421          23 :     addIC(ins, allocateIC(cache));
   10422          23 : }
   10423             : 
   10424             : void
   10425           6 : CodeGenerator::addSetPropertyCache(LInstruction* ins, LiveRegisterSet liveRegs, Register objReg,
   10426             :                                    Register temp, FloatRegister tempDouble,
   10427             :                                    FloatRegister tempF32, const ConstantOrRegister& id,
   10428             :                                    const ConstantOrRegister& value,
   10429             :                                    bool strict, bool needsPostBarrier, bool needsTypeBarrier,
   10430             :                                    bool guardHoles, jsbytecode* profilerLeavePc)
   10431             : {
   10432           6 :     CacheKind kind = CacheKind::SetElem;
   10433           6 :     if (id.constant() && id.value().isString()) {
   10434           6 :         JSString* idString = id.value().toString();
   10435             :         uint32_t dummy;
   10436           6 :         if (idString->isAtom() && !idString->asAtom().isIndex(&dummy))
   10437           6 :             kind = CacheKind::SetProp;
   10438             :     }
   10439             :     IonSetPropertyIC cache(kind, liveRegs, objReg, temp, tempDouble, tempF32,
   10440           6 :                            id, value, strict, needsPostBarrier, needsTypeBarrier, guardHoles);
   10441           6 :     addIC(ins, allocateIC(cache));
   10442           6 : }
   10443             : 
   10444             : ConstantOrRegister
   10445          60 : CodeGenerator::toConstantOrRegister(LInstruction* lir, size_t n, MIRType type)
   10446             : {
   10447          60 :     if (type == MIRType::Value)
   10448           5 :         return TypedOrValueRegister(ToValue(lir, n));
   10449             : 
   10450          55 :     const LAllocation* value = lir->getOperand(n);
   10451          55 :     if (value->isConstant())
   10452          19 :         return ConstantOrRegister(value->toConstant()->toJSValue());
   10453             : 
   10454          36 :     return TypedOrValueRegister(type, ToAnyRegister(value));
   10455             : }
   10456             : 
   10457             : void
   10458          17 : CodeGenerator::visitGetPropertyCacheV(LGetPropertyCacheV* ins)
   10459             : {
   10460          17 :     LiveRegisterSet liveRegs = ins->safepoint()->liveRegs();
   10461             :     TypedOrValueRegister value =
   10462          17 :         toConstantOrRegister(ins, LGetPropertyCacheV::Value, ins->mir()->value()->type()).reg();
   10463          17 :     ConstantOrRegister id = toConstantOrRegister(ins, LGetPropertyCacheV::Id, ins->mir()->idval()->type());
   10464          17 :     bool monitoredResult = ins->mir()->monitoredResult();
   10465          17 :     TypedOrValueRegister output = TypedOrValueRegister(GetValueOutput(ins));
   10466          17 :     Register maybeTemp = ins->temp()->isBogusTemp() ? InvalidReg : ToRegister(ins->temp());
   10467             : 
   10468          51 :     addGetPropertyCache(ins, liveRegs, value, id, output, maybeTemp, monitoredResult,
   10469          51 :                         ins->mir()->allowDoubleResult(), ins->mir()->profilerLeavePc());
   10470          17 : }
   10471             : 
   10472             : void
   10473           6 : CodeGenerator::visitGetPropertyCacheT(LGetPropertyCacheT* ins)
   10474             : {
   10475           6 :     LiveRegisterSet liveRegs = ins->safepoint()->liveRegs();
   10476             :     TypedOrValueRegister value =
   10477           6 :         toConstantOrRegister(ins, LGetPropertyCacheV::Value, ins->mir()->value()->type()).reg();
   10478           6 :     ConstantOrRegister id = toConstantOrRegister(ins, LGetPropertyCacheT::Id, ins->mir()->idval()->type());
   10479           6 :     bool monitoredResult = ins->mir()->monitoredResult();
   10480           6 :     TypedOrValueRegister output(ins->mir()->type(), ToAnyRegister(ins->getDef(0)));
   10481           6 :     Register maybeTemp = ins->temp()->isBogusTemp() ? InvalidReg : ToRegister(ins->temp());
   10482             : 
   10483          18 :     addGetPropertyCache(ins, liveRegs, value, id, output, maybeTemp, monitoredResult,
   10484          18 :                         ins->mir()->allowDoubleResult(), ins->mir()->profilerLeavePc());
   10485           6 : }
   10486             : 
   10487             : void
   10488           0 : CodeGenerator::visitBindNameCache(LBindNameCache* ins)
   10489             : {
   10490           0 :     LiveRegisterSet liveRegs = ins->safepoint()->liveRegs();
   10491           0 :     Register envChain = ToRegister(ins->environmentChain());
   10492           0 :     Register output = ToRegister(ins->output());
   10493           0 :     Register temp = ToRegister(ins->temp());
   10494             : 
   10495           0 :     IonBindNameIC ic(liveRegs, envChain, output, temp);
   10496           0 :     addIC(ins, allocateIC(ic));
   10497           0 : }
   10498             : 
   10499             : void
   10500           0 : CodeGenerator::visitHasOwnCache(LHasOwnCache* ins)
   10501             : {
   10502           0 :     LiveRegisterSet liveRegs = ins->safepoint()->liveRegs();
   10503             :     TypedOrValueRegister value =
   10504           0 :         toConstantOrRegister(ins, LHasOwnCache::Value, ins->mir()->value()->type()).reg();
   10505             :     TypedOrValueRegister id =
   10506           0 :         toConstantOrRegister(ins, LHasOwnCache::Id, ins->mir()->idval()->type()).reg();
   10507           0 :     Register output = ToRegister(ins->output());
   10508             : 
   10509           0 :     IonHasOwnIC cache(liveRegs, value, id, output);
   10510           0 :     addIC(ins, allocateIC(cache));
   10511           0 : }
   10512             : 
   10513             : typedef bool (*SetPropertyFn)(JSContext*, HandleObject,
   10514             :                               HandlePropertyName, const HandleValue, bool, jsbytecode*);
   10515           3 : static const VMFunction SetPropertyInfo = FunctionInfo<SetPropertyFn>(SetProperty, "SetProperty");
   10516             : 
   10517             : void
   10518           0 : CodeGenerator::visitCallSetProperty(LCallSetProperty* ins)
   10519             : {
   10520           0 :     ConstantOrRegister value = TypedOrValueRegister(ToValue(ins, LCallSetProperty::Value));
   10521             : 
   10522           0 :     const Register objReg = ToRegister(ins->getOperand(0));
   10523             : 
   10524           0 :     pushArg(ImmPtr(ins->mir()->resumePoint()->pc()));
   10525           0 :     pushArg(Imm32(ins->mir()->strict()));
   10526             : 
   10527           0 :     pushArg(value);
   10528           0 :     pushArg(ImmGCPtr(ins->mir()->name()));
   10529           0 :     pushArg(objReg);
   10530             : 
   10531           0 :     callVM(SetPropertyInfo, ins);
   10532           0 : }
   10533             : 
   10534             : typedef bool (*DeletePropertyFn)(JSContext*, HandleValue, HandlePropertyName, bool*);
   10535           3 : static const VMFunction DeletePropertyStrictInfo =
   10536           6 :     FunctionInfo<DeletePropertyFn>(DeletePropertyJit<true>, "DeletePropertyStrictJit");
   10537           3 : static const VMFunction DeletePropertyNonStrictInfo =
   10538           6 :     FunctionInfo<DeletePropertyFn>(DeletePropertyJit<false>, "DeletePropertyNonStrictJit");
   10539             : 
   10540             : void
   10541           0 : CodeGenerator::visitCallDeleteProperty(LCallDeleteProperty* lir)
   10542             : {
   10543           0 :     pushArg(ImmGCPtr(lir->mir()->name()));
   10544           0 :     pushArg(ToValue(lir, LCallDeleteProperty::Value));
   10545             : 
   10546           0 :     if (lir->mir()->strict())
   10547           0 :         callVM(DeletePropertyStrictInfo, lir);
   10548             :     else
   10549           0 :         callVM(DeletePropertyNonStrictInfo, lir);
   10550           0 : }
   10551             : 
   10552             : typedef bool (*DeleteElementFn)(JSContext*, HandleValue, HandleValue, bool*);
   10553           3 : static const VMFunction DeleteElementStrictInfo =
   10554           6 :     FunctionInfo<DeleteElementFn>(DeleteElementJit<true>, "DeleteElementStrictJit");
   10555           3 : static const VMFunction DeleteElementNonStrictInfo =
   10556           6 :     FunctionInfo<DeleteElementFn>(DeleteElementJit<false>, "DeleteElementNonStrictJit");
   10557             : 
   10558             : void
   10559           0 : CodeGenerator::visitCallDeleteElement(LCallDeleteElement* lir)
   10560             : {
   10561           0 :     pushArg(ToValue(lir, LCallDeleteElement::Index));
   10562           0 :     pushArg(ToValue(lir, LCallDeleteElement::Value));
   10563             : 
   10564           0 :     if (lir->mir()->strict())
   10565           0 :         callVM(DeleteElementStrictInfo, lir);
   10566             :     else
   10567           0 :         callVM(DeleteElementNonStrictInfo, lir);
   10568           0 : }
   10569             : 
   10570             : void
   10571           6 : CodeGenerator::visitSetPropertyCache(LSetPropertyCache* ins)
   10572             : {
   10573           6 :     LiveRegisterSet liveRegs = ins->safepoint()->liveRegs();
   10574           6 :     Register objReg = ToRegister(ins->getOperand(0));
   10575           6 :     Register temp = ToRegister(ins->temp());
   10576           6 :     FloatRegister tempDouble = ToTempFloatRegisterOrInvalid(ins->tempDouble());
   10577           6 :     FloatRegister tempF32 = ToTempFloatRegisterOrInvalid(ins->tempFloat32());
   10578             : 
   10579             :     ConstantOrRegister id =
   10580           6 :         toConstantOrRegister(ins, LSetPropertyCache::Id, ins->mir()->idval()->type());
   10581             :     ConstantOrRegister value =
   10582           6 :         toConstantOrRegister(ins, LSetPropertyCache::Value, ins->mir()->value()->type());
   10583             : 
   10584          36 :     addSetPropertyCache(ins, liveRegs, objReg, temp, tempDouble, tempF32,
   10585          12 :                         id, value, ins->mir()->strict(), ins->mir()->needsPostBarrier(),
   10586          12 :                         ins->mir()->needsTypeBarrier(), ins->mir()->guardHoles(),
   10587          12 :                         ins->mir()->profilerLeavePc());
   10588           6 : }
   10589             : 
   10590             : typedef bool (*ThrowFn)(JSContext*, HandleValue);
   10591           3 : static const VMFunction ThrowInfoCodeGen = FunctionInfo<ThrowFn>(js::Throw, "Throw");
   10592             : 
   10593             : void
   10594           1 : CodeGenerator::visitThrow(LThrow* lir)
   10595             : {
   10596           1 :     pushArg(ToValue(lir, LThrow::Value));
   10597           1 :     callVM(ThrowInfoCodeGen, lir);
   10598           1 : }
   10599             : 
   10600             : typedef bool (*BitNotFn)(JSContext*, HandleValue, int* p);
   10601           3 : static const VMFunction BitNotInfo = FunctionInfo<BitNotFn>(BitNot, "BitNot");
   10602             : 
   10603             : void
   10604           0 : CodeGenerator::visitBitNotV(LBitNotV* lir)
   10605             : {
   10606           0 :     pushArg(ToValue(lir, LBitNotV::Input));
   10607           0 :     callVM(BitNotInfo, lir);
   10608           0 : }
   10609             : 
   10610             : typedef bool (*BitopFn)(JSContext*, HandleValue, HandleValue, int* p);
   10611           3 : static const VMFunction BitAndInfo = FunctionInfo<BitopFn>(BitAnd, "BitAnd");
   10612           3 : static const VMFunction BitOrInfo = FunctionInfo<BitopFn>(BitOr, "BitOr");
   10613           3 : static const VMFunction BitXorInfo = FunctionInfo<BitopFn>(BitXor, "BitXor");
   10614           3 : static const VMFunction BitLhsInfo = FunctionInfo<BitopFn>(BitLsh, "BitLsh");
   10615           3 : static const VMFunction BitRhsInfo = FunctionInfo<BitopFn>(BitRsh, "BitRsh");
   10616             : 
   10617             : void
   10618           0 : CodeGenerator::visitBitOpV(LBitOpV* lir)
   10619             : {
   10620           0 :     pushArg(ToValue(lir, LBitOpV::RhsInput));
   10621           0 :     pushArg(ToValue(lir, LBitOpV::LhsInput));
   10622             : 
   10623           0 :     switch (lir->jsop()) {
   10624             :       case JSOP_BITAND:
   10625           0 :         callVM(BitAndInfo, lir);
   10626           0 :         break;
   10627             :       case JSOP_BITOR:
   10628           0 :         callVM(BitOrInfo, lir);
   10629           0 :         break;
   10630             :       case JSOP_BITXOR:
   10631           0 :         callVM(BitXorInfo, lir);
   10632           0 :         break;
   10633             :       case JSOP_LSH:
   10634           0 :         callVM(BitLhsInfo, lir);
   10635           0 :         break;
   10636             :       case JSOP_RSH:
   10637           0 :         callVM(BitRhsInfo, lir);
   10638           0 :         break;
   10639             :       default:
   10640           0 :         MOZ_CRASH("unexpected bitop");
   10641             :     }
   10642           0 : }
   10643             : 
   10644             : class OutOfLineTypeOfV : public OutOfLineCodeBase<CodeGenerator>
   10645             : {
   10646             :     LTypeOfV* ins_;
   10647             : 
   10648             :   public:
   10649           0 :     explicit OutOfLineTypeOfV(LTypeOfV* ins)
   10650           0 :       : ins_(ins)
   10651           0 :     { }
   10652             : 
   10653           0 :     void accept(CodeGenerator* codegen) {
   10654           0 :         codegen->visitOutOfLineTypeOfV(this);
   10655           0 :     }
   10656           0 :     LTypeOfV* ins() const {
   10657           0 :         return ins_;
   10658             :     }
   10659             : };
   10660             : 
   10661             : void
   10662           0 : CodeGenerator::visitTypeOfV(LTypeOfV* lir)
   10663             : {
   10664           0 :     const ValueOperand value = ToValue(lir, LTypeOfV::Input);
   10665           0 :     Register output = ToRegister(lir->output());
   10666           0 :     Register tag = masm.splitTagForTest(value);
   10667             : 
   10668           0 :     const JSAtomState& names = GetJitContext()->runtime->names();
   10669           0 :     Label done;
   10670             : 
   10671           0 :     MDefinition* input = lir->mir()->input();
   10672             : 
   10673           0 :     bool testObject = input->mightBeType(MIRType::Object);
   10674           0 :     bool testNumber = input->mightBeType(MIRType::Int32) || input->mightBeType(MIRType::Double);
   10675           0 :     bool testBoolean = input->mightBeType(MIRType::Boolean);
   10676           0 :     bool testUndefined = input->mightBeType(MIRType::Undefined);
   10677           0 :     bool testNull = input->mightBeType(MIRType::Null);
   10678           0 :     bool testString = input->mightBeType(MIRType::String);
   10679           0 :     bool testSymbol = input->mightBeType(MIRType::Symbol);
   10680             : 
   10681           0 :     unsigned numTests = unsigned(testObject) + unsigned(testNumber) + unsigned(testBoolean) +
   10682           0 :         unsigned(testUndefined) + unsigned(testNull) + unsigned(testString) + unsigned(testSymbol);
   10683             : 
   10684           0 :     MOZ_ASSERT_IF(!input->emptyResultTypeSet(), numTests > 0);
   10685             : 
   10686           0 :     OutOfLineTypeOfV* ool = nullptr;
   10687           0 :     if (testObject) {
   10688           0 :         if (lir->mir()->inputMaybeCallableOrEmulatesUndefined()) {
   10689             :             // The input may be a callable object (result is "function") or may
   10690             :             // emulate undefined (result is "undefined"). Use an OOL path.
   10691           0 :             ool = new(alloc()) OutOfLineTypeOfV(lir);
   10692           0 :             addOutOfLineCode(ool, lir->mir());
   10693             : 
   10694           0 :             if (numTests > 1)
   10695           0 :                 masm.branchTestObject(Assembler::Equal, tag, ool->entry());
   10696             :             else
   10697           0 :                 masm.jump(ool->entry());
   10698             :         } else {
   10699             :             // Input is not callable and does not emulate undefined, so if
   10700             :             // it's an object the result is always "object".
   10701           0 :             Label notObject;
   10702           0 :             if (numTests > 1)
   10703           0 :                 masm.branchTestObject(Assembler::NotEqual, tag, &notObject);
   10704           0 :             masm.movePtr(ImmGCPtr(names.object), output);
   10705           0 :             if (numTests > 1)
   10706           0 :                 masm.jump(&done);
   10707           0 :             masm.bind(&notObject);
   10708             :         }
   10709           0 :         numTests--;
   10710             :     }
   10711             : 
   10712           0 :     if (testNumber) {
   10713           0 :         Label notNumber;
   10714           0 :         if (numTests > 1)
   10715           0 :             masm.branchTestNumber(Assembler::NotEqual, tag, &notNumber);
   10716           0 :         masm.movePtr(ImmGCPtr(names.number), output);
   10717           0 :         if (numTests > 1)
   10718           0 :             masm.jump(&done);
   10719           0 :         masm.bind(&notNumber);
   10720           0 :         numTests--;
   10721             :     }
   10722             : 
   10723           0 :     if (testUndefined) {
   10724           0 :         Label notUndefined;
   10725           0 :         if (numTests > 1)
   10726           0 :             masm.branchTestUndefined(Assembler::NotEqual, tag, &notUndefined);
   10727           0 :         masm.movePtr(ImmGCPtr(names.undefined), output);
   10728           0 :         if (numTests > 1)
   10729           0 :             masm.jump(&done);
   10730           0 :         masm.bind(&notUndefined);
   10731           0 :         numTests--;
   10732             :     }
   10733             : 
   10734           0 :     if (testNull) {
   10735           0 :         Label notNull;
   10736           0 :         if (numTests > 1)
   10737           0 :             masm.branchTestNull(Assembler::NotEqual, tag, &notNull);
   10738           0 :         masm.movePtr(ImmGCPtr(names.object), output);
   10739           0 :         if (numTests > 1)
   10740           0 :             masm.jump(&done);
   10741           0 :         masm.bind(&notNull);
   10742           0 :         numTests--;
   10743             :     }
   10744             : 
   10745           0 :     if (testBoolean) {
   10746           0 :         Label notBoolean;
   10747           0 :         if (numTests > 1)
   10748           0 :             masm.branchTestBoolean(Assembler::NotEqual, tag, &notBoolean);
   10749           0 :         masm.movePtr(ImmGCPtr(names.boolean), output);
   10750           0 :         if (numTests > 1)
   10751           0 :             masm.jump(&done);
   10752           0 :         masm.bind(&notBoolean);
   10753           0 :         numTests--;
   10754             :     }
   10755             : 
   10756           0 :     if (testString) {
   10757           0 :         Label notString;
   10758           0 :         if (numTests > 1)
   10759           0 :             masm.branchTestString(Assembler::NotEqual, tag, &notString);
   10760           0 :         masm.movePtr(ImmGCPtr(names.string), output);
   10761           0 :         if (numTests > 1)
   10762           0 :             masm.jump(&done);
   10763           0 :         masm.bind(&notString);
   10764           0 :         numTests--;
   10765             :     }
   10766             : 
   10767           0 :     if (testSymbol) {
   10768           0 :         Label notSymbol;
   10769           0 :         if (numTests > 1)
   10770           0 :             masm.branchTestSymbol(Assembler::NotEqual, tag, &notSymbol);
   10771           0 :         masm.movePtr(ImmGCPtr(names.symbol), output);
   10772           0 :         if (numTests > 1)
   10773           0 :             masm.jump(&done);
   10774           0 :         masm.bind(&notSymbol);
   10775           0 :         numTests--;
   10776             :     }
   10777             : 
   10778           0 :     MOZ_ASSERT(numTests == 0);
   10779             : 
   10780           0 :     masm.bind(&done);
   10781           0 :     if (ool)
   10782           0 :         masm.bind(ool->rejoin());
   10783           0 : }
   10784             : 
   10785             : void
   10786           0 : CodeGenerator::visitOutOfLineTypeOfV(OutOfLineTypeOfV* ool)
   10787             : {
   10788           0 :     LTypeOfV* ins = ool->ins();
   10789           0 :     const JSAtomState& names = GetJitContext()->runtime->names();
   10790             : 
   10791           0 :     ValueOperand input = ToValue(ins, LTypeOfV::Input);
   10792           0 :     Register temp = ToTempUnboxRegister(ins->tempToUnbox());
   10793           0 :     Register output = ToRegister(ins->output());
   10794             : 
   10795           0 :     Register obj = masm.extractObject(input, temp);
   10796             : 
   10797           0 :     Label slowCheck, isObject, isCallable, isUndefined, done;
   10798           0 :     masm.typeOfObject(obj, output, &slowCheck, &isObject, &isCallable, &isUndefined);
   10799             : 
   10800           0 :     masm.bind(&isCallable);
   10801           0 :     masm.movePtr(ImmGCPtr(names.function), output);
   10802           0 :     masm.jump(ool->rejoin());
   10803             : 
   10804           0 :     masm.bind(&isUndefined);
   10805           0 :     masm.movePtr(ImmGCPtr(names.undefined), output);
   10806           0 :     masm.jump(ool->rejoin());
   10807             : 
   10808           0 :     masm.bind(&isObject);
   10809           0 :     masm.movePtr(ImmGCPtr(names.object), output);
   10810           0 :     masm.jump(ool->rejoin());
   10811             : 
   10812           0 :     masm.bind(&slowCheck);
   10813             : 
   10814           0 :     saveVolatile(output);
   10815           0 :     masm.setupUnalignedABICall(output);
   10816           0 :     masm.passABIArg(obj);
   10817           0 :     masm.movePtr(ImmPtr(GetJitContext()->runtime), output);
   10818           0 :     masm.passABIArg(output);
   10819           0 :     masm.callWithABI(JS_FUNC_TO_DATA_PTR(void*, TypeOfObject));
   10820           0 :     masm.storeCallWordResult(output);
   10821           0 :     restoreVolatile(output);
   10822             : 
   10823           0 :     masm.jump(ool->rejoin());
   10824           0 : }
   10825             : 
   10826             : typedef JSObject* (*ToAsyncFn)(JSContext*, HandleFunction);
   10827           3 : static const VMFunction ToAsyncInfo = FunctionInfo<ToAsyncFn>(js::WrapAsyncFunction, "ToAsync");
   10828             : 
   10829             : void
   10830           0 : CodeGenerator::visitToAsync(LToAsync* lir)
   10831             : {
   10832           0 :     pushArg(ToRegister(lir->unwrapped()));
   10833           0 :     callVM(ToAsyncInfo, lir);
   10834           0 : }
   10835             : 
   10836             : typedef JSObject* (*ToAsyncGenFn)(JSContext*, HandleFunction);
   10837           3 : static const VMFunction ToAsyncGenInfo =
   10838           6 :     FunctionInfo<ToAsyncGenFn>(js::WrapAsyncGenerator, "ToAsyncGen");
   10839             : 
   10840             : void
   10841           0 : CodeGenerator::visitToAsyncGen(LToAsyncGen* lir)
   10842             : {
   10843           0 :     pushArg(ToRegister(lir->unwrapped()));
   10844           0 :     callVM(ToAsyncGenInfo, lir);
   10845           0 : }
   10846             : 
   10847             : typedef JSObject* (*ToAsyncIterFn)(JSContext*, HandleObject);
   10848           3 : static const VMFunction ToAsyncIterInfo =
   10849           6 :     FunctionInfo<ToAsyncIterFn>(js::CreateAsyncFromSyncIterator, "ToAsyncIter");
   10850             : 
   10851             : void
   10852           0 : CodeGenerator::visitToAsyncIter(LToAsyncIter* lir)
   10853             : {
   10854           0 :     pushArg(ToRegister(lir->unwrapped()));
   10855           0 :     callVM(ToAsyncIterInfo, lir);
   10856           0 : }
   10857             : 
   10858             : typedef bool (*ToIdFn)(JSContext*, HandleScript, jsbytecode*, HandleValue,
   10859             :                        MutableHandleValue);
   10860           3 : static const VMFunction ToIdInfo = FunctionInfo<ToIdFn>(ToIdOperation, "ToIdOperation");
   10861             : 
   10862             : void
   10863           0 : CodeGenerator::visitToIdV(LToIdV* lir)
   10864             : {
   10865           0 :     Label notInt32;
   10866           0 :     FloatRegister temp = ToFloatRegister(lir->tempFloat());
   10867           0 :     const ValueOperand out = ToOutValue(lir);
   10868           0 :     ValueOperand input = ToValue(lir, LToIdV::Input);
   10869             : 
   10870           0 :     OutOfLineCode* ool = oolCallVM(ToIdInfo, lir,
   10871           0 :                                    ArgList(ImmGCPtr(current->mir()->info().script()),
   10872           0 :                                            ImmPtr(lir->mir()->resumePoint()->pc()),
   10873           0 :                                            ToValue(lir, LToIdV::Input)),
   10874           0 :                                    StoreValueTo(out));
   10875             : 
   10876           0 :     Register tag = masm.splitTagForTest(input);
   10877             : 
   10878           0 :     masm.branchTestInt32(Assembler::NotEqual, tag, &notInt32);
   10879           0 :     masm.moveValue(input, out);
   10880           0 :     masm.jump(ool->rejoin());
   10881             : 
   10882           0 :     masm.bind(&notInt32);
   10883           0 :     masm.branchTestDouble(Assembler::NotEqual, tag, ool->entry());
   10884           0 :     masm.unboxDouble(input, temp);
   10885           0 :     masm.convertDoubleToInt32(temp, out.scratchReg(), ool->entry(), true);
   10886           0 :     masm.tagValue(JSVAL_TYPE_INT32, out.scratchReg(), out);
   10887             : 
   10888           0 :     masm.bind(ool->rejoin());
   10889           0 : }
   10890             : 
   10891             : template<typename T>
   10892             : void
   10893           1 : CodeGenerator::emitLoadElementT(LLoadElementT* lir, const T& source)
   10894             : {
   10895           1 :     if (LIRGenerator::allowTypedElementHoleCheck()) {
   10896           0 :         if (lir->mir()->needsHoleCheck()) {
   10897           0 :             Label bail;
   10898           0 :             masm.branchTestMagic(Assembler::Equal, source, &bail);
   10899           0 :             bailoutFrom(&bail, lir->snapshot());
   10900             :         }
   10901             :     } else {
   10902           1 :         MOZ_ASSERT(!lir->mir()->needsHoleCheck());
   10903             :     }
   10904             : 
   10905           1 :     AnyRegister output = ToAnyRegister(lir->output());
   10906           1 :     if (lir->mir()->loadDoubles())
   10907           0 :         masm.loadDouble(source, output.fpu());
   10908             :     else
   10909           1 :         masm.loadUnboxedValue(source, lir->mir()->type(), output);
   10910           1 : }
   10911             : 
   10912             : void
   10913           1 : CodeGenerator::visitLoadElementT(LLoadElementT* lir)
   10914             : {
   10915           1 :     Register elements = ToRegister(lir->elements());
   10916           1 :     const LAllocation* index = lir->index();
   10917           1 :     if (index->isConstant()) {
   10918           0 :         int32_t offset = ToInt32(index) * sizeof(js::Value) + lir->mir()->offsetAdjustment();
   10919           0 :         emitLoadElementT(lir, Address(elements, offset));
   10920             :     } else {
   10921           2 :         emitLoadElementT(lir, BaseIndex(elements, ToRegister(index), TimesEight,
   10922           1 :                                         lir->mir()->offsetAdjustment()));
   10923             :     }
   10924           1 : }
   10925             : 
   10926             : void
   10927           0 : CodeGenerator::visitLoadElementV(LLoadElementV* load)
   10928             : {
   10929           0 :     Register elements = ToRegister(load->elements());
   10930           0 :     const ValueOperand out = ToOutValue(load);
   10931             : 
   10932           0 :     if (load->index()->isConstant()) {
   10933           0 :         NativeObject::elementsSizeMustNotOverflow();
   10934           0 :         int32_t offset = ToInt32(load->index()) * sizeof(Value) + load->mir()->offsetAdjustment();
   10935           0 :         masm.loadValue(Address(elements, offset), out);
   10936             :     } else {
   10937           0 :         masm.loadValue(BaseObjectElementIndex(elements, ToRegister(load->index()),
   10938           0 :                                               load->mir()->offsetAdjustment()), out);
   10939             :     }
   10940             : 
   10941           0 :     if (load->mir()->needsHoleCheck()) {
   10942           0 :         Label testMagic;
   10943           0 :         masm.branchTestMagic(Assembler::Equal, out, &testMagic);
   10944           0 :         bailoutFrom(&testMagic, load->snapshot());
   10945             :     }
   10946           0 : }
   10947             : 
   10948             : void
   10949           0 : CodeGenerator::visitLoadElementHole(LLoadElementHole* lir)
   10950             : {
   10951           0 :     Register elements = ToRegister(lir->elements());
   10952           0 :     Register initLength = ToRegister(lir->initLength());
   10953           0 :     const ValueOperand out = ToOutValue(lir);
   10954             : 
   10955           0 :     const MLoadElementHole* mir = lir->mir();
   10956             : 
   10957             :     // If the index is out of bounds, load |undefined|. Otherwise, load the
   10958             :     // value.
   10959           0 :     Label undefined, done;
   10960           0 :     if (lir->index()->isConstant())
   10961           0 :         masm.branch32(Assembler::BelowOrEqual, initLength, Imm32(ToInt32(lir->index())), &undefined);
   10962             :     else
   10963           0 :         masm.branch32(Assembler::BelowOrEqual, initLength, ToRegister(lir->index()), &undefined);
   10964             : 
   10965           0 :     if (mir->unboxedType() != JSVAL_TYPE_MAGIC) {
   10966           0 :         size_t width = UnboxedTypeSize(mir->unboxedType());
   10967           0 :         if (lir->index()->isConstant()) {
   10968           0 :             Address addr(elements, ToInt32(lir->index()) * width);
   10969           0 :             masm.loadUnboxedProperty(addr, mir->unboxedType(), out);
   10970             :         } else {
   10971           0 :             BaseIndex addr(elements, ToRegister(lir->index()), ScaleFromElemWidth(width));
   10972           0 :             masm.loadUnboxedProperty(addr, mir->unboxedType(), out);
   10973             :         }
   10974             :     } else {
   10975           0 :         if (lir->index()->isConstant()) {
   10976           0 :             NativeObject::elementsSizeMustNotOverflow();
   10977           0 :             masm.loadValue(Address(elements, ToInt32(lir->index()) * sizeof(Value)), out);
   10978             :         } else {
   10979           0 :             masm.loadValue(BaseObjectElementIndex(elements, ToRegister(lir->index())), out);
   10980             :         }
   10981             :     }
   10982             : 
   10983             :     // If a hole check is needed, and the value wasn't a hole, we're done.
   10984             :     // Otherwise, we'll load undefined.
   10985           0 :     if (lir->mir()->needsHoleCheck())
   10986           0 :         masm.branchTestMagic(Assembler::NotEqual, out, &done);
   10987             :     else
   10988           0 :         masm.jump(&done);
   10989             : 
   10990           0 :     masm.bind(&undefined);
   10991             : 
   10992           0 :     if (mir->needsNegativeIntCheck()) {
   10993           0 :         if (lir->index()->isConstant()) {
   10994           0 :             if (ToInt32(lir->index()) < 0)
   10995           0 :                 bailout(lir->snapshot());
   10996             :         } else {
   10997           0 :             Label negative;
   10998           0 :             masm.branch32(Assembler::LessThan, ToRegister(lir->index()), Imm32(0), &negative);
   10999           0 :             bailoutFrom(&negative, lir->snapshot());
   11000             :         }
   11001             :     }
   11002             : 
   11003           0 :     masm.moveValue(UndefinedValue(), out);
   11004           0 :     masm.bind(&done);
   11005           0 : }
   11006             : 
   11007             : void
   11008           0 : CodeGenerator::visitLoadUnboxedPointerV(LLoadUnboxedPointerV* lir)
   11009             : {
   11010           0 :     Register elements = ToRegister(lir->elements());
   11011           0 :     const ValueOperand out = ToOutValue(lir);
   11012             : 
   11013           0 :     if (lir->index()->isConstant()) {
   11014           0 :         int32_t offset = ToInt32(lir->index()) * sizeof(uintptr_t) + lir->mir()->offsetAdjustment();
   11015           0 :         masm.loadPtr(Address(elements, offset), out.scratchReg());
   11016             :     } else {
   11017           0 :         masm.loadPtr(BaseIndex(elements, ToRegister(lir->index()), ScalePointer,
   11018           0 :                                lir->mir()->offsetAdjustment()), out.scratchReg());
   11019             :     }
   11020             : 
   11021           0 :     Label notNull, done;
   11022           0 :     masm.branchPtr(Assembler::NotEqual, out.scratchReg(), ImmWord(0), &notNull);
   11023             : 
   11024           0 :     masm.moveValue(NullValue(), out);
   11025           0 :     masm.jump(&done);
   11026             : 
   11027           0 :     masm.bind(&notNull);
   11028           0 :     masm.tagValue(JSVAL_TYPE_OBJECT, out.scratchReg(), out);
   11029             : 
   11030           0 :     masm.bind(&done);
   11031           0 : }
   11032             : 
   11033             : void
   11034           0 : CodeGenerator::visitLoadUnboxedPointerT(LLoadUnboxedPointerT* lir)
   11035             : {
   11036           0 :     Register elements = ToRegister(lir->elements());
   11037           0 :     const LAllocation* index = lir->index();
   11038           0 :     Register out = ToRegister(lir->output());
   11039             : 
   11040             :     bool bailOnNull;
   11041             :     int32_t offsetAdjustment;
   11042           0 :     if (lir->mir()->isLoadUnboxedObjectOrNull()) {
   11043           0 :         bailOnNull = lir->mir()->toLoadUnboxedObjectOrNull()->nullBehavior() ==
   11044             :                      MLoadUnboxedObjectOrNull::BailOnNull;
   11045           0 :         offsetAdjustment = lir->mir()->toLoadUnboxedObjectOrNull()->offsetAdjustment();
   11046           0 :     } else if (lir->mir()->isLoadUnboxedString()) {
   11047           0 :         bailOnNull = false;
   11048           0 :         offsetAdjustment = lir->mir()->toLoadUnboxedString()->offsetAdjustment();
   11049             :     } else {
   11050           0 :         MOZ_CRASH();
   11051             :     }
   11052             : 
   11053           0 :     if (index->isConstant()) {
   11054           0 :         Address source(elements, ToInt32(index) * sizeof(uintptr_t) + offsetAdjustment);
   11055           0 :         masm.loadPtr(source, out);
   11056             :     } else {
   11057           0 :         BaseIndex source(elements, ToRegister(index), ScalePointer, offsetAdjustment);
   11058           0 :         masm.loadPtr(source, out);
   11059             :     }
   11060             : 
   11061           0 :     if (bailOnNull) {
   11062           0 :         Label bail;
   11063           0 :         masm.branchTestPtr(Assembler::Zero, out, out, &bail);
   11064           0 :         bailoutFrom(&bail, lir->snapshot());
   11065             :     }
   11066           0 : }
   11067             : 
   11068             : void
   11069           0 : CodeGenerator::visitUnboxObjectOrNull(LUnboxObjectOrNull* lir)
   11070             : {
   11071           0 :     Register obj = ToRegister(lir->input());
   11072             : 
   11073           0 :     if (lir->mir()->fallible()) {
   11074           0 :         Label bail;
   11075           0 :         masm.branchTestPtr(Assembler::Zero, obj, obj, &bail);
   11076           0 :         bailoutFrom(&bail, lir->snapshot());
   11077             :     }
   11078           0 : }
   11079             : 
   11080             : void
   11081           0 : CodeGenerator::visitLoadUnboxedScalar(LLoadUnboxedScalar* lir)
   11082             : {
   11083           0 :     Register elements = ToRegister(lir->elements());
   11084           0 :     Register temp = lir->temp()->isBogusTemp() ? InvalidReg : ToRegister(lir->temp());
   11085           0 :     AnyRegister out = ToAnyRegister(lir->output());
   11086             : 
   11087           0 :     const MLoadUnboxedScalar* mir = lir->mir();
   11088             : 
   11089           0 :     Scalar::Type readType = mir->readType();
   11090           0 :     unsigned numElems = mir->numElems();
   11091             : 
   11092           0 :     int width = Scalar::byteSize(mir->storageType());
   11093           0 :     bool canonicalizeDouble = mir->canonicalizeDoubles();
   11094             : 
   11095           0 :     Label fail;
   11096           0 :     if (lir->index()->isConstant()) {
   11097           0 :         Address source(elements, ToInt32(lir->index()) * width + mir->offsetAdjustment());
   11098           0 :         masm.loadFromTypedArray(readType, source, out, temp, &fail, canonicalizeDouble, numElems);
   11099             :     } else {
   11100             :         BaseIndex source(elements, ToRegister(lir->index()), ScaleFromElemWidth(width),
   11101           0 :                          mir->offsetAdjustment());
   11102           0 :         masm.loadFromTypedArray(readType, source, out, temp, &fail, canonicalizeDouble, numElems);
   11103             :     }
   11104             : 
   11105           0 :     if (fail.used())
   11106           0 :         bailoutFrom(&fail, lir->snapshot());
   11107           0 : }
   11108             : 
   11109             : void
   11110           0 : CodeGenerator::visitLoadTypedArrayElementHole(LLoadTypedArrayElementHole* lir)
   11111             : {
   11112           0 :     Register object = ToRegister(lir->object());
   11113           0 :     const ValueOperand out = ToOutValue(lir);
   11114             : 
   11115             :     // Load the length.
   11116           0 :     Register scratch = out.scratchReg();
   11117           0 :     RegisterOrInt32Constant key = ToRegisterOrInt32Constant(lir->index());
   11118           0 :     masm.unboxInt32(Address(object, TypedArrayObject::lengthOffset()), scratch);
   11119             : 
   11120             :     // Load undefined unless length > key.
   11121           0 :     Label inbounds, done;
   11122           0 :     masm.branch32(Assembler::Above, scratch, key, &inbounds);
   11123           0 :     masm.moveValue(UndefinedValue(), out);
   11124           0 :     masm.jump(&done);
   11125             : 
   11126             :     // Load the elements vector.
   11127           0 :     masm.bind(&inbounds);
   11128           0 :     masm.loadPtr(Address(object, TypedArrayObject::dataOffset()), scratch);
   11129             : 
   11130           0 :     Scalar::Type arrayType = lir->mir()->arrayType();
   11131           0 :     int width = Scalar::byteSize(arrayType);
   11132             : 
   11133           0 :     Label fail;
   11134           0 :     if (key.isConstant()) {
   11135           0 :         Address source(scratch, key.constant() * width);
   11136           0 :         masm.loadFromTypedArray(arrayType, source, out, lir->mir()->allowDouble(),
   11137           0 :                                 out.scratchReg(), &fail);
   11138             :     } else {
   11139           0 :         BaseIndex source(scratch, key.reg(), ScaleFromElemWidth(width));
   11140           0 :         masm.loadFromTypedArray(arrayType, source, out, lir->mir()->allowDouble(),
   11141           0 :                                 out.scratchReg(), &fail);
   11142             :     }
   11143             : 
   11144           0 :     if (fail.used())
   11145           0 :         bailoutFrom(&fail, lir->snapshot());
   11146             : 
   11147           0 :     masm.bind(&done);
   11148           0 : }
   11149             : 
   11150             : template <typename T>
   11151             : static inline void
   11152           0 : StoreToTypedArray(MacroAssembler& masm, Scalar::Type writeType, const LAllocation* value,
   11153             :                   const T& dest, unsigned numElems = 0)
   11154             : {
   11155           0 :     if (Scalar::isSimdType(writeType) ||
   11156           0 :         writeType == Scalar::Float32 ||
   11157             :         writeType == Scalar::Float64)
   11158             :     {
   11159           0 :         masm.storeToTypedFloatArray(writeType, ToFloatRegister(value), dest, numElems);
   11160             :     } else {
   11161           0 :         if (value->isConstant())
   11162           0 :             masm.storeToTypedIntArray(writeType, Imm32(ToInt32(value)), dest);
   11163             :         else
   11164           0 :             masm.storeToTypedIntArray(writeType, ToRegister(value), dest);
   11165             :     }
   11166           0 : }
   11167             : 
   11168             : void
   11169           0 : CodeGenerator::visitStoreUnboxedScalar(LStoreUnboxedScalar* lir)
   11170             : {
   11171           0 :     Register elements = ToRegister(lir->elements());
   11172           0 :     const LAllocation* value = lir->value();
   11173             : 
   11174           0 :     const MStoreUnboxedScalar* mir = lir->mir();
   11175             : 
   11176           0 :     Scalar::Type writeType = mir->writeType();
   11177           0 :     unsigned numElems = mir->numElems();
   11178             : 
   11179           0 :     int width = Scalar::byteSize(mir->storageType());
   11180             : 
   11181           0 :     if (lir->index()->isConstant()) {
   11182           0 :         Address dest(elements, ToInt32(lir->index()) * width + mir->offsetAdjustment());
   11183           0 :         StoreToTypedArray(masm, writeType, value, dest, numElems);
   11184             :     } else {
   11185             :         BaseIndex dest(elements, ToRegister(lir->index()), ScaleFromElemWidth(width),
   11186           0 :                        mir->offsetAdjustment());
   11187           0 :         StoreToTypedArray(masm, writeType, value, dest, numElems);
   11188             :     }
   11189           0 : }
   11190             : 
   11191             : void
   11192           0 : CodeGenerator::visitStoreTypedArrayElementHole(LStoreTypedArrayElementHole* lir)
   11193             : {
   11194           0 :     Register elements = ToRegister(lir->elements());
   11195           0 :     const LAllocation* value = lir->value();
   11196             : 
   11197           0 :     Scalar::Type arrayType = lir->mir()->arrayType();
   11198           0 :     int width = Scalar::byteSize(arrayType);
   11199             : 
   11200           0 :     const LAllocation* index = lir->index();
   11201           0 :     const LAllocation* length = lir->length();
   11202             : 
   11203           0 :     bool guardLength = true;
   11204           0 :     if (index->isConstant() && length->isConstant()) {
   11205           0 :         uint32_t idx = ToInt32(index);
   11206           0 :         uint32_t len = ToInt32(length);
   11207           0 :         if (idx >= len)
   11208           0 :             return;
   11209           0 :         guardLength = false;
   11210             :     }
   11211           0 :     Label skip;
   11212           0 :     if (index->isConstant()) {
   11213           0 :         uint32_t idx = ToInt32(index);
   11214           0 :         if (guardLength) {
   11215           0 :             if (length->isRegister())
   11216           0 :                 masm.branch32(Assembler::BelowOrEqual, ToRegister(length), Imm32(idx), &skip);
   11217             :             else
   11218           0 :                 masm.branch32(Assembler::BelowOrEqual, ToAddress(length), Imm32(idx), &skip);
   11219             :         }
   11220           0 :         Address dest(elements, idx * width);
   11221           0 :         StoreToTypedArray(masm, arrayType, value, dest);
   11222             :     } else {
   11223           0 :         Register idxReg = ToRegister(index);
   11224           0 :         MOZ_ASSERT(guardLength);
   11225           0 :         if (length->isConstant())
   11226           0 :             masm.branch32(Assembler::AboveOrEqual, idxReg, Imm32(ToInt32(length)), &skip);
   11227           0 :         else if (length->isRegister())
   11228           0 :             masm.branch32(Assembler::BelowOrEqual, ToRegister(length), idxReg, &skip);
   11229             :         else
   11230           0 :             masm.branch32(Assembler::BelowOrEqual, ToAddress(length), idxReg, &skip);
   11231           0 :         BaseIndex dest(elements, ToRegister(index), ScaleFromElemWidth(width));
   11232           0 :         StoreToTypedArray(masm, arrayType, value, dest);
   11233             :     }
   11234           0 :     if (guardLength)
   11235           0 :         masm.bind(&skip);
   11236             : }
   11237             : 
   11238             : void
   11239           0 : CodeGenerator::visitAtomicIsLockFree(LAtomicIsLockFree* lir)
   11240             : {
   11241           0 :     Register value = ToRegister(lir->value());
   11242           0 :     Register output = ToRegister(lir->output());
   11243             : 
   11244             :     // Keep this in sync with isLockfree() in jit/AtomicOperations.h.
   11245           0 :     MOZ_ASSERT(AtomicOperations::isLockfree(1));  // Implementation artifact
   11246           0 :     MOZ_ASSERT(AtomicOperations::isLockfree(2));  // Implementation artifact
   11247           0 :     MOZ_ASSERT(AtomicOperations::isLockfree(4));  // Spec requirement
   11248           0 :     MOZ_ASSERT(!AtomicOperations::isLockfree(8)); // Implementation invariant, for now
   11249             : 
   11250           0 :     Label Ldone, Lfailed;
   11251           0 :     masm.move32(Imm32(1), output);
   11252           0 :     masm.branch32(Assembler::Equal, value, Imm32(4), &Ldone);
   11253           0 :     masm.branch32(Assembler::Equal, value, Imm32(2), &Ldone);
   11254           0 :     masm.branch32(Assembler::Equal, value, Imm32(1), &Ldone);
   11255           0 :     masm.move32(Imm32(0), output);
   11256           0 :     masm.bind(&Ldone);
   11257           0 : }
   11258             : 
   11259             : void
   11260           0 : CodeGenerator::visitGuardSharedTypedArray(LGuardSharedTypedArray* guard)
   11261             : {
   11262           0 :     Register obj = ToRegister(guard->input());
   11263           0 :     Register tmp = ToRegister(guard->tempInt());
   11264             : 
   11265             :     // The shared-memory flag is a bit in the ObjectElements header
   11266             :     // that is set if the TypedArray is mapping a SharedArrayBuffer.
   11267             :     // The flag is set at construction and does not change subsequently.
   11268           0 :     masm.loadPtr(Address(obj, TypedArrayObject::offsetOfElements()), tmp);
   11269           0 :     masm.load32(Address(tmp, ObjectElements::offsetOfFlags()), tmp);
   11270           0 :     bailoutTest32(Assembler::Zero, tmp, Imm32(ObjectElements::SHARED_MEMORY), guard->snapshot());
   11271           0 : }
   11272             : 
   11273             : void
   11274           0 : CodeGenerator::visitClampIToUint8(LClampIToUint8* lir)
   11275             : {
   11276           0 :     Register output = ToRegister(lir->output());
   11277           0 :     MOZ_ASSERT(output == ToRegister(lir->input()));
   11278           0 :     masm.clampIntToUint8(output);
   11279           0 : }
   11280             : 
   11281             : void
   11282           0 : CodeGenerator::visitClampDToUint8(LClampDToUint8* lir)
   11283             : {
   11284           0 :     FloatRegister input = ToFloatRegister(lir->input());
   11285           0 :     Register output = ToRegister(lir->output());
   11286           0 :     masm.clampDoubleToUint8(input, output);
   11287           0 : }
   11288             : 
   11289             : void
   11290           0 : CodeGenerator::visitClampVToUint8(LClampVToUint8* lir)
   11291             : {
   11292           0 :     ValueOperand operand = ToValue(lir, LClampVToUint8::Input);
   11293           0 :     FloatRegister tempFloat = ToFloatRegister(lir->tempFloat());
   11294           0 :     Register output = ToRegister(lir->output());
   11295           0 :     MDefinition* input = lir->mir()->input();
   11296             : 
   11297             :     Label* stringEntry;
   11298             :     Label* stringRejoin;
   11299           0 :     if (input->mightBeType(MIRType::String)) {
   11300           0 :         OutOfLineCode* oolString = oolCallVM(StringToNumberInfo, lir, ArgList(output),
   11301           0 :                                              StoreFloatRegisterTo(tempFloat));
   11302           0 :         stringEntry = oolString->entry();
   11303           0 :         stringRejoin = oolString->rejoin();
   11304             :     } else {
   11305           0 :         stringEntry = nullptr;
   11306           0 :         stringRejoin = nullptr;
   11307             :     }
   11308             : 
   11309           0 :     Label fails;
   11310           0 :     masm.clampValueToUint8(operand, input,
   11311             :                            stringEntry, stringRejoin,
   11312           0 :                            output, tempFloat, output, &fails);
   11313             : 
   11314           0 :     bailoutFrom(&fails, lir->snapshot());
   11315           0 : }
   11316             : 
   11317             : void
   11318           2 : CodeGenerator::visitInCache(LInCache* ins)
   11319             : {
   11320           2 :     LiveRegisterSet liveRegs = ins->safepoint()->liveRegs();
   11321             : 
   11322           2 :     ConstantOrRegister key = toConstantOrRegister(ins, LInCache::LHS, ins->mir()->key()->type());
   11323           2 :     Register object = ToRegister(ins->rhs());
   11324           2 :     Register output = ToRegister(ins->output());
   11325           2 :     Register temp = ToRegister(ins->temp());
   11326             : 
   11327           2 :     IonInIC cache(liveRegs, key, object, output, temp);
   11328           2 :     addIC(ins, allocateIC(cache));
   11329           2 : }
   11330             : 
   11331             : typedef bool (*OperatorInIFn)(JSContext*, uint32_t, HandleObject, bool*);
   11332           3 : static const VMFunction OperatorInIInfo = FunctionInfo<OperatorInIFn>(OperatorInI, "OperatorInI");
   11333             : 
   11334             : void
   11335           0 : CodeGenerator::visitInArray(LInArray* lir)
   11336             : {
   11337           0 :     const MInArray* mir = lir->mir();
   11338           0 :     Register elements = ToRegister(lir->elements());
   11339           0 :     Register initLength = ToRegister(lir->initLength());
   11340           0 :     Register output = ToRegister(lir->output());
   11341             : 
   11342             :     // When the array is not packed we need to do a hole check in addition to the bounds check.
   11343           0 :     Label falseBranch, done, trueBranch;
   11344             : 
   11345           0 :     OutOfLineCode* ool = nullptr;
   11346           0 :     Label* failedInitLength = &falseBranch;
   11347             : 
   11348           0 :     if (lir->index()->isConstant()) {
   11349           0 :         int32_t index = ToInt32(lir->index());
   11350             : 
   11351           0 :         MOZ_ASSERT_IF(index < 0, mir->needsNegativeIntCheck());
   11352           0 :         if (mir->needsNegativeIntCheck()) {
   11353           0 :             ool = oolCallVM(OperatorInIInfo, lir,
   11354           0 :                             ArgList(Imm32(index), ToRegister(lir->object())),
   11355           0 :                             StoreRegisterTo(output));
   11356           0 :             failedInitLength = ool->entry();
   11357             :         }
   11358             : 
   11359           0 :         masm.branch32(Assembler::BelowOrEqual, initLength, Imm32(index), failedInitLength);
   11360           0 :         if (mir->needsHoleCheck() && mir->unboxedType() == JSVAL_TYPE_MAGIC) {
   11361           0 :             NativeObject::elementsSizeMustNotOverflow();
   11362           0 :             Address address = Address(elements, index * sizeof(Value));
   11363           0 :             masm.branchTestMagic(Assembler::Equal, address, &falseBranch);
   11364             :         }
   11365             :     } else {
   11366           0 :         Label negativeIntCheck;
   11367           0 :         Register index = ToRegister(lir->index());
   11368             : 
   11369           0 :         if (mir->needsNegativeIntCheck())
   11370           0 :             failedInitLength = &negativeIntCheck;
   11371             : 
   11372           0 :         masm.branch32(Assembler::BelowOrEqual, initLength, index, failedInitLength);
   11373           0 :         if (mir->needsHoleCheck() && mir->unboxedType() == JSVAL_TYPE_MAGIC) {
   11374           0 :             BaseIndex address = BaseIndex(elements, ToRegister(lir->index()), TimesEight);
   11375           0 :             masm.branchTestMagic(Assembler::Equal, address, &falseBranch);
   11376             :         }
   11377           0 :         masm.jump(&trueBranch);
   11378             : 
   11379           0 :         if (mir->needsNegativeIntCheck()) {
   11380           0 :             masm.bind(&negativeIntCheck);
   11381           0 :             ool = oolCallVM(OperatorInIInfo, lir,
   11382           0 :                             ArgList(index, ToRegister(lir->object())),
   11383           0 :                             StoreRegisterTo(output));
   11384             : 
   11385           0 :             masm.branch32(Assembler::LessThan, index, Imm32(0), ool->entry());
   11386           0 :             masm.jump(&falseBranch);
   11387             :         }
   11388             :     }
   11389             : 
   11390           0 :     masm.bind(&trueBranch);
   11391           0 :     masm.move32(Imm32(1), output);
   11392           0 :     masm.jump(&done);
   11393             : 
   11394           0 :     masm.bind(&falseBranch);
   11395           0 :     masm.move32(Imm32(0), output);
   11396           0 :     masm.bind(&done);
   11397             : 
   11398           0 :     if (ool)
   11399           0 :         masm.bind(ool->rejoin());
   11400           0 : }
   11401             : 
   11402             : void
   11403           0 : CodeGenerator::visitInstanceOfO(LInstanceOfO* ins)
   11404             : {
   11405           0 :     emitInstanceOf(ins, ins->mir()->prototypeObject());
   11406           0 : }
   11407             : 
   11408             : void
   11409           0 : CodeGenerator::visitInstanceOfV(LInstanceOfV* ins)
   11410             : {
   11411           0 :     emitInstanceOf(ins, ins->mir()->prototypeObject());
   11412           0 : }
   11413             : 
   11414             : // Wrap IsDelegateOfObject, which takes a JSObject*, not a HandleObject
   11415             : static bool
   11416           0 : IsDelegateObject(JSContext* cx, HandleObject protoObj, HandleObject obj, bool* res)
   11417             : {
   11418           0 :     return IsDelegateOfObject(cx, protoObj, obj, res);
   11419             : }
   11420             : 
   11421             : typedef bool (*IsDelegateObjectFn)(JSContext*, HandleObject, HandleObject, bool*);
   11422           3 : static const VMFunction IsDelegateObjectInfo =
   11423           6 :     FunctionInfo<IsDelegateObjectFn>(IsDelegateObject, "IsDelegateObject");
   11424             : 
   11425             : void
   11426           0 : CodeGenerator::emitInstanceOf(LInstruction* ins, JSObject* prototypeObject)
   11427             : {
   11428             :     // This path implements fun_hasInstance when the function's prototype is
   11429             :     // known to be prototypeObject.
   11430             : 
   11431           0 :     Label done;
   11432           0 :     Register output = ToRegister(ins->getDef(0));
   11433             : 
   11434             :     // If the lhs is a primitive, the result is false.
   11435           0 :     Register objReg;
   11436           0 :     if (ins->isInstanceOfV()) {
   11437           0 :         Label isObject;
   11438           0 :         ValueOperand lhsValue = ToValue(ins, LInstanceOfV::LHS);
   11439           0 :         masm.branchTestObject(Assembler::Equal, lhsValue, &isObject);
   11440           0 :         masm.mov(ImmWord(0), output);
   11441           0 :         masm.jump(&done);
   11442           0 :         masm.bind(&isObject);
   11443           0 :         objReg = masm.extractObject(lhsValue, output);
   11444             :     } else {
   11445           0 :         objReg = ToRegister(ins->toInstanceOfO()->lhs());
   11446             :     }
   11447             : 
   11448             :     // Crawl the lhs's prototype chain in a loop to search for prototypeObject.
   11449             :     // This follows the main loop of js::IsDelegate, though additionally breaks
   11450             :     // out of the loop on Proxy::LazyProto.
   11451             : 
   11452             :     // Load the lhs's prototype.
   11453           0 :     masm.loadObjProto(objReg, output);
   11454             : 
   11455           0 :     Label testLazy;
   11456             :     {
   11457           0 :         Label loopPrototypeChain;
   11458           0 :         masm.bind(&loopPrototypeChain);
   11459             : 
   11460             :         // Test for the target prototype object.
   11461           0 :         Label notPrototypeObject;
   11462           0 :         masm.branchPtr(Assembler::NotEqual, output, ImmGCPtr(prototypeObject), &notPrototypeObject);
   11463           0 :         masm.mov(ImmWord(1), output);
   11464           0 :         masm.jump(&done);
   11465           0 :         masm.bind(&notPrototypeObject);
   11466             : 
   11467           0 :         MOZ_ASSERT(uintptr_t(TaggedProto::LazyProto) == 1);
   11468             : 
   11469             :         // Test for nullptr or Proxy::LazyProto
   11470           0 :         masm.branchPtr(Assembler::BelowOrEqual, output, ImmWord(1), &testLazy);
   11471             : 
   11472             :         // Load the current object's prototype.
   11473           0 :         masm.loadObjProto(output, output);
   11474             : 
   11475           0 :         masm.jump(&loopPrototypeChain);
   11476             :     }
   11477             : 
   11478             :     // Make a VM call if an object with a lazy proto was found on the prototype
   11479             :     // chain. This currently occurs only for cross compartment wrappers, which
   11480             :     // we do not expect to be compared with non-wrapper functions from this
   11481             :     // compartment. Otherwise, we stopped on a nullptr prototype and the output
   11482             :     // register is already correct.
   11483             : 
   11484           0 :     OutOfLineCode* ool = oolCallVM(IsDelegateObjectInfo, ins,
   11485           0 :                                    ArgList(ImmGCPtr(prototypeObject), objReg),
   11486           0 :                                    StoreRegisterTo(output));
   11487             : 
   11488             :     // Regenerate the original lhs object for the VM call.
   11489           0 :     Label regenerate, *lazyEntry;
   11490           0 :     if (objReg != output) {
   11491           0 :         lazyEntry = ool->entry();
   11492             :     } else {
   11493           0 :         masm.bind(&regenerate);
   11494           0 :         lazyEntry = &regenerate;
   11495           0 :         if (ins->isInstanceOfV()) {
   11496           0 :             ValueOperand lhsValue = ToValue(ins, LInstanceOfV::LHS);
   11497           0 :             objReg = masm.extractObject(lhsValue, output);
   11498             :         } else {
   11499           0 :             objReg = ToRegister(ins->toInstanceOfO()->lhs());
   11500             :         }
   11501           0 :         MOZ_ASSERT(objReg == output);
   11502           0 :         masm.jump(ool->entry());
   11503             :     }
   11504             : 
   11505           0 :     masm.bind(&testLazy);
   11506           0 :     masm.branchPtr(Assembler::Equal, output, ImmWord(1), lazyEntry);
   11507             : 
   11508           0 :     masm.bind(&done);
   11509           0 :     masm.bind(ool->rejoin());
   11510           0 : }
   11511             : 
   11512             : typedef bool (*HasInstanceFn)(JSContext*, HandleObject, HandleValue, bool*);
   11513           3 : static const VMFunction HasInstanceInfo = FunctionInfo<HasInstanceFn>(js::HasInstance, "HasInstance");
   11514             : 
   11515             : void
   11516           0 : CodeGenerator::visitCallInstanceOf(LCallInstanceOf* ins)
   11517             : {
   11518           0 :     ValueOperand lhs = ToValue(ins, LCallInstanceOf::LHS);
   11519           0 :     Register rhs = ToRegister(ins->rhs());
   11520           0 :     MOZ_ASSERT(ToRegister(ins->output()) == ReturnReg);
   11521             : 
   11522           0 :     pushArg(lhs);
   11523           0 :     pushArg(rhs);
   11524           0 :     callVM(HasInstanceInfo, ins);
   11525           0 : }
   11526             : 
   11527             : void
   11528           0 : CodeGenerator::visitGetDOMProperty(LGetDOMProperty* ins)
   11529             : {
   11530           0 :     const Register JSContextReg = ToRegister(ins->getJSContextReg());
   11531           0 :     const Register ObjectReg = ToRegister(ins->getObjectReg());
   11532           0 :     const Register PrivateReg = ToRegister(ins->getPrivReg());
   11533           0 :     const Register ValueReg = ToRegister(ins->getValueReg());
   11534             : 
   11535           0 :     Label haveValue;
   11536           0 :     if (ins->mir()->valueMayBeInSlot()) {
   11537           0 :         size_t slot = ins->mir()->domMemberSlotIndex();
   11538             :         // It's a bit annoying to redo these slot calculations, which duplcate
   11539             :         // LSlots and a few other things like that, but I'm not sure there's a
   11540             :         // way to reuse those here.
   11541             :         //
   11542             :         // If this ever gets fixed to work with proxies (by not assuming that
   11543             :         // reserved slot indices, which is what domMemberSlotIndex() returns,
   11544             :         // match fixed slot indices), we can reenable MGetDOMProperty for
   11545             :         // proxies in IonBuilder.
   11546           0 :         if (slot < NativeObject::MAX_FIXED_SLOTS) {
   11547           0 :             masm.loadValue(Address(ObjectReg, NativeObject::getFixedSlotOffset(slot)),
   11548           0 :                            JSReturnOperand);
   11549             :         } else {
   11550             :             // It's a dynamic slot.
   11551           0 :             slot -= NativeObject::MAX_FIXED_SLOTS;
   11552             :             // Use PrivateReg as a scratch register for the slots pointer.
   11553           0 :             masm.loadPtr(Address(ObjectReg, NativeObject::offsetOfSlots()),
   11554           0 :                          PrivateReg);
   11555           0 :             masm.loadValue(Address(PrivateReg, slot*sizeof(js::Value)),
   11556           0 :                            JSReturnOperand);
   11557             :         }
   11558           0 :         masm.branchTestUndefined(Assembler::NotEqual, JSReturnOperand, &haveValue);
   11559             :     }
   11560             : 
   11561           0 :     DebugOnly<uint32_t> initialStack = masm.framePushed();
   11562             : 
   11563           0 :     masm.checkStackAlignment();
   11564             : 
   11565             :     // Make space for the outparam.  Pre-initialize it to UndefinedValue so we
   11566             :     // can trace it at GC time.
   11567           0 :     masm.Push(UndefinedValue());
   11568             :     // We pass the pointer to our out param as an instance of
   11569             :     // JSJitGetterCallArgs, since on the binary level it's the same thing.
   11570             :     JS_STATIC_ASSERT(sizeof(JSJitGetterCallArgs) == sizeof(Value*));
   11571           0 :     masm.moveStackPtrTo(ValueReg);
   11572             : 
   11573           0 :     masm.Push(ObjectReg);
   11574             : 
   11575           0 :     LoadDOMPrivate(masm, ObjectReg, PrivateReg);
   11576             : 
   11577             :     // Rooting will happen at GC time.
   11578           0 :     masm.moveStackPtrTo(ObjectReg);
   11579             : 
   11580           0 :     uint32_t safepointOffset = masm.buildFakeExitFrame(JSContextReg);
   11581           0 :     masm.loadJSContext(JSContextReg);
   11582           0 :     masm.enterFakeExitFrame(JSContextReg, JSContextReg, IonDOMExitFrameLayoutGetterToken);
   11583             : 
   11584           0 :     markSafepointAt(safepointOffset, ins);
   11585             : 
   11586           0 :     masm.setupUnalignedABICall(JSContextReg);
   11587           0 :     masm.loadJSContext(JSContextReg);
   11588           0 :     masm.passABIArg(JSContextReg);
   11589           0 :     masm.passABIArg(ObjectReg);
   11590           0 :     masm.passABIArg(PrivateReg);
   11591           0 :     masm.passABIArg(ValueReg);
   11592           0 :     masm.callWithABI(JS_FUNC_TO_DATA_PTR(void*, ins->mir()->fun()));
   11593             : 
   11594           0 :     if (ins->mir()->isInfallible()) {
   11595           0 :         masm.loadValue(Address(masm.getStackPointer(), IonDOMExitFrameLayout::offsetOfResult()),
   11596           0 :                        JSReturnOperand);
   11597             :     } else {
   11598           0 :         masm.branchIfFalseBool(ReturnReg, masm.exceptionLabel());
   11599             : 
   11600           0 :         masm.loadValue(Address(masm.getStackPointer(), IonDOMExitFrameLayout::offsetOfResult()),
   11601           0 :                        JSReturnOperand);
   11602             :     }
   11603           0 :     masm.adjustStack(IonDOMExitFrameLayout::Size());
   11604             : 
   11605           0 :     masm.bind(&haveValue);
   11606             : 
   11607           0 :     MOZ_ASSERT(masm.framePushed() == initialStack);
   11608           0 : }
   11609             : 
   11610             : void
   11611           0 : CodeGenerator::visitGetDOMMemberV(LGetDOMMemberV* ins)
   11612             : {
   11613             :     // It's simpler to duplicate visitLoadFixedSlotV here than it is to try to
   11614             :     // use an LLoadFixedSlotV or some subclass of it for this case: that would
   11615             :     // require us to have MGetDOMMember inherit from MLoadFixedSlot, and then
   11616             :     // we'd have to duplicate a bunch of stuff we now get for free from
   11617             :     // MGetDOMProperty.
   11618             :     //
   11619             :     // If this ever gets fixed to work with proxies (by not assuming that
   11620             :     // reserved slot indices, which is what domMemberSlotIndex() returns,
   11621             :     // match fixed slot indices), we can reenable MGetDOMMember for
   11622             :     // proxies in IonBuilder.
   11623           0 :     Register object = ToRegister(ins->object());
   11624           0 :     size_t slot = ins->mir()->domMemberSlotIndex();
   11625           0 :     ValueOperand result = GetValueOutput(ins);
   11626             : 
   11627           0 :     masm.loadValue(Address(object, NativeObject::getFixedSlotOffset(slot)), result);
   11628           0 : }
   11629             : 
   11630             : void
   11631           0 : CodeGenerator::visitGetDOMMemberT(LGetDOMMemberT* ins)
   11632             : {
   11633             :     // It's simpler to duplicate visitLoadFixedSlotT here than it is to try to
   11634             :     // use an LLoadFixedSlotT or some subclass of it for this case: that would
   11635             :     // require us to have MGetDOMMember inherit from MLoadFixedSlot, and then
   11636             :     // we'd have to duplicate a bunch of stuff we now get for free from
   11637             :     // MGetDOMProperty.
   11638             :     //
   11639             :     // If this ever gets fixed to work with proxies (by not assuming that
   11640             :     // reserved slot indices, which is what domMemberSlotIndex() returns,
   11641             :     // match fixed slot indices), we can reenable MGetDOMMember for
   11642             :     // proxies in IonBuilder.
   11643           0 :     Register object = ToRegister(ins->object());
   11644           0 :     size_t slot = ins->mir()->domMemberSlotIndex();
   11645           0 :     AnyRegister result = ToAnyRegister(ins->getDef(0));
   11646           0 :     MIRType type = ins->mir()->type();
   11647             : 
   11648           0 :     masm.loadUnboxedValue(Address(object, NativeObject::getFixedSlotOffset(slot)), type, result);
   11649           0 : }
   11650             : 
   11651             : void
   11652           0 : CodeGenerator::visitSetDOMProperty(LSetDOMProperty* ins)
   11653             : {
   11654           0 :     const Register JSContextReg = ToRegister(ins->getJSContextReg());
   11655           0 :     const Register ObjectReg = ToRegister(ins->getObjectReg());
   11656           0 :     const Register PrivateReg = ToRegister(ins->getPrivReg());
   11657           0 :     const Register ValueReg = ToRegister(ins->getValueReg());
   11658             : 
   11659           0 :     DebugOnly<uint32_t> initialStack = masm.framePushed();
   11660             : 
   11661           0 :     masm.checkStackAlignment();
   11662             : 
   11663             :     // Push the argument. Rooting will happen at GC time.
   11664           0 :     ValueOperand argVal = ToValue(ins, LSetDOMProperty::Value);
   11665           0 :     masm.Push(argVal);
   11666             :     // We pass the pointer to our out param as an instance of
   11667             :     // JSJitGetterCallArgs, since on the binary level it's the same thing.
   11668             :     JS_STATIC_ASSERT(sizeof(JSJitSetterCallArgs) == sizeof(Value*));
   11669           0 :     masm.moveStackPtrTo(ValueReg);
   11670             : 
   11671           0 :     masm.Push(ObjectReg);
   11672             : 
   11673           0 :     LoadDOMPrivate(masm, ObjectReg, PrivateReg);
   11674             : 
   11675             :     // Rooting will happen at GC time.
   11676           0 :     masm.moveStackPtrTo(ObjectReg);
   11677             : 
   11678           0 :     uint32_t safepointOffset = masm.buildFakeExitFrame(JSContextReg);
   11679           0 :     masm.loadJSContext(JSContextReg);
   11680           0 :     masm.enterFakeExitFrame(JSContextReg, JSContextReg, IonDOMExitFrameLayoutSetterToken);
   11681             : 
   11682           0 :     markSafepointAt(safepointOffset, ins);
   11683             : 
   11684           0 :     masm.setupUnalignedABICall(JSContextReg);
   11685           0 :     masm.loadJSContext(JSContextReg);
   11686           0 :     masm.passABIArg(JSContextReg);
   11687           0 :     masm.passABIArg(ObjectReg);
   11688           0 :     masm.passABIArg(PrivateReg);
   11689           0 :     masm.passABIArg(ValueReg);
   11690           0 :     masm.callWithABI(JS_FUNC_TO_DATA_PTR(void*, ins->mir()->fun()));
   11691             : 
   11692           0 :     masm.branchIfFalseBool(ReturnReg, masm.exceptionLabel());
   11693             : 
   11694           0 :     masm.adjustStack(IonDOMExitFrameLayout::Size());
   11695             : 
   11696           0 :     MOZ_ASSERT(masm.framePushed() == initialStack);
   11697           0 : }
   11698             : 
   11699             : class OutOfLineIsCallable : public OutOfLineCodeBase<CodeGenerator>
   11700             : {
   11701             :     LIsCallable* ins_;
   11702             : 
   11703             :   public:
   11704           0 :     explicit OutOfLineIsCallable(LIsCallable* ins)
   11705           0 :       : ins_(ins)
   11706           0 :     { }
   11707             : 
   11708           0 :     void accept(CodeGenerator* codegen) {
   11709           0 :         codegen->visitOutOfLineIsCallable(this);
   11710           0 :     }
   11711           0 :     LIsCallable* ins() const {
   11712           0 :         return ins_;
   11713             :     }
   11714             : };
   11715             : 
   11716             : template <CodeGenerator::CallableOrConstructor mode>
   11717             : void
   11718           0 : CodeGenerator::emitIsCallableOrConstructor(Register object, Register output, Label* failure)
   11719             : {
   11720           0 :     Label notFunction, hasCOps, done;
   11721           0 :     masm.loadObjClass(object, output);
   11722             : 
   11723             :     // Just skim proxies off. Their notion of isCallable()/isConstructor() is
   11724             :     // more complicated.
   11725           0 :     masm.branchTestClassIsProxy(true, output, failure);
   11726             : 
   11727             :     // An object is callable iff:
   11728             :     //   is<JSFunction>() || (getClass()->cOps && getClass()->cOps->call).
   11729             :     // An object is constructor iff:
   11730             :     //  ((is<JSFunction>() && as<JSFunction>().isConstructor) ||
   11731             :     //   (getClass()->cOps && getClass()->cOps->construct)).
   11732           0 :     masm.branchPtr(Assembler::NotEqual, output, ImmPtr(&JSFunction::class_), &notFunction);
   11733             :     if (mode == Callable) {
   11734           0 :         masm.move32(Imm32(1), output);
   11735             :     } else {
   11736           0 :         Label notConstructor;
   11737           0 :         masm.load16ZeroExtend(Address(object, JSFunction::offsetOfFlags()), output);
   11738           0 :         masm.and32(Imm32(JSFunction::CONSTRUCTOR), output);
   11739           0 :         masm.branchTest32(Assembler::Zero, output, output, &notConstructor);
   11740           0 :         masm.move32(Imm32(1), output);
   11741           0 :         masm.jump(&done);
   11742           0 :         masm.bind(&notConstructor);
   11743           0 :         masm.move32(Imm32(0), output);
   11744             :     }
   11745           0 :     masm.jump(&done);
   11746             : 
   11747           0 :     masm.bind(&notFunction);
   11748           0 :     masm.branchPtr(Assembler::NonZero, Address(output, offsetof(js::Class, cOps)),
   11749             :                    ImmPtr(nullptr), &hasCOps);
   11750           0 :     masm.move32(Imm32(0), output);
   11751           0 :     masm.jump(&done);
   11752             : 
   11753           0 :     masm.bind(&hasCOps);
   11754           0 :     masm.loadPtr(Address(output, offsetof(js::Class, cOps)), output);
   11755             :     size_t opsOffset = mode == Callable
   11756             :                        ? offsetof(js::ClassOps, call)
   11757           0 :                        : offsetof(js::ClassOps, construct);
   11758           0 :     masm.cmpPtrSet(Assembler::NonZero, Address(output, opsOffset),
   11759             :                    ImmPtr(nullptr), output);
   11760             : 
   11761           0 :     masm.bind(&done);
   11762           0 : }
   11763             : 
   11764             : void
   11765           0 : CodeGenerator::visitIsCallable(LIsCallable* ins)
   11766             : {
   11767           0 :     Register object = ToRegister(ins->object());
   11768           0 :     Register output = ToRegister(ins->output());
   11769             : 
   11770           0 :     OutOfLineIsCallable* ool = new(alloc()) OutOfLineIsCallable(ins);
   11771           0 :     addOutOfLineCode(ool, ins->mir());
   11772             : 
   11773           0 :     emitIsCallableOrConstructor<Callable>(object, output, ool->entry());
   11774             : 
   11775           0 :     masm.bind(ool->rejoin());
   11776           0 : }
   11777             : 
   11778             : void
   11779           0 : CodeGenerator::visitOutOfLineIsCallable(OutOfLineIsCallable* ool)
   11780             : {
   11781           0 :     LIsCallable* ins = ool->ins();
   11782           0 :     Register object = ToRegister(ins->object());
   11783           0 :     Register output = ToRegister(ins->output());
   11784             : 
   11785           0 :     saveVolatile(output);
   11786           0 :     masm.setupUnalignedABICall(output);
   11787           0 :     masm.passABIArg(object);
   11788           0 :     masm.callWithABI(JS_FUNC_TO_DATA_PTR(void*, ObjectIsCallable));
   11789           0 :     masm.storeCallBoolResult(output);
   11790           0 :     restoreVolatile(output);
   11791           0 :     masm.jump(ool->rejoin());
   11792           0 : }
   11793             : 
   11794             : typedef bool (*CheckIsCallableFn)(JSContext*, HandleValue, CheckIsCallableKind);
   11795           3 : static const VMFunction CheckIsCallableInfo =
   11796           6 :     FunctionInfo<CheckIsCallableFn>(CheckIsCallable, "CheckIsCallable");
   11797             : 
   11798             : void
   11799           0 : CodeGenerator::visitCheckIsCallable(LCheckIsCallable* ins)
   11800             : {
   11801           0 :     ValueOperand checkValue = ToValue(ins, LCheckIsCallable::CheckValue);
   11802           0 :     Register temp = ToRegister(ins->temp());
   11803             : 
   11804             :     // OOL code is used in the following 2 cases:
   11805             :     //   * checkValue is not callable
   11806             :     //   * checkValue is proxy and it's unknown whether it's callable or not
   11807             :     // CheckIsCallable checks if passed value is callable, regardless of the
   11808             :     // cases above.  IsCallable operation is not observable and checking it
   11809             :     // again doesn't matter.
   11810           0 :     OutOfLineCode* ool = oolCallVM(CheckIsCallableInfo, ins,
   11811           0 :                                    ArgList(checkValue, Imm32(ins->mir()->checkKind())),
   11812           0 :                                    StoreNothing());
   11813             : 
   11814           0 :     masm.branchTestObject(Assembler::NotEqual, checkValue, ool->entry());
   11815             : 
   11816           0 :     Register object = masm.extractObject(checkValue, temp);
   11817           0 :     emitIsCallableOrConstructor<Callable>(object, temp, ool->entry());
   11818             : 
   11819           0 :     masm.branchTest32(Assembler::Zero, temp, temp, ool->entry());
   11820             : 
   11821           0 :     masm.bind(ool->rejoin());
   11822           0 : }
   11823             : 
   11824             : class OutOfLineIsConstructor : public OutOfLineCodeBase<CodeGenerator>
   11825             : {
   11826             :     LIsConstructor* ins_;
   11827             : 
   11828             :   public:
   11829           0 :     explicit OutOfLineIsConstructor(LIsConstructor* ins)
   11830           0 :       : ins_(ins)
   11831           0 :     { }
   11832             : 
   11833           0 :     void accept(CodeGenerator* codegen) {
   11834           0 :         codegen->visitOutOfLineIsConstructor(this);
   11835           0 :     }
   11836           0 :     LIsConstructor* ins() const {
   11837           0 :         return ins_;
   11838             :     }
   11839             : };
   11840             : 
   11841             : void
   11842           0 : CodeGenerator::visitIsConstructor(LIsConstructor* ins)
   11843             : {
   11844           0 :     Register object = ToRegister(ins->object());
   11845           0 :     Register output = ToRegister(ins->output());
   11846             : 
   11847           0 :     OutOfLineIsConstructor* ool = new(alloc()) OutOfLineIsConstructor(ins);
   11848           0 :     addOutOfLineCode(ool, ins->mir());
   11849             : 
   11850           0 :     emitIsCallableOrConstructor<Constructor>(object, output, ool->entry());
   11851             : 
   11852           0 :     masm.bind(ool->rejoin());
   11853           0 : }
   11854             : 
   11855             : void
   11856           0 : CodeGenerator::visitOutOfLineIsConstructor(OutOfLineIsConstructor* ool)
   11857             : {
   11858           0 :     LIsConstructor* ins = ool->ins();
   11859           0 :     Register object = ToRegister(ins->object());
   11860           0 :     Register output = ToRegister(ins->output());
   11861             : 
   11862           0 :     saveVolatile(output);
   11863           0 :     masm.setupUnalignedABICall(output);
   11864           0 :     masm.passABIArg(object);
   11865           0 :     masm.callWithABI(JS_FUNC_TO_DATA_PTR(void*, ObjectIsConstructor));
   11866           0 :     masm.storeCallBoolResult(output);
   11867           0 :     restoreVolatile(output);
   11868           0 :     masm.jump(ool->rejoin());
   11869           0 : }
   11870             : 
   11871             : typedef bool (*IsArrayFn)(JSContext*, HandleObject, bool*);
   11872           3 : static const VMFunction IsArrayInfo = FunctionInfo<IsArrayFn>(JS::IsArray, "IsArray");
   11873             : 
   11874             : static void
   11875           0 : EmitObjectIsArray(MacroAssembler& masm, OutOfLineCode* ool, Register obj, Register output,
   11876             :                   Label* notArray = nullptr)
   11877             : {
   11878           0 :     masm.loadObjClass(obj, output);
   11879             : 
   11880           0 :     Label isArray;
   11881           0 :     masm.branchPtr(Assembler::Equal, output, ImmPtr(&ArrayObject::class_), &isArray);
   11882           0 :     masm.branchPtr(Assembler::Equal, output, ImmPtr(&UnboxedArrayObject::class_), &isArray);
   11883             : 
   11884             :     // Branch to OOL path if it's a proxy.
   11885           0 :     masm.branchTestClassIsProxy(true, output, ool->entry());
   11886             : 
   11887           0 :     if (notArray)
   11888           0 :         masm.bind(notArray);
   11889           0 :     masm.move32(Imm32(0), output);
   11890           0 :     masm.jump(ool->rejoin());
   11891             : 
   11892           0 :     masm.bind(&isArray);
   11893           0 :     masm.move32(Imm32(1), output);
   11894             : 
   11895           0 :     masm.bind(ool->rejoin());
   11896           0 : }
   11897             : 
   11898             : void
   11899           0 : CodeGenerator::visitIsArrayO(LIsArrayO* lir)
   11900             : {
   11901           0 :     Register object = ToRegister(lir->object());
   11902           0 :     Register output = ToRegister(lir->output());
   11903             : 
   11904           0 :     OutOfLineCode* ool = oolCallVM(IsArrayInfo, lir, ArgList(object),
   11905           0 :                                    StoreRegisterTo(output));
   11906           0 :     EmitObjectIsArray(masm, ool, object, output);
   11907           0 : }
   11908             : 
   11909             : void
   11910           0 : CodeGenerator::visitIsArrayV(LIsArrayV* lir)
   11911             : {
   11912           0 :     ValueOperand val = ToValue(lir, LIsArrayV::Value);
   11913           0 :     Register output = ToRegister(lir->output());
   11914           0 :     Register temp = ToRegister(lir->temp());
   11915             : 
   11916           0 :     Label notArray;
   11917           0 :     masm.branchTestObject(Assembler::NotEqual, val, &notArray);
   11918           0 :     masm.unboxObject(val, temp);
   11919             : 
   11920           0 :     OutOfLineCode* ool = oolCallVM(IsArrayInfo, lir, ArgList(temp),
   11921           0 :                                    StoreRegisterTo(output));
   11922           0 :     EmitObjectIsArray(masm, ool, temp, output, &notArray);
   11923           0 : }
   11924             : 
   11925             : void
   11926           0 : CodeGenerator::visitIsObject(LIsObject* ins)
   11927             : {
   11928           0 :     Register output = ToRegister(ins->output());
   11929           0 :     ValueOperand value = ToValue(ins, LIsObject::Input);
   11930           0 :     masm.testObjectSet(Assembler::Equal, value, output);
   11931           0 : }
   11932             : 
   11933             : void
   11934           0 : CodeGenerator::visitIsObjectAndBranch(LIsObjectAndBranch* ins)
   11935             : {
   11936           0 :     ValueOperand value = ToValue(ins, LIsObjectAndBranch::Input);
   11937           0 :     testObjectEmitBranch(Assembler::Equal, value, ins->ifTrue(), ins->ifFalse());
   11938           0 : }
   11939             : 
   11940             : void
   11941           0 : CodeGenerator::loadOutermostJSScript(Register reg)
   11942             : {
   11943             :     // The "outermost" JSScript means the script that we are compiling
   11944             :     // basically; this is not always the script associated with the
   11945             :     // current basic block, which might be an inlined script.
   11946             : 
   11947           0 :     MIRGraph& graph = current->mir()->graph();
   11948           0 :     MBasicBlock* entryBlock = graph.entryBlock();
   11949           0 :     masm.movePtr(ImmGCPtr(entryBlock->info().script()), reg);
   11950           0 : }
   11951             : 
   11952             : void
   11953           0 : CodeGenerator::loadJSScriptForBlock(MBasicBlock* block, Register reg)
   11954             : {
   11955             :     // The current JSScript means the script for the current
   11956             :     // basic block. This may be an inlined script.
   11957             : 
   11958           0 :     JSScript* script = block->info().script();
   11959           0 :     masm.movePtr(ImmGCPtr(script), reg);
   11960           0 : }
   11961             : 
   11962             : void
   11963           0 : CodeGenerator::visitHasClass(LHasClass* ins)
   11964             : {
   11965           0 :     Register lhs = ToRegister(ins->lhs());
   11966           0 :     Register output = ToRegister(ins->output());
   11967             : 
   11968           0 :     masm.loadObjClass(lhs, output);
   11969           0 :     masm.cmpPtrSet(Assembler::Equal, output, ImmPtr(ins->mir()->getClass()), output);
   11970           0 : }
   11971             : 
   11972             : void
   11973           0 : CodeGenerator::visitWasmParameter(LWasmParameter* lir)
   11974             : {
   11975           0 : }
   11976             : 
   11977             : void
   11978           0 : CodeGenerator::visitWasmParameterI64(LWasmParameterI64* lir)
   11979             : {
   11980           0 : }
   11981             : 
   11982             : void
   11983           0 : CodeGenerator::visitWasmReturn(LWasmReturn* lir)
   11984             : {
   11985             :     // Don't emit a jump to the return label if this is the last block.
   11986           0 :     if (current->mir() != *gen->graph().poBegin())
   11987           0 :         masm.jump(&returnLabel_);
   11988           0 : }
   11989             : 
   11990             : void
   11991           0 : CodeGenerator::visitWasmReturnI64(LWasmReturnI64* lir)
   11992             : {
   11993             :     // Don't emit a jump to the return label if this is the last block.
   11994           0 :     if (current->mir() != *gen->graph().poBegin())
   11995           0 :         masm.jump(&returnLabel_);
   11996           0 : }
   11997             : 
   11998             : void
   11999           0 : CodeGenerator::visitWasmReturnVoid(LWasmReturnVoid* lir)
   12000             : {
   12001             :     // Don't emit a jump to the return label if this is the last block.
   12002           0 :     if (current->mir() != *gen->graph().poBegin())
   12003           0 :         masm.jump(&returnLabel_);
   12004           0 : }
   12005             : 
   12006             : void
   12007           0 : CodeGenerator::emitAssertRangeI(const Range* r, Register input)
   12008             : {
   12009             :     // Check the lower bound.
   12010           0 :     if (r->hasInt32LowerBound() && r->lower() > INT32_MIN) {
   12011           0 :         Label success;
   12012           0 :         masm.branch32(Assembler::GreaterThanOrEqual, input, Imm32(r->lower()), &success);
   12013           0 :         masm.assumeUnreachable("Integer input should be equal or higher than Lowerbound.");
   12014           0 :         masm.bind(&success);
   12015             :     }
   12016             : 
   12017             :     // Check the upper bound.
   12018           0 :     if (r->hasInt32UpperBound() && r->upper() < INT32_MAX) {
   12019           0 :         Label success;
   12020           0 :         masm.branch32(Assembler::LessThanOrEqual, input, Imm32(r->upper()), &success);
   12021           0 :         masm.assumeUnreachable("Integer input should be lower or equal than Upperbound.");
   12022           0 :         masm.bind(&success);
   12023             :     }
   12024             : 
   12025             :     // For r->canHaveFractionalPart(), r->canBeNegativeZero(), and
   12026             :     // r->exponent(), there's nothing to check, because if we ended up in the
   12027             :     // integer range checking code, the value is already in an integer register
   12028             :     // in the integer range.
   12029           0 : }
   12030             : 
   12031             : void
   12032           0 : CodeGenerator::emitAssertRangeD(const Range* r, FloatRegister input, FloatRegister temp)
   12033             : {
   12034             :     // Check the lower bound.
   12035           0 :     if (r->hasInt32LowerBound()) {
   12036           0 :         Label success;
   12037           0 :         masm.loadConstantDouble(r->lower(), temp);
   12038           0 :         if (r->canBeNaN())
   12039           0 :             masm.branchDouble(Assembler::DoubleUnordered, input, input, &success);
   12040           0 :         masm.branchDouble(Assembler::DoubleGreaterThanOrEqual, input, temp, &success);
   12041           0 :         masm.assumeUnreachable("Double input should be equal or higher than Lowerbound.");
   12042           0 :         masm.bind(&success);
   12043             :     }
   12044             :     // Check the upper bound.
   12045           0 :     if (r->hasInt32UpperBound()) {
   12046           0 :         Label success;
   12047           0 :         masm.loadConstantDouble(r->upper(), temp);
   12048           0 :         if (r->canBeNaN())
   12049           0 :             masm.branchDouble(Assembler::DoubleUnordered, input, input, &success);
   12050           0 :         masm.branchDouble(Assembler::DoubleLessThanOrEqual, input, temp, &success);
   12051           0 :         masm.assumeUnreachable("Double input should be lower or equal than Upperbound.");
   12052           0 :         masm.bind(&success);
   12053             :     }
   12054             : 
   12055             :     // This code does not yet check r->canHaveFractionalPart(). This would require new
   12056             :     // assembler interfaces to make rounding instructions available.
   12057             : 
   12058           0 :     if (!r->canBeNegativeZero()) {
   12059           0 :         Label success;
   12060             : 
   12061             :         // First, test for being equal to 0.0, which also includes -0.0.
   12062           0 :         masm.loadConstantDouble(0.0, temp);
   12063           0 :         masm.branchDouble(Assembler::DoubleNotEqualOrUnordered, input, temp, &success);
   12064             : 
   12065             :         // The easiest way to distinguish -0.0 from 0.0 is that 1.0/-0.0 is
   12066             :         // -Infinity instead of Infinity.
   12067           0 :         masm.loadConstantDouble(1.0, temp);
   12068           0 :         masm.divDouble(input, temp);
   12069           0 :         masm.branchDouble(Assembler::DoubleGreaterThan, temp, input, &success);
   12070             : 
   12071           0 :         masm.assumeUnreachable("Input shouldn't be negative zero.");
   12072             : 
   12073           0 :         masm.bind(&success);
   12074             :     }
   12075             : 
   12076           0 :     if (!r->hasInt32Bounds() && !r->canBeInfiniteOrNaN() &&
   12077           0 :         r->exponent() < FloatingPoint<double>::kExponentBias)
   12078             :     {
   12079             :         // Check the bounds implied by the maximum exponent.
   12080           0 :         Label exponentLoOk;
   12081           0 :         masm.loadConstantDouble(pow(2.0, r->exponent() + 1), temp);
   12082           0 :         masm.branchDouble(Assembler::DoubleUnordered, input, input, &exponentLoOk);
   12083           0 :         masm.branchDouble(Assembler::DoubleLessThanOrEqual, input, temp, &exponentLoOk);
   12084           0 :         masm.assumeUnreachable("Check for exponent failed.");
   12085           0 :         masm.bind(&exponentLoOk);
   12086             : 
   12087           0 :         Label exponentHiOk;
   12088           0 :         masm.loadConstantDouble(-pow(2.0, r->exponent() + 1), temp);
   12089           0 :         masm.branchDouble(Assembler::DoubleUnordered, input, input, &exponentHiOk);
   12090           0 :         masm.branchDouble(Assembler::DoubleGreaterThanOrEqual, input, temp, &exponentHiOk);
   12091           0 :         masm.assumeUnreachable("Check for exponent failed.");
   12092           0 :         masm.bind(&exponentHiOk);
   12093           0 :     } else if (!r->hasInt32Bounds() && !r->canBeNaN()) {
   12094             :         // If we think the value can't be NaN, check that it isn't.
   12095           0 :         Label notnan;
   12096           0 :         masm.branchDouble(Assembler::DoubleOrdered, input, input, &notnan);
   12097           0 :         masm.assumeUnreachable("Input shouldn't be NaN.");
   12098           0 :         masm.bind(&notnan);
   12099             : 
   12100             :         // If we think the value also can't be an infinity, check that it isn't.
   12101           0 :         if (!r->canBeInfiniteOrNaN()) {
   12102           0 :             Label notposinf;
   12103           0 :             masm.loadConstantDouble(PositiveInfinity<double>(), temp);
   12104           0 :             masm.branchDouble(Assembler::DoubleLessThan, input, temp, &notposinf);
   12105           0 :             masm.assumeUnreachable("Input shouldn't be +Inf.");
   12106           0 :             masm.bind(&notposinf);
   12107             : 
   12108           0 :             Label notneginf;
   12109           0 :             masm.loadConstantDouble(NegativeInfinity<double>(), temp);
   12110           0 :             masm.branchDouble(Assembler::DoubleGreaterThan, input, temp, &notneginf);
   12111           0 :             masm.assumeUnreachable("Input shouldn't be -Inf.");
   12112           0 :             masm.bind(&notneginf);
   12113             :         }
   12114             :     }
   12115           0 : }
   12116             : 
   12117             : void
   12118           0 : CodeGenerator::visitAssertResultV(LAssertResultV* ins)
   12119             : {
   12120           0 :     const ValueOperand value = ToValue(ins, LAssertResultV::Input);
   12121           0 :     emitAssertResultV(value, ins->mirRaw()->resultTypeSet());
   12122           0 : }
   12123             : 
   12124             : void
   12125           0 : CodeGenerator::visitAssertResultT(LAssertResultT* ins)
   12126             : {
   12127           0 :     Register input = ToRegister(ins->input());
   12128           0 :     MDefinition* mir = ins->mirRaw();
   12129             : 
   12130           0 :     emitAssertObjectOrStringResult(input, mir->type(), mir->resultTypeSet());
   12131           0 : }
   12132             : 
   12133             : void
   12134           0 : CodeGenerator::visitAssertRangeI(LAssertRangeI* ins)
   12135             : {
   12136           0 :     Register input = ToRegister(ins->input());
   12137           0 :     const Range* r = ins->range();
   12138             : 
   12139           0 :     emitAssertRangeI(r, input);
   12140           0 : }
   12141             : 
   12142             : void
   12143           0 : CodeGenerator::visitAssertRangeD(LAssertRangeD* ins)
   12144             : {
   12145           0 :     FloatRegister input = ToFloatRegister(ins->input());
   12146           0 :     FloatRegister temp = ToFloatRegister(ins->temp());
   12147           0 :     const Range* r = ins->range();
   12148             : 
   12149           0 :     emitAssertRangeD(r, input, temp);
   12150           0 : }
   12151             : 
   12152             : void
   12153           0 : CodeGenerator::visitAssertRangeF(LAssertRangeF* ins)
   12154             : {
   12155           0 :     FloatRegister input = ToFloatRegister(ins->input());
   12156           0 :     FloatRegister temp = ToFloatRegister(ins->temp());
   12157           0 :     FloatRegister temp2 = ToFloatRegister(ins->temp2());
   12158             : 
   12159           0 :     const Range* r = ins->range();
   12160             : 
   12161           0 :     masm.convertFloat32ToDouble(input, temp);
   12162           0 :     emitAssertRangeD(r, temp, temp2);
   12163           0 : }
   12164             : 
   12165             : void
   12166           0 : CodeGenerator::visitAssertRangeV(LAssertRangeV* ins)
   12167             : {
   12168           0 :     const Range* r = ins->range();
   12169           0 :     const ValueOperand value = ToValue(ins, LAssertRangeV::Input);
   12170           0 :     Register tag = masm.splitTagForTest(value);
   12171           0 :     Label done;
   12172             : 
   12173             :     {
   12174           0 :         Label isNotInt32;
   12175           0 :         masm.branchTestInt32(Assembler::NotEqual, tag, &isNotInt32);
   12176           0 :         Register unboxInt32 = ToTempUnboxRegister(ins->temp());
   12177           0 :         Register input = masm.extractInt32(value, unboxInt32);
   12178           0 :         emitAssertRangeI(r, input);
   12179           0 :         masm.jump(&done);
   12180           0 :         masm.bind(&isNotInt32);
   12181             :     }
   12182             : 
   12183             :     {
   12184           0 :         Label isNotDouble;
   12185           0 :         masm.branchTestDouble(Assembler::NotEqual, tag, &isNotDouble);
   12186           0 :         FloatRegister input = ToFloatRegister(ins->floatTemp1());
   12187           0 :         FloatRegister temp = ToFloatRegister(ins->floatTemp2());
   12188           0 :         masm.unboxDouble(value, input);
   12189           0 :         emitAssertRangeD(r, input, temp);
   12190           0 :         masm.jump(&done);
   12191           0 :         masm.bind(&isNotDouble);
   12192             :     }
   12193             : 
   12194           0 :     masm.assumeUnreachable("Incorrect range for Value.");
   12195           0 :     masm.bind(&done);
   12196           0 : }
   12197             : 
   12198             : void
   12199           5 : CodeGenerator::visitInterruptCheck(LInterruptCheck* lir)
   12200             : {
   12201           5 :     if (lir->implicit()) {
   12202           0 :         OutOfLineInterruptCheckImplicit* ool = new(alloc()) OutOfLineInterruptCheckImplicit(current, lir);
   12203           0 :         addOutOfLineCode(ool, lir->mir());
   12204             : 
   12205           0 :         lir->setOolEntry(ool->entry());
   12206           0 :         masm.bind(ool->rejoin());
   12207           0 :         return;
   12208             :     }
   12209             : 
   12210           5 :     OutOfLineCode* ool = oolCallVM(InterruptCheckInfo, lir, ArgList(), StoreNothing());
   12211             : 
   12212           5 :     Register temp = ToRegister(lir->temp());
   12213             : 
   12214           5 :     const void* contextAddr = GetJitContext()->compartment->zone()->addressOfJSContext();
   12215           5 :     masm.loadPtr(AbsoluteAddress(contextAddr), temp);
   12216          10 :     masm.branch32(Assembler::NotEqual, Address(temp, offsetof(JSContext, interrupt_)),
   12217           5 :                   Imm32(0), ool->entry());
   12218           5 :     masm.bind(ool->rejoin());
   12219             : }
   12220             : 
   12221             : void
   12222           0 : CodeGenerator::visitWasmTrap(LWasmTrap* lir)
   12223             : {
   12224           0 :     MOZ_ASSERT(gen->compilingWasm());
   12225           0 :     const MWasmTrap* mir = lir->mir();
   12226             : 
   12227           0 :     masm.jump(trap(mir, mir->trap()));
   12228           0 : }
   12229             : 
   12230             : void
   12231           0 : CodeGenerator::visitWasmBoundsCheck(LWasmBoundsCheck* ins)
   12232             : {
   12233             : #ifdef WASM_HUGE_MEMORY
   12234           0 :     MOZ_CRASH("No wasm bounds check for huge memory");
   12235             : #else
   12236             :     const MWasmBoundsCheck* mir = ins->mir();
   12237             :     Register ptr = ToRegister(ins->ptr());
   12238             :     Register boundsCheckLimit = ToRegister(ins->boundsCheckLimit());
   12239             :     masm.wasmBoundsCheck(Assembler::AboveOrEqual, ptr, boundsCheckLimit,
   12240             :                          trap(mir, wasm::Trap::OutOfBounds));
   12241             : #endif
   12242             : }
   12243             : 
   12244             : void
   12245           0 : CodeGenerator::visitWasmLoadTls(LWasmLoadTls* ins)
   12246             : {
   12247           0 :     switch (ins->mir()->type()) {
   12248             :       case MIRType::Pointer:
   12249           0 :         masm.loadPtr(Address(ToRegister(ins->tlsPtr()), ins->mir()->offset()),
   12250           0 :                      ToRegister(ins->output()));
   12251           0 :         break;
   12252             :       case MIRType::Int32:
   12253           0 :         masm.load32(Address(ToRegister(ins->tlsPtr()), ins->mir()->offset()),
   12254           0 :                     ToRegister(ins->output()));
   12255           0 :         break;
   12256             :       default:
   12257           0 :         MOZ_CRASH("MIRType not supported in WasmLoadTls");
   12258             :     }
   12259           0 : }
   12260             : 
   12261             : typedef bool (*RecompileFn)(JSContext*);
   12262           3 : static const VMFunction RecompileFnInfo = FunctionInfo<RecompileFn>(Recompile, "Recompile");
   12263             : 
   12264             : typedef bool (*ForcedRecompileFn)(JSContext*);
   12265           3 : static const VMFunction ForcedRecompileFnInfo =
   12266           6 :     FunctionInfo<ForcedRecompileFn>(ForcedRecompile, "ForcedRecompile");
   12267             : 
   12268             : void
   12269           6 : CodeGenerator::visitRecompileCheck(LRecompileCheck* ins)
   12270             : {
   12271          12 :     Label done;
   12272           6 :     Register tmp = ToRegister(ins->scratch());
   12273             :     OutOfLineCode* ool;
   12274           6 :     if (ins->mir()->forceRecompilation())
   12275           6 :         ool = oolCallVM(ForcedRecompileFnInfo, ins, ArgList(), StoreRegisterTo(tmp));
   12276             :     else
   12277           0 :         ool = oolCallVM(RecompileFnInfo, ins, ArgList(), StoreRegisterTo(tmp));
   12278             : 
   12279             :     // Check if warm-up counter is high enough.
   12280           6 :     AbsoluteAddress warmUpCount = AbsoluteAddress(ins->mir()->script()->addressOfWarmUpCounter());
   12281           6 :     if (ins->mir()->increaseWarmUpCounter()) {
   12282           0 :         masm.load32(warmUpCount, tmp);
   12283           0 :         masm.add32(Imm32(1), tmp);
   12284           0 :         masm.store32(tmp, warmUpCount);
   12285           0 :         masm.branch32(Assembler::BelowOrEqual, tmp, Imm32(ins->mir()->recompileThreshold()), &done);
   12286             :     } else {
   12287          12 :         masm.branch32(Assembler::BelowOrEqual, warmUpCount, Imm32(ins->mir()->recompileThreshold()),
   12288           6 :                       &done);
   12289             :     }
   12290             : 
   12291             :     // Check if not yet recompiling.
   12292           6 :     CodeOffset label = masm.movWithPatch(ImmWord(uintptr_t(-1)), tmp);
   12293           6 :     masm.propagateOOM(ionScriptLabels_.append(label));
   12294          18 :     masm.branch32(Assembler::Equal,
   12295          12 :                   Address(tmp, IonScript::offsetOfRecompiling()),
   12296             :                   Imm32(0),
   12297           6 :                   ool->entry());
   12298           6 :     masm.bind(ool->rejoin());
   12299           6 :     masm.bind(&done);
   12300           6 : }
   12301             : 
   12302             : void
   12303           0 : CodeGenerator::visitLexicalCheck(LLexicalCheck* ins)
   12304             : {
   12305           0 :     ValueOperand inputValue = ToValue(ins, LLexicalCheck::Input);
   12306           0 :     Label bail;
   12307           0 :     masm.branchTestMagicValue(Assembler::Equal, inputValue, JS_UNINITIALIZED_LEXICAL, &bail);
   12308           0 :     bailoutFrom(&bail, ins->snapshot());
   12309           0 : }
   12310             : 
   12311             : typedef bool (*ThrowRuntimeLexicalErrorFn)(JSContext*, unsigned);
   12312           3 : static const VMFunction ThrowRuntimeLexicalErrorInfo =
   12313           6 :     FunctionInfo<ThrowRuntimeLexicalErrorFn>(ThrowRuntimeLexicalError, "ThrowRuntimeLexicalError");
   12314             : 
   12315             : void
   12316           0 : CodeGenerator::visitThrowRuntimeLexicalError(LThrowRuntimeLexicalError* ins)
   12317             : {
   12318           0 :     pushArg(Imm32(ins->mir()->errorNumber()));
   12319           0 :     callVM(ThrowRuntimeLexicalErrorInfo, ins);
   12320           0 : }
   12321             : 
   12322             : typedef bool (*GlobalNameConflictsCheckFromIonFn)(JSContext*, HandleScript);
   12323           3 : static const VMFunction GlobalNameConflictsCheckFromIonInfo =
   12324           6 :     FunctionInfo<GlobalNameConflictsCheckFromIonFn>(GlobalNameConflictsCheckFromIon,
   12325             :                                                     "GlobalNameConflictsCheckFromIon");
   12326             : 
   12327             : void
   12328           0 : CodeGenerator::visitGlobalNameConflictsCheck(LGlobalNameConflictsCheck* ins)
   12329             : {
   12330           0 :     pushArg(ImmGCPtr(ins->mirRaw()->block()->info().script()));
   12331           0 :     callVM(GlobalNameConflictsCheckFromIonInfo, ins);
   12332           0 : }
   12333             : 
   12334             : void
   12335           0 : CodeGenerator::visitDebugger(LDebugger* ins)
   12336             : {
   12337           0 :     Register cx = ToRegister(ins->getTemp(0));
   12338           0 :     Register temp = ToRegister(ins->getTemp(1));
   12339             : 
   12340           0 :     masm.loadJSContext(cx);
   12341           0 :     masm.setupUnalignedABICall(temp);
   12342           0 :     masm.passABIArg(cx);
   12343           0 :     masm.callWithABI(JS_FUNC_TO_DATA_PTR(void*, GlobalHasLiveOnDebuggerStatement));
   12344             : 
   12345           0 :     Label bail;
   12346           0 :     masm.branchIfTrueBool(ReturnReg, &bail);
   12347           0 :     bailoutFrom(&bail, ins->snapshot());
   12348           0 : }
   12349             : 
   12350             : void
   12351           0 : CodeGenerator::visitNewTarget(LNewTarget *ins)
   12352             : {
   12353           0 :     ValueOperand output = GetValueOutput(ins);
   12354             : 
   12355             :     // if (isConstructing) output = argv[Max(numActualArgs, numFormalArgs)]
   12356           0 :     Label notConstructing, done;
   12357           0 :     Address calleeToken(masm.getStackPointer(), frameSize() + JitFrameLayout::offsetOfCalleeToken());
   12358           0 :     masm.branchTestPtr(Assembler::Zero, calleeToken,
   12359           0 :                        Imm32(CalleeToken_FunctionConstructing), &notConstructing);
   12360             : 
   12361           0 :     Register argvLen = output.scratchReg();
   12362             : 
   12363           0 :     Address actualArgsPtr(masm.getStackPointer(), frameSize() + JitFrameLayout::offsetOfNumActualArgs());
   12364           0 :     masm.loadPtr(actualArgsPtr, argvLen);
   12365             : 
   12366           0 :     Label useNFormals;
   12367             : 
   12368           0 :     size_t numFormalArgs = ins->mirRaw()->block()->info().funMaybeLazy()->nargs();
   12369           0 :     masm.branchPtr(Assembler::Below, argvLen, Imm32(numFormalArgs),
   12370           0 :                    &useNFormals);
   12371             : 
   12372           0 :     size_t argsOffset = frameSize() + JitFrameLayout::offsetOfActualArgs();
   12373             :     {
   12374           0 :         BaseValueIndex newTarget(masm.getStackPointer(), argvLen, argsOffset);
   12375           0 :         masm.loadValue(newTarget, output);
   12376           0 :         masm.jump(&done);
   12377             :     }
   12378             : 
   12379           0 :     masm.bind(&useNFormals);
   12380             : 
   12381             :     {
   12382           0 :         Address newTarget(masm.getStackPointer(), argsOffset + (numFormalArgs * sizeof(Value)));
   12383           0 :         masm.loadValue(newTarget, output);
   12384           0 :         masm.jump(&done);
   12385             :     }
   12386             : 
   12387             :     // else output = undefined
   12388           0 :     masm.bind(&notConstructing);
   12389           0 :     masm.moveValue(UndefinedValue(), output);
   12390           0 :     masm.bind(&done);
   12391           0 : }
   12392             : 
   12393             : void
   12394           0 : CodeGenerator::visitCheckReturn(LCheckReturn* ins)
   12395             : {
   12396           0 :     ValueOperand returnValue = ToValue(ins, LCheckReturn::ReturnValue);
   12397           0 :     ValueOperand thisValue = ToValue(ins, LCheckReturn::ThisValue);
   12398           0 :     Label bail, noChecks;
   12399           0 :     masm.branchTestObject(Assembler::Equal, returnValue, &noChecks);
   12400           0 :     masm.branchTestUndefined(Assembler::NotEqual, returnValue, &bail);
   12401           0 :     masm.branchTestMagicValue(Assembler::Equal, thisValue, JS_UNINITIALIZED_LEXICAL, &bail);
   12402           0 :     bailoutFrom(&bail, ins->snapshot());
   12403           0 :     masm.bind(&noChecks);
   12404           0 : }
   12405             : 
   12406             : typedef bool (*ThrowCheckIsObjectFn)(JSContext*, CheckIsObjectKind);
   12407           3 : static const VMFunction ThrowCheckIsObjectInfo =
   12408           6 :     FunctionInfo<ThrowCheckIsObjectFn>(ThrowCheckIsObject, "ThrowCheckIsObject");
   12409             : 
   12410             : void
   12411           0 : CodeGenerator::visitCheckIsObj(LCheckIsObj* ins)
   12412             : {
   12413           0 :     ValueOperand checkValue = ToValue(ins, LCheckIsObj::CheckValue);
   12414             : 
   12415           0 :     OutOfLineCode* ool = oolCallVM(ThrowCheckIsObjectInfo, ins,
   12416           0 :                                    ArgList(Imm32(ins->mir()->checkKind())),
   12417           0 :                                    StoreNothing());
   12418           0 :     masm.branchTestObject(Assembler::NotEqual, checkValue, ool->entry());
   12419           0 :     masm.bind(ool->rejoin());
   12420           0 : }
   12421             : 
   12422             : typedef bool (*ThrowObjCoercibleFn)(JSContext*, HandleValue);
   12423           3 : static const VMFunction ThrowObjectCoercibleInfo =
   12424           6 :     FunctionInfo<ThrowObjCoercibleFn>(ThrowObjectCoercible, "ThrowObjectCoercible");
   12425             : 
   12426             : void
   12427           0 : CodeGenerator::visitCheckObjCoercible(LCheckObjCoercible* ins)
   12428             : {
   12429           0 :     ValueOperand checkValue = ToValue(ins, LCheckObjCoercible::CheckValue);
   12430           0 :     Label fail, done;
   12431           0 :     masm.branchTestNull(Assembler::Equal, checkValue, &fail);
   12432           0 :     masm.branchTestUndefined(Assembler::NotEqual, checkValue, &done);
   12433           0 :     masm.bind(&fail);
   12434           0 :     pushArg(checkValue);
   12435           0 :     callVM(ThrowObjectCoercibleInfo, ins);
   12436           0 :     masm.bind(&done);
   12437           0 : }
   12438             : 
   12439             : typedef bool (*CheckSelfHostedFn)(JSContext*, HandleValue);
   12440           3 : static const VMFunction CheckSelfHostedInfo =
   12441           6 :     FunctionInfo<CheckSelfHostedFn>(js::Debug_CheckSelfHosted, "Debug_CheckSelfHosted");
   12442             : 
   12443             : void
   12444           0 : CodeGenerator::visitDebugCheckSelfHosted(LDebugCheckSelfHosted* ins)
   12445             : {
   12446           0 :     ValueOperand checkValue = ToValue(ins, LDebugCheckSelfHosted::CheckValue);
   12447           0 :     pushArg(checkValue);
   12448           0 :     callVM(CheckSelfHostedInfo, ins);
   12449           0 : }
   12450             : 
   12451             : void
   12452           0 : CodeGenerator::visitRandom(LRandom* ins)
   12453             : {
   12454             :     using mozilla::non_crypto::XorShift128PlusRNG;
   12455             : 
   12456           0 :     FloatRegister output = ToFloatRegister(ins->output());
   12457           0 :     Register tempReg = ToRegister(ins->temp0());
   12458             : 
   12459             : #ifdef JS_PUNBOX64
   12460           0 :     Register64 s0Reg(ToRegister(ins->temp1()));
   12461           0 :     Register64 s1Reg(ToRegister(ins->temp2()));
   12462             : #else
   12463             :     Register64 s0Reg(ToRegister(ins->temp1()), ToRegister(ins->temp2()));
   12464             :     Register64 s1Reg(ToRegister(ins->temp3()), ToRegister(ins->temp4()));
   12465             : #endif
   12466             : 
   12467           0 :     const void* rng = gen->compartment->addressOfRandomNumberGenerator();
   12468           0 :     masm.movePtr(ImmPtr(rng), tempReg);
   12469             : 
   12470             :     static_assert(sizeof(XorShift128PlusRNG) == 2 * sizeof(uint64_t),
   12471             :                   "Code below assumes XorShift128PlusRNG contains two uint64_t values");
   12472             : 
   12473           0 :     Address state0Addr(tempReg, XorShift128PlusRNG::offsetOfState0());
   12474           0 :     Address state1Addr(tempReg, XorShift128PlusRNG::offsetOfState1());
   12475             : 
   12476             :     // uint64_t s1 = mState[0];
   12477           0 :     masm.load64(state0Addr, s1Reg);
   12478             : 
   12479             :     // s1 ^= s1 << 23;
   12480           0 :     masm.move64(s1Reg, s0Reg);
   12481           0 :     masm.lshift64(Imm32(23), s1Reg);
   12482           0 :     masm.xor64(s0Reg, s1Reg);
   12483             : 
   12484             :     // s1 ^= s1 >> 17
   12485           0 :     masm.move64(s1Reg, s0Reg);
   12486           0 :     masm.rshift64(Imm32(17), s1Reg);
   12487           0 :     masm.xor64(s0Reg, s1Reg);
   12488             : 
   12489             :     // const uint64_t s0 = mState[1];
   12490           0 :     masm.load64(state1Addr, s0Reg);
   12491             : 
   12492             :     // mState[0] = s0;
   12493           0 :     masm.store64(s0Reg, state0Addr);
   12494             : 
   12495             :     // s1 ^= s0
   12496           0 :     masm.xor64(s0Reg, s1Reg);
   12497             : 
   12498             :     // s1 ^= s0 >> 26
   12499           0 :     masm.rshift64(Imm32(26), s0Reg);
   12500           0 :     masm.xor64(s0Reg, s1Reg);
   12501             : 
   12502             :     // mState[1] = s1
   12503           0 :     masm.store64(s1Reg, state1Addr);
   12504             : 
   12505             :     // s1 += mState[0]
   12506           0 :     masm.load64(state0Addr, s0Reg);
   12507           0 :     masm.add64(s0Reg, s1Reg);
   12508             : 
   12509             :     // See comment in XorShift128PlusRNG::nextDouble().
   12510             :     static const int MantissaBits = FloatingPoint<double>::kExponentShift + 1;
   12511             :     static const double ScaleInv = double(1) / (1ULL << MantissaBits);
   12512             : 
   12513           0 :     masm.and64(Imm64((1ULL << MantissaBits) - 1), s1Reg);
   12514             : 
   12515           0 :     if (masm.convertUInt64ToDoubleNeedsTemp())
   12516           0 :         masm.convertUInt64ToDouble(s1Reg, output, tempReg);
   12517             :     else
   12518           0 :         masm.convertUInt64ToDouble(s1Reg, output, Register::Invalid());
   12519             : 
   12520             :     // output *= ScaleInv
   12521           0 :     masm.mulDoublePtr(ImmPtr(&ScaleInv), tempReg, output);
   12522           0 : }
   12523             : 
   12524             : void
   12525           0 : CodeGenerator::visitSignExtend(LSignExtend* ins)
   12526             : {
   12527           0 :     Register input = ToRegister(ins->input());
   12528           0 :     Register output = ToRegister(ins->output());
   12529             : 
   12530           0 :     switch (ins->mode()) {
   12531             :       case MSignExtend::Byte:
   12532           0 :         masm.move8SignExtend(input, output);
   12533           0 :         break;
   12534             :       case MSignExtend::Half:
   12535           0 :         masm.move16SignExtend(input, output);
   12536           0 :         break;
   12537             :     }
   12538           0 : }
   12539             : 
   12540             : void
   12541           0 : CodeGenerator::visitRotate(LRotate* ins)
   12542             : {
   12543           0 :     MRotate* mir = ins->mir();
   12544           0 :     Register input = ToRegister(ins->input());
   12545           0 :     Register dest = ToRegister(ins->output());
   12546             : 
   12547           0 :     const LAllocation* count = ins->count();
   12548           0 :     if (count->isConstant()) {
   12549           0 :         int32_t c = ToInt32(count) & 0x1F;
   12550           0 :         if (mir->isLeftRotate())
   12551           0 :             masm.rotateLeft(Imm32(c), input, dest);
   12552             :         else
   12553           0 :             masm.rotateRight(Imm32(c), input, dest);
   12554             :     } else {
   12555           0 :         Register creg = ToRegister(count);
   12556           0 :         if (mir->isLeftRotate())
   12557           0 :             masm.rotateLeft(creg, input, dest);
   12558             :         else
   12559           0 :             masm.rotateRight(creg, input, dest);
   12560             :     }
   12561           0 : }
   12562             : 
   12563             : class OutOfLineNaNToZero : public OutOfLineCodeBase<CodeGenerator>
   12564             : {
   12565             :     LNaNToZero* lir_;
   12566             : 
   12567             :   public:
   12568           0 :     explicit OutOfLineNaNToZero(LNaNToZero* lir)
   12569           0 :       : lir_(lir)
   12570           0 :     {}
   12571             : 
   12572           0 :     void accept(CodeGenerator* codegen) {
   12573           0 :         codegen->visitOutOfLineNaNToZero(this);
   12574           0 :     }
   12575           0 :     LNaNToZero* lir() const {
   12576           0 :         return lir_;
   12577             :     }
   12578             : };
   12579             : 
   12580             : void
   12581           0 : CodeGenerator::visitOutOfLineNaNToZero(OutOfLineNaNToZero* ool)
   12582             : {
   12583           0 :     FloatRegister output = ToFloatRegister(ool->lir()->output());
   12584           0 :     masm.loadConstantDouble(0.0, output);
   12585           0 :     masm.jump(ool->rejoin());
   12586           0 : }
   12587             : 
   12588             : void
   12589           0 : CodeGenerator::visitNaNToZero(LNaNToZero* lir)
   12590             : {
   12591           0 :     FloatRegister input = ToFloatRegister(lir->input());
   12592             : 
   12593           0 :     OutOfLineNaNToZero* ool = new(alloc()) OutOfLineNaNToZero(lir);
   12594           0 :     addOutOfLineCode(ool, lir->mir());
   12595             : 
   12596           0 :     if (lir->mir()->operandIsNeverNegativeZero()){
   12597           0 :         masm.branchDouble(Assembler::DoubleUnordered, input, input, ool->entry());
   12598             :     } else {
   12599           0 :         FloatRegister scratch = ToFloatRegister(lir->tempDouble());
   12600           0 :         masm.loadConstantDouble(0.0, scratch);
   12601           0 :         masm.branchDouble(Assembler::DoubleEqualOrUnordered, input, scratch, ool->entry());
   12602             :     }
   12603           0 :     masm.bind(ool->rejoin());
   12604           0 : }
   12605             : 
   12606             : typedef bool (*FinishBoundFunctionInitFn)(JSContext* cx, HandleFunction bound,
   12607             :                                           HandleObject target, int32_t argCount);
   12608           3 : static const VMFunction FinishBoundFunctionInitInfo =
   12609           6 :     FunctionInfo<FinishBoundFunctionInitFn>(JSFunction::finishBoundFunctionInit,
   12610             :                                             "JSFunction::finishBoundFunctionInit");
   12611             : 
   12612             : void
   12613           0 : CodeGenerator::visitFinishBoundFunctionInit(LFinishBoundFunctionInit* lir)
   12614             : {
   12615           0 :     Register bound = ToRegister(lir->bound());
   12616           0 :     Register target = ToRegister(lir->target());
   12617           0 :     Register argCount = ToRegister(lir->argCount());
   12618           0 :     Register temp1 = ToRegister(lir->temp1());
   12619           0 :     Register temp2 = ToRegister(lir->temp2());
   12620             : 
   12621           0 :     OutOfLineCode* ool = oolCallVM(FinishBoundFunctionInitInfo, lir,
   12622           0 :                                    ArgList(bound, target, argCount), StoreNothing());
   12623           0 :     Label* slowPath = ool->entry();
   12624             : 
   12625           0 :     const size_t boundLengthOffset = FunctionExtended::offsetOfExtendedSlot(BOUND_FUN_LENGTH_SLOT);
   12626             : 
   12627             :     // Take the slow path if the target is not a JSFunction.
   12628           0 :     masm.branchTestObjClass(Assembler::NotEqual, target, temp1, &JSFunction::class_, slowPath);
   12629             : 
   12630             :     // Take the slow path if we'd need to adjust the [[Prototype]].
   12631           0 :     masm.loadObjProto(bound, temp1);
   12632           0 :     masm.loadObjProto(target, temp2);
   12633           0 :     masm.branchPtr(Assembler::NotEqual, temp1, temp2, slowPath);
   12634             : 
   12635             :     // Get the function flags.
   12636           0 :     masm.load16ZeroExtend(Address(target, JSFunction::offsetOfFlags()), temp1);
   12637             : 
   12638             :     // Functions with lazy scripts don't store their length.
   12639             :     // If the length or name property is resolved, it might be shadowed.
   12640           0 :     masm.branchTest32(Assembler::NonZero,
   12641             :                       temp1,
   12642             :                       Imm32(JSFunction::INTERPRETED_LAZY |
   12643             :                             JSFunction::RESOLVED_NAME |
   12644             :                             JSFunction::RESOLVED_LENGTH),
   12645           0 :                       slowPath);
   12646             : 
   12647           0 :     Label notBoundTarget, loadName;
   12648           0 :     masm.branchTest32(Assembler::Zero, temp1, Imm32(JSFunction::BOUND_FUN), &notBoundTarget);
   12649             :     {
   12650             :         // Target's name atom doesn't contain the bound function prefix, so we
   12651             :         // need to call into the VM.
   12652           0 :         masm.branchTest32(Assembler::Zero, temp1,
   12653           0 :                           Imm32(JSFunction::HAS_BOUND_FUNCTION_NAME_PREFIX), slowPath);
   12654             : 
   12655             :         // We also take the slow path when target's length isn't an int32.
   12656           0 :         masm.branchTestInt32(Assembler::NotEqual, Address(target, boundLengthOffset), slowPath);
   12657             : 
   12658             :         // Bound functions reuse HAS_GUESSED_ATOM for HAS_BOUND_FUNCTION_NAME_PREFIX,
   12659             :         // so skip the guessed atom check below.
   12660             :         static_assert(JSFunction::HAS_BOUND_FUNCTION_NAME_PREFIX == JSFunction::HAS_GUESSED_ATOM,
   12661             :                       "HAS_BOUND_FUNCTION_NAME_PREFIX is shared with HAS_GUESSED_ATOM");
   12662           0 :         masm.jump(&loadName);
   12663             :     }
   12664           0 :     masm.bind(&notBoundTarget);
   12665             : 
   12666           0 :     Label guessed, hasName;
   12667           0 :     masm.branchTest32(Assembler::NonZero, temp1, Imm32(JSFunction::HAS_GUESSED_ATOM), &guessed);
   12668           0 :     masm.bind(&loadName);
   12669           0 :     masm.loadPtr(Address(target, JSFunction::offsetOfAtom()), temp2);
   12670           0 :     masm.branchTestPtr(Assembler::NonZero, temp2, temp2, &hasName);
   12671             :     {
   12672           0 :         masm.bind(&guessed);
   12673             : 
   12674             :         // Unnamed class expression don't have a name property. To avoid
   12675             :         // looking it up from the prototype chain, we take the slow path here.
   12676           0 :         masm.branchFunctionKind(Assembler::Equal, JSFunction::ClassConstructor, target, temp2,
   12677           0 :                                 slowPath);
   12678             : 
   12679             :         // An absent name property defaults to the empty string.
   12680           0 :         const JSAtomState& names = GetJitContext()->runtime->names();
   12681           0 :         masm.movePtr(ImmGCPtr(names.empty), temp2);
   12682             :     }
   12683           0 :     masm.bind(&hasName);
   12684             : 
   12685             :     // Store the target's name atom in the bound function as is.
   12686           0 :     masm.storePtr(temp2, Address(bound, JSFunction::offsetOfAtom()));
   12687             : 
   12688             :     // Set the BOUND_FN flag and, if the target is a constructor, the
   12689             :     // CONSTRUCTOR flag.
   12690           0 :     Label isConstructor, boundFlagsComputed;
   12691           0 :     masm.load16ZeroExtend(Address(bound, JSFunction::offsetOfFlags()), temp2);
   12692           0 :     masm.branchTest32(Assembler::NonZero, temp1, Imm32(JSFunction::CONSTRUCTOR), &isConstructor);
   12693             :     {
   12694           0 :         masm.or32(Imm32(JSFunction::BOUND_FUN), temp2);
   12695           0 :         masm.jump(&boundFlagsComputed);
   12696             :     }
   12697           0 :     masm.bind(&isConstructor);
   12698             :     {
   12699           0 :         masm.or32(Imm32(JSFunction::BOUND_FUN | JSFunction::CONSTRUCTOR), temp2);
   12700             :     }
   12701           0 :     masm.bind(&boundFlagsComputed);
   12702           0 :     masm.store16(temp2, Address(bound, JSFunction::offsetOfFlags()));
   12703             : 
   12704             :     // Load the target function's length.
   12705           0 :     Label isInterpreted, isBound, lengthLoaded;
   12706           0 :     masm.branchTest32(Assembler::NonZero, temp1, Imm32(JSFunction::BOUND_FUN), &isBound);
   12707           0 :     masm.branchTest32(Assembler::NonZero, temp1, Imm32(JSFunction::INTERPRETED), &isInterpreted);
   12708             :     {
   12709             :         // Load the length property of a native function.
   12710           0 :         masm.load16ZeroExtend(Address(target, JSFunction::offsetOfNargs()), temp1);
   12711           0 :         masm.jump(&lengthLoaded);
   12712             :     }
   12713           0 :     masm.bind(&isBound);
   12714             :     {
   12715             :         // Load the length property of a bound function.
   12716           0 :         masm.unboxInt32(Address(target, boundLengthOffset), temp1);
   12717           0 :         masm.jump(&lengthLoaded);
   12718             :     }
   12719           0 :     masm.bind(&isInterpreted);
   12720             :     {
   12721             :         // Load the length property of an interpreted function.
   12722           0 :         masm.loadPtr(Address(target, JSFunction::offsetOfNativeOrScript()), temp1);
   12723           0 :         masm.load16ZeroExtend(Address(temp1, JSScript::offsetOfFunLength()), temp1);
   12724             :     }
   12725           0 :     masm.bind(&lengthLoaded);
   12726             : 
   12727             :     // Compute the bound function length: Max(0, target.length - argCount).
   12728           0 :     Label nonNegative;
   12729           0 :     masm.sub32(argCount, temp1);
   12730           0 :     masm.branch32(Assembler::GreaterThanOrEqual, temp1, Imm32(0), &nonNegative);
   12731           0 :     masm.move32(Imm32(0), temp1);
   12732           0 :     masm.bind(&nonNegative);
   12733             : 
   12734             :     // Store the bound function's length into the extended slot.
   12735           0 :     masm.storeValue(JSVAL_TYPE_INT32, temp1, Address(bound, boundLengthOffset));
   12736             : 
   12737           0 :     masm.bind(ool->rejoin());
   12738           0 : }
   12739             : 
   12740             : } // namespace jit
   12741             : } // namespace js

Generated by: LCOV version 1.13