LCOV - code coverage report
Current view: top level - js/src/wasm - AsmJS.cpp (source / functions) Hit Total Coverage
Test: output.info Lines: 5 4754 0.1 %
Date: 2017-07-14 16:53:18 Functions: 2 541 0.4 %
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             :  *
       4             :  * Copyright 2014 Mozilla Foundation
       5             :  *
       6             :  * Licensed under the Apache License, Version 2.0 (the "License");
       7             :  * you may not use this file except in compliance with the License.
       8             :  * You may obtain a copy of the License at
       9             :  *
      10             :  *     http://www.apache.org/licenses/LICENSE-2.0
      11             :  *
      12             :  * Unless required by applicable law or agreed to in writing, software
      13             :  * distributed under the License is distributed on an "AS IS" BASIS,
      14             :  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
      15             :  * See the License for the specific language governing permissions and
      16             :  * limitations under the License.
      17             :  */
      18             : 
      19             : #include "wasm/AsmJS.h"
      20             : 
      21             : #include "mozilla/Attributes.h"
      22             : #include "mozilla/Compression.h"
      23             : #include "mozilla/MathAlgorithms.h"
      24             : #include "mozilla/Maybe.h"
      25             : #include "mozilla/Unused.h"
      26             : 
      27             : #include "jsmath.h"
      28             : #include "jsprf.h"
      29             : #include "jsstr.h"
      30             : #include "jsutil.h"
      31             : 
      32             : #include "jswrapper.h"
      33             : 
      34             : #include "builtin/SIMD.h"
      35             : #include "frontend/Parser.h"
      36             : #include "gc/Policy.h"
      37             : #include "jit/AtomicOperations.h"
      38             : #include "js/MemoryMetrics.h"
      39             : #include "vm/ErrorReporting.h"
      40             : #include "vm/SelfHosting.h"
      41             : #include "vm/StringBuffer.h"
      42             : #include "vm/Time.h"
      43             : #include "vm/TypedArrayObject.h"
      44             : #include "wasm/WasmCompile.h"
      45             : #include "wasm/WasmGenerator.h"
      46             : #include "wasm/WasmInstance.h"
      47             : #include "wasm/WasmJS.h"
      48             : #include "wasm/WasmSerialize.h"
      49             : #include "wasm/WasmValidate.h"
      50             : 
      51             : #include "jsobjinlines.h"
      52             : 
      53             : #include "frontend/ParseNode-inl.h"
      54             : #include "vm/ArrayBufferObject-inl.h"
      55             : 
      56             : using namespace js;
      57             : using namespace js::frontend;
      58             : using namespace js::jit;
      59             : using namespace js::wasm;
      60             : 
      61             : using mozilla::CeilingLog2;
      62             : using mozilla::Compression::LZ4;
      63             : using mozilla::HashGeneric;
      64             : using mozilla::IsNaN;
      65             : using mozilla::IsNegativeZero;
      66             : using mozilla::IsPositiveZero;
      67             : using mozilla::IsPowerOfTwo;
      68             : using mozilla::Maybe;
      69             : using mozilla::Move;
      70             : using mozilla::PodCopy;
      71             : using mozilla::PodEqual;
      72             : using mozilla::PodZero;
      73             : using mozilla::PositiveInfinity;
      74             : using mozilla::Unused;
      75             : using JS::AsmJSOption;
      76             : using JS::GenericNaN;
      77             : 
      78             : /*****************************************************************************/
      79             : 
      80             : // The asm.js valid heap lengths are precisely the WASM valid heap lengths for ARM
      81             : // greater or equal to MinHeapLength
      82             : static const size_t MinHeapLength = PageSize;
      83             : 
      84             : static uint32_t
      85           0 : RoundUpToNextValidAsmJSHeapLength(uint32_t length)
      86             : {
      87           0 :     if (length <= MinHeapLength)
      88           0 :         return MinHeapLength;
      89             : 
      90           0 :     return wasm::RoundUpToNextValidARMImmediate(length);
      91             : }
      92             : 
      93             : 
      94             : /*****************************************************************************/
      95             : // asm.js module object
      96             : 
      97             : // The asm.js spec recognizes this set of builtin Math functions.
      98             : enum AsmJSMathBuiltinFunction
      99             : {
     100             :     AsmJSMathBuiltin_sin, AsmJSMathBuiltin_cos, AsmJSMathBuiltin_tan,
     101             :     AsmJSMathBuiltin_asin, AsmJSMathBuiltin_acos, AsmJSMathBuiltin_atan,
     102             :     AsmJSMathBuiltin_ceil, AsmJSMathBuiltin_floor, AsmJSMathBuiltin_exp,
     103             :     AsmJSMathBuiltin_log, AsmJSMathBuiltin_pow, AsmJSMathBuiltin_sqrt,
     104             :     AsmJSMathBuiltin_abs, AsmJSMathBuiltin_atan2, AsmJSMathBuiltin_imul,
     105             :     AsmJSMathBuiltin_fround, AsmJSMathBuiltin_min, AsmJSMathBuiltin_max,
     106             :     AsmJSMathBuiltin_clz32
     107             : };
     108             : 
     109             : // The asm.js spec will recognize this set of builtin Atomics functions.
     110             : enum AsmJSAtomicsBuiltinFunction
     111             : {
     112             :     AsmJSAtomicsBuiltin_compareExchange,
     113             :     AsmJSAtomicsBuiltin_exchange,
     114             :     AsmJSAtomicsBuiltin_load,
     115             :     AsmJSAtomicsBuiltin_store,
     116             :     AsmJSAtomicsBuiltin_add,
     117             :     AsmJSAtomicsBuiltin_sub,
     118             :     AsmJSAtomicsBuiltin_and,
     119             :     AsmJSAtomicsBuiltin_or,
     120             :     AsmJSAtomicsBuiltin_xor,
     121             :     AsmJSAtomicsBuiltin_isLockFree
     122             : };
     123             : 
     124             : 
     125             : // An AsmJSGlobal represents a JS global variable in the asm.js module function.
     126           0 : class AsmJSGlobal
     127             : {
     128             :   public:
     129             :     enum Which { Variable, FFI, ArrayView, ArrayViewCtor, MathBuiltinFunction,
     130             :                  AtomicsBuiltinFunction, Constant, SimdCtor, SimdOp };
     131             :     enum VarInitKind { InitConstant, InitImport };
     132             :     enum ConstantKind { GlobalConstant, MathConstant };
     133             : 
     134             :   private:
     135           0 :     struct CacheablePod {
     136             :         Which which_;
     137             :         union V {
     138             :             struct {
     139             :                 VarInitKind initKind_;
     140             :                 union U {
     141             :                     ValType importType_;
     142             :                     Val val_;
     143             :                     U() {}
     144             :                 } u;
     145             :             } var;
     146             :             uint32_t ffiIndex_;
     147             :             Scalar::Type viewType_;
     148             :             AsmJSMathBuiltinFunction mathBuiltinFunc_;
     149             :             AsmJSAtomicsBuiltinFunction atomicsBuiltinFunc_;
     150             :             SimdType simdCtorType_;
     151             :             struct {
     152             :                 SimdType type_;
     153             :                 SimdOperation which_;
     154             :             } simdOp;
     155             :             struct {
     156             :                 ConstantKind kind_;
     157             :                 double value_;
     158             :             } constant;
     159           0 :             V() {}
     160             :         } u;
     161             :     } pod;
     162             :     CacheableChars field_;
     163             : 
     164             :     friend class ModuleValidator;
     165             : 
     166             :   public:
     167           0 :     AsmJSGlobal() = default;
     168           0 :     AsmJSGlobal(Which which, UniqueChars field) {
     169           0 :         mozilla::PodZero(&pod);  // zero padding for Valgrind
     170           0 :         pod.which_ = which;
     171           0 :         field_ = Move(field);
     172           0 :     }
     173           0 :     const char* field() const {
     174           0 :         return field_.get();
     175             :     }
     176           0 :     Which which() const {
     177           0 :         return pod.which_;
     178             :     }
     179           0 :     VarInitKind varInitKind() const {
     180           0 :         MOZ_ASSERT(pod.which_ == Variable);
     181           0 :         return pod.u.var.initKind_;
     182             :     }
     183           0 :     Val varInitVal() const {
     184           0 :         MOZ_ASSERT(pod.which_ == Variable);
     185           0 :         MOZ_ASSERT(pod.u.var.initKind_ == InitConstant);
     186           0 :         return pod.u.var.u.val_;
     187             :     }
     188           0 :     ValType varInitImportType() const {
     189           0 :         MOZ_ASSERT(pod.which_ == Variable);
     190           0 :         MOZ_ASSERT(pod.u.var.initKind_ == InitImport);
     191           0 :         return pod.u.var.u.importType_;
     192             :     }
     193           0 :     uint32_t ffiIndex() const {
     194           0 :         MOZ_ASSERT(pod.which_ == FFI);
     195           0 :         return pod.u.ffiIndex_;
     196             :     }
     197             :     // When a view is created from an imported constructor:
     198             :     //   var I32 = stdlib.Int32Array;
     199             :     //   var i32 = new I32(buffer);
     200             :     // the second import has nothing to validate and thus has a null field.
     201           0 :     Scalar::Type viewType() const {
     202           0 :         MOZ_ASSERT(pod.which_ == ArrayView || pod.which_ == ArrayViewCtor);
     203           0 :         return pod.u.viewType_;
     204             :     }
     205           0 :     AsmJSMathBuiltinFunction mathBuiltinFunction() const {
     206           0 :         MOZ_ASSERT(pod.which_ == MathBuiltinFunction);
     207           0 :         return pod.u.mathBuiltinFunc_;
     208             :     }
     209           0 :     AsmJSAtomicsBuiltinFunction atomicsBuiltinFunction() const {
     210           0 :         MOZ_ASSERT(pod.which_ == AtomicsBuiltinFunction);
     211           0 :         return pod.u.atomicsBuiltinFunc_;
     212             :     }
     213           0 :     SimdType simdCtorType() const {
     214           0 :         MOZ_ASSERT(pod.which_ == SimdCtor);
     215           0 :         return pod.u.simdCtorType_;
     216             :     }
     217           0 :     SimdOperation simdOperation() const {
     218           0 :         MOZ_ASSERT(pod.which_ == SimdOp);
     219           0 :         return pod.u.simdOp.which_;
     220             :     }
     221           0 :     SimdType simdOperationType() const {
     222           0 :         MOZ_ASSERT(pod.which_ == SimdOp);
     223           0 :         return pod.u.simdOp.type_;
     224             :     }
     225           0 :     ConstantKind constantKind() const {
     226           0 :         MOZ_ASSERT(pod.which_ == Constant);
     227           0 :         return pod.u.constant.kind_;
     228             :     }
     229           0 :     double constantValue() const {
     230           0 :         MOZ_ASSERT(pod.which_ == Constant);
     231           0 :         return pod.u.constant.value_;
     232             :     }
     233             : 
     234             :     WASM_DECLARE_SERIALIZABLE(AsmJSGlobal);
     235             : };
     236             : 
     237             : typedef Vector<AsmJSGlobal, 0, SystemAllocPolicy> AsmJSGlobalVector;
     238             : 
     239             : // An AsmJSImport is slightly different than an asm.js FFI function: a single
     240             : // asm.js FFI function can be called with many different signatures. When
     241             : // compiled to wasm, each unique FFI function paired with signature generates a
     242             : // wasm import.
     243             : class AsmJSImport
     244             : {
     245             :     uint32_t ffiIndex_;
     246             :   public:
     247             :     AsmJSImport() = default;
     248           0 :     explicit AsmJSImport(uint32_t ffiIndex) : ffiIndex_(ffiIndex) {}
     249           0 :     uint32_t ffiIndex() const { return ffiIndex_; }
     250             : };
     251             : 
     252             : typedef Vector<AsmJSImport, 0, SystemAllocPolicy> AsmJSImportVector;
     253             : 
     254             : // An AsmJSExport logically extends Export with the extra information needed for
     255             : // an asm.js exported function, viz., the offsets in module's source chars in
     256             : // case the function is toString()ed.
     257             : class AsmJSExport
     258             : {
     259             :     uint32_t funcIndex_;
     260             : 
     261             :     // All fields are treated as cacheable POD:
     262             :     uint32_t startOffsetInModule_;  // Store module-start-relative offsets
     263             :     uint32_t endOffsetInModule_;    // so preserved by serialization.
     264             : 
     265             :   public:
     266             :     AsmJSExport() { PodZero(this); }
     267           0 :     AsmJSExport(uint32_t funcIndex, uint32_t startOffsetInModule, uint32_t endOffsetInModule)
     268           0 :       : funcIndex_(funcIndex),
     269             :         startOffsetInModule_(startOffsetInModule),
     270           0 :         endOffsetInModule_(endOffsetInModule)
     271           0 :     {}
     272           0 :     uint32_t funcIndex() const {
     273           0 :         return funcIndex_;
     274             :     }
     275           0 :     uint32_t startOffsetInModule() const {
     276           0 :         return startOffsetInModule_;
     277             :     }
     278           0 :     uint32_t endOffsetInModule() const {
     279           0 :         return endOffsetInModule_;
     280             :     }
     281             : };
     282             : 
     283             : typedef Vector<AsmJSExport, 0, SystemAllocPolicy> AsmJSExportVector;
     284             : 
     285             : enum class CacheResult
     286             : {
     287             :     Hit,
     288             :     Miss
     289             : };
     290             : 
     291             : // Holds the immutable guts of an AsmJSModule.
     292             : //
     293             : // AsmJSMetadata is built incrementally by ModuleValidator and then shared
     294             : // immutably between AsmJSModules.
     295             : 
     296             : struct AsmJSMetadataCacheablePod
     297             : {
     298             :     uint32_t                numFFIs;
     299             :     uint32_t                srcLength;
     300             :     uint32_t                srcLengthWithRightBrace;
     301             :     bool                    usesSimd;
     302             : 
     303           0 :     AsmJSMetadataCacheablePod() { PodZero(this); }
     304             : };
     305             : 
     306             : struct js::AsmJSMetadata : Metadata, AsmJSMetadataCacheablePod
     307             : {
     308             :     AsmJSGlobalVector       asmJSGlobals;
     309             :     AsmJSImportVector       asmJSImports;
     310             :     AsmJSExportVector       asmJSExports;
     311             :     CacheableCharsVector    asmJSFuncNames;
     312             :     CacheableChars          globalArgumentName;
     313             :     CacheableChars          importArgumentName;
     314             :     CacheableChars          bufferArgumentName;
     315             : 
     316             :     CacheResult             cacheResult;
     317             : 
     318             :     // These values are not serialized since they are relative to the
     319             :     // containing script which can be different between serialization and
     320             :     // deserialization contexts. Thus, they must be set explicitly using the
     321             :     // ambient Parser/ScriptSource after deserialization.
     322             :     //
     323             :     // srcStart refers to the offset in the ScriptSource to the beginning of
     324             :     // the asm.js module function. If the function has been created with the
     325             :     // Function constructor, this will be the first character in the function
     326             :     // source. Otherwise, it will be the opening parenthesis of the arguments
     327             :     // list.
     328             :     uint32_t                toStringStart;
     329             :     uint32_t                srcStart;
     330             :     uint32_t                srcBodyStart;
     331             :     bool                    strict;
     332             :     ScriptSourceHolder      scriptSource;
     333             : 
     334           0 :     uint32_t srcEndBeforeCurly() const {
     335           0 :         return srcStart + srcLength;
     336             :     }
     337           0 :     uint32_t srcEndAfterCurly() const {
     338           0 :         return srcStart + srcLengthWithRightBrace;
     339             :     }
     340             : 
     341           0 :     explicit AsmJSMetadata(UniqueMetadataTier tier)
     342           0 :       : Metadata(Move(tier), ModuleKind::AsmJS),
     343             :         cacheResult(CacheResult::Miss),
     344             :         srcStart(0),
     345             :         srcBodyStart(0),
     346           0 :         strict(false)
     347           0 :     {}
     348           0 :     ~AsmJSMetadata() override {}
     349             : 
     350           0 :     const AsmJSExport& lookupAsmJSExport(uint32_t funcIndex) const {
     351             :         // The AsmJSExportVector isn't stored in sorted order so do a linear
     352             :         // search. This is for the super-cold and already-expensive toString()
     353             :         // path and the number of exports is generally small.
     354           0 :         for (const AsmJSExport& exp : asmJSExports) {
     355           0 :             if (exp.funcIndex() == funcIndex)
     356           0 :                 return exp;
     357             :         }
     358           0 :         MOZ_CRASH("missing asm.js func export");
     359             :     }
     360             : 
     361           0 :     bool mutedErrors() const override {
     362           0 :         return scriptSource.get()->mutedErrors();
     363             :     }
     364           0 :     const char16_t* displayURL() const override {
     365           0 :         return scriptSource.get()->hasDisplayURL() ? scriptSource.get()->displayURL() : nullptr;
     366             :     }
     367           0 :     ScriptSource* maybeScriptSource() const override {
     368           0 :         return scriptSource.get();
     369             :     }
     370           0 :     bool getFuncName(const Bytes* maybeBytecode, uint32_t funcIndex, UTF8Bytes* name) const override {
     371             :         // asm.js doesn't allow exporting imports or putting imports in tables
     372           0 :         MOZ_ASSERT(funcIndex >= AsmJSFirstDefFuncIndex);
     373           0 :         const char* p = asmJSFuncNames[funcIndex - AsmJSFirstDefFuncIndex].get();
     374           0 :         return name->append(p, strlen(p));
     375             :     }
     376             : 
     377           0 :     AsmJSMetadataCacheablePod& pod() { return *this; }
     378           0 :     const AsmJSMetadataCacheablePod& pod() const { return *this; }
     379             : 
     380             :     WASM_DECLARE_SERIALIZABLE_OVERRIDE(AsmJSMetadata)
     381             : };
     382             : 
     383             : typedef RefPtr<AsmJSMetadata> MutableAsmJSMetadata;
     384             : 
     385             : /*****************************************************************************/
     386             : // ParseNode utilities
     387             : 
     388             : static inline ParseNode*
     389           0 : NextNode(ParseNode* pn)
     390             : {
     391           0 :     return pn->pn_next;
     392             : }
     393             : 
     394             : static inline ParseNode*
     395           0 : UnaryKid(ParseNode* pn)
     396             : {
     397           0 :     MOZ_ASSERT(pn->isArity(PN_UNARY));
     398           0 :     return pn->pn_kid;
     399             : }
     400             : 
     401             : static inline ParseNode*
     402           0 : BinaryRight(ParseNode* pn)
     403             : {
     404           0 :     MOZ_ASSERT(pn->isArity(PN_BINARY));
     405           0 :     return pn->pn_right;
     406             : }
     407             : 
     408             : static inline ParseNode*
     409           0 : BinaryLeft(ParseNode* pn)
     410             : {
     411           0 :     MOZ_ASSERT(pn->isArity(PN_BINARY));
     412           0 :     return pn->pn_left;
     413             : }
     414             : 
     415             : static inline ParseNode*
     416           0 : ReturnExpr(ParseNode* pn)
     417             : {
     418           0 :     MOZ_ASSERT(pn->isKind(PNK_RETURN));
     419           0 :     return UnaryKid(pn);
     420             : }
     421             : 
     422             : static inline ParseNode*
     423           0 : TernaryKid1(ParseNode* pn)
     424             : {
     425           0 :     MOZ_ASSERT(pn->isArity(PN_TERNARY));
     426           0 :     return pn->pn_kid1;
     427             : }
     428             : 
     429             : static inline ParseNode*
     430           0 : TernaryKid2(ParseNode* pn)
     431             : {
     432           0 :     MOZ_ASSERT(pn->isArity(PN_TERNARY));
     433           0 :     return pn->pn_kid2;
     434             : }
     435             : 
     436             : static inline ParseNode*
     437           0 : TernaryKid3(ParseNode* pn)
     438             : {
     439           0 :     MOZ_ASSERT(pn->isArity(PN_TERNARY));
     440           0 :     return pn->pn_kid3;
     441             : }
     442             : 
     443             : static inline ParseNode*
     444           0 : ListHead(ParseNode* pn)
     445             : {
     446           0 :     MOZ_ASSERT(pn->isArity(PN_LIST));
     447           0 :     return pn->pn_head;
     448             : }
     449             : 
     450             : static inline unsigned
     451           0 : ListLength(ParseNode* pn)
     452             : {
     453           0 :     MOZ_ASSERT(pn->isArity(PN_LIST));
     454           0 :     return pn->pn_count;
     455             : }
     456             : 
     457             : static inline ParseNode*
     458           0 : CallCallee(ParseNode* pn)
     459             : {
     460           0 :     MOZ_ASSERT(pn->isKind(PNK_CALL));
     461           0 :     return ListHead(pn);
     462             : }
     463             : 
     464             : static inline unsigned
     465           0 : CallArgListLength(ParseNode* pn)
     466             : {
     467           0 :     MOZ_ASSERT(pn->isKind(PNK_CALL));
     468           0 :     MOZ_ASSERT(ListLength(pn) >= 1);
     469           0 :     return ListLength(pn) - 1;
     470             : }
     471             : 
     472             : static inline ParseNode*
     473           0 : CallArgList(ParseNode* pn)
     474             : {
     475           0 :     MOZ_ASSERT(pn->isKind(PNK_CALL));
     476           0 :     return NextNode(ListHead(pn));
     477             : }
     478             : 
     479             : static inline ParseNode*
     480           0 : VarListHead(ParseNode* pn)
     481             : {
     482           0 :     MOZ_ASSERT(pn->isKind(PNK_VAR) || pn->isKind(PNK_CONST));
     483           0 :     return ListHead(pn);
     484             : }
     485             : 
     486             : static inline bool
     487           0 : IsDefaultCase(ParseNode* pn)
     488             : {
     489           0 :     return pn->as<CaseClause>().isDefault();
     490             : }
     491             : 
     492             : static inline ParseNode*
     493           0 : CaseExpr(ParseNode* pn)
     494             : {
     495           0 :     return pn->as<CaseClause>().caseExpression();
     496             : }
     497             : 
     498             : static inline ParseNode*
     499           0 : CaseBody(ParseNode* pn)
     500             : {
     501           0 :     return pn->as<CaseClause>().statementList();
     502             : }
     503             : 
     504             : static inline ParseNode*
     505           0 : BinaryOpLeft(ParseNode* pn)
     506             : {
     507           0 :     MOZ_ASSERT(pn->isBinaryOperation());
     508           0 :     MOZ_ASSERT(pn->isArity(PN_LIST));
     509           0 :     MOZ_ASSERT(pn->pn_count == 2);
     510           0 :     return ListHead(pn);
     511             : }
     512             : 
     513             : static inline ParseNode*
     514           0 : BinaryOpRight(ParseNode* pn)
     515             : {
     516           0 :     MOZ_ASSERT(pn->isBinaryOperation());
     517           0 :     MOZ_ASSERT(pn->isArity(PN_LIST));
     518           0 :     MOZ_ASSERT(pn->pn_count == 2);
     519           0 :     return NextNode(ListHead(pn));
     520             : }
     521             : 
     522             : static inline ParseNode*
     523           0 : BitwiseLeft(ParseNode* pn)
     524             : {
     525           0 :     return BinaryOpLeft(pn);
     526             : }
     527             : 
     528             : static inline ParseNode*
     529           0 : BitwiseRight(ParseNode* pn)
     530             : {
     531           0 :     return BinaryOpRight(pn);
     532             : }
     533             : 
     534             : static inline ParseNode*
     535           0 : MultiplyLeft(ParseNode* pn)
     536             : {
     537           0 :     MOZ_ASSERT(pn->isKind(PNK_STAR));
     538           0 :     return BinaryOpLeft(pn);
     539             : }
     540             : 
     541             : static inline ParseNode*
     542           0 : MultiplyRight(ParseNode* pn)
     543             : {
     544           0 :     MOZ_ASSERT(pn->isKind(PNK_STAR));
     545           0 :     return BinaryOpRight(pn);
     546             : }
     547             : 
     548             : static inline ParseNode*
     549           0 : AddSubLeft(ParseNode* pn)
     550             : {
     551           0 :     MOZ_ASSERT(pn->isKind(PNK_ADD) || pn->isKind(PNK_SUB));
     552           0 :     return BinaryOpLeft(pn);
     553             : }
     554             : 
     555             : static inline ParseNode*
     556           0 : AddSubRight(ParseNode* pn)
     557             : {
     558           0 :     MOZ_ASSERT(pn->isKind(PNK_ADD) || pn->isKind(PNK_SUB));
     559           0 :     return BinaryOpRight(pn);
     560             : }
     561             : 
     562             : static inline ParseNode*
     563           0 : DivOrModLeft(ParseNode* pn)
     564             : {
     565           0 :     MOZ_ASSERT(pn->isKind(PNK_DIV) || pn->isKind(PNK_MOD));
     566           0 :     return BinaryOpLeft(pn);
     567             : }
     568             : 
     569             : static inline ParseNode*
     570           0 : DivOrModRight(ParseNode* pn)
     571             : {
     572           0 :     MOZ_ASSERT(pn->isKind(PNK_DIV) || pn->isKind(PNK_MOD));
     573           0 :     return BinaryOpRight(pn);
     574             : }
     575             : 
     576             : static inline ParseNode*
     577           0 : ComparisonLeft(ParseNode* pn)
     578             : {
     579           0 :     return BinaryOpLeft(pn);
     580             : }
     581             : 
     582             : static inline ParseNode*
     583           0 : ComparisonRight(ParseNode* pn)
     584             : {
     585           0 :     return BinaryOpRight(pn);
     586             : }
     587             : 
     588             : static inline bool
     589           0 : IsExpressionStatement(ParseNode* pn)
     590             : {
     591           0 :     return pn->isKind(PNK_SEMI);
     592             : }
     593             : 
     594             : static inline ParseNode*
     595           0 : ExpressionStatementExpr(ParseNode* pn)
     596             : {
     597           0 :     MOZ_ASSERT(pn->isKind(PNK_SEMI));
     598           0 :     return UnaryKid(pn);
     599             : }
     600             : 
     601             : static inline PropertyName*
     602           0 : LoopControlMaybeLabel(ParseNode* pn)
     603             : {
     604           0 :     MOZ_ASSERT(pn->isKind(PNK_BREAK) || pn->isKind(PNK_CONTINUE));
     605           0 :     MOZ_ASSERT(pn->isArity(PN_NULLARY));
     606           0 :     return pn->as<LoopControlStatement>().label();
     607             : }
     608             : 
     609             : static inline PropertyName*
     610           0 : LabeledStatementLabel(ParseNode* pn)
     611             : {
     612           0 :     return pn->as<LabeledStatement>().label();
     613             : }
     614             : 
     615             : static inline ParseNode*
     616           0 : LabeledStatementStatement(ParseNode* pn)
     617             : {
     618           0 :     return pn->as<LabeledStatement>().statement();
     619             : }
     620             : 
     621             : static double
     622           0 : NumberNodeValue(ParseNode* pn)
     623             : {
     624           0 :     MOZ_ASSERT(pn->isKind(PNK_NUMBER));
     625           0 :     return pn->pn_dval;
     626             : }
     627             : 
     628             : static bool
     629           0 : NumberNodeHasFrac(ParseNode* pn)
     630             : {
     631           0 :     MOZ_ASSERT(pn->isKind(PNK_NUMBER));
     632           0 :     return pn->pn_u.number.decimalPoint == HasDecimal;
     633             : }
     634             : 
     635             : static ParseNode*
     636           0 : DotBase(ParseNode* pn)
     637             : {
     638           0 :     MOZ_ASSERT(pn->isKind(PNK_DOT));
     639           0 :     MOZ_ASSERT(pn->isArity(PN_NAME));
     640           0 :     return pn->expr();
     641             : }
     642             : 
     643             : static PropertyName*
     644           0 : DotMember(ParseNode* pn)
     645             : {
     646           0 :     MOZ_ASSERT(pn->isKind(PNK_DOT));
     647           0 :     MOZ_ASSERT(pn->isArity(PN_NAME));
     648           0 :     return pn->pn_atom->asPropertyName();
     649             : }
     650             : 
     651             : static ParseNode*
     652           0 : ElemBase(ParseNode* pn)
     653             : {
     654           0 :     MOZ_ASSERT(pn->isKind(PNK_ELEM));
     655           0 :     return BinaryLeft(pn);
     656             : }
     657             : 
     658             : static ParseNode*
     659           0 : ElemIndex(ParseNode* pn)
     660             : {
     661           0 :     MOZ_ASSERT(pn->isKind(PNK_ELEM));
     662           0 :     return BinaryRight(pn);
     663             : }
     664             : 
     665             : static inline JSFunction*
     666           0 : FunctionObject(ParseNode* fn)
     667             : {
     668           0 :     MOZ_ASSERT(fn->isKind(PNK_FUNCTION));
     669           0 :     MOZ_ASSERT(fn->isArity(PN_CODE));
     670           0 :     return fn->pn_funbox->function();
     671             : }
     672             : 
     673             : static inline PropertyName*
     674           0 : FunctionName(ParseNode* fn)
     675             : {
     676           0 :     if (JSAtom* name = FunctionObject(fn)->explicitName())
     677           0 :         return name->asPropertyName();
     678           0 :     return nullptr;
     679             : }
     680             : 
     681             : static inline ParseNode*
     682           0 : FunctionStatementList(ParseNode* fn)
     683             : {
     684           0 :     MOZ_ASSERT(fn->pn_body->isKind(PNK_PARAMSBODY));
     685           0 :     ParseNode* last = fn->pn_body->last();
     686           0 :     MOZ_ASSERT(last->isKind(PNK_LEXICALSCOPE));
     687           0 :     MOZ_ASSERT(last->isEmptyScope());
     688           0 :     ParseNode* body = last->scopeBody();
     689           0 :     MOZ_ASSERT(body->isKind(PNK_STATEMENTLIST));
     690           0 :     return body;
     691             : }
     692             : 
     693             : static inline bool
     694           0 : IsNormalObjectField(JSContext* cx, ParseNode* pn)
     695             : {
     696           0 :     return pn->isKind(PNK_COLON) &&
     697           0 :            pn->getOp() == JSOP_INITPROP &&
     698           0 :            BinaryLeft(pn)->isKind(PNK_OBJECT_PROPERTY_NAME);
     699             : }
     700             : 
     701             : static inline PropertyName*
     702           0 : ObjectNormalFieldName(JSContext* cx, ParseNode* pn)
     703             : {
     704           0 :     MOZ_ASSERT(IsNormalObjectField(cx, pn));
     705           0 :     MOZ_ASSERT(BinaryLeft(pn)->isKind(PNK_OBJECT_PROPERTY_NAME));
     706           0 :     return BinaryLeft(pn)->pn_atom->asPropertyName();
     707             : }
     708             : 
     709             : static inline ParseNode*
     710           0 : ObjectNormalFieldInitializer(JSContext* cx, ParseNode* pn)
     711             : {
     712           0 :     MOZ_ASSERT(IsNormalObjectField(cx, pn));
     713           0 :     return BinaryRight(pn);
     714             : }
     715             : 
     716             : static inline ParseNode*
     717           0 : MaybeInitializer(ParseNode* pn)
     718             : {
     719           0 :     return pn->expr();
     720             : }
     721             : 
     722             : static inline bool
     723           0 : IsUseOfName(ParseNode* pn, PropertyName* name)
     724             : {
     725           0 :     return pn->isKind(PNK_NAME) && pn->name() == name;
     726             : }
     727             : 
     728             : static inline bool
     729           0 : IsIgnoredDirectiveName(JSContext* cx, JSAtom* atom)
     730             : {
     731           0 :     return atom != cx->names().useStrict;
     732             : }
     733             : 
     734             : static inline bool
     735           0 : IsIgnoredDirective(JSContext* cx, ParseNode* pn)
     736             : {
     737           0 :     return pn->isKind(PNK_SEMI) &&
     738           0 :            UnaryKid(pn) &&
     739           0 :            UnaryKid(pn)->isKind(PNK_STRING) &&
     740           0 :            IsIgnoredDirectiveName(cx, UnaryKid(pn)->pn_atom);
     741             : }
     742             : 
     743             : static inline bool
     744           0 : IsEmptyStatement(ParseNode* pn)
     745             : {
     746           0 :     return pn->isKind(PNK_SEMI) && !UnaryKid(pn);
     747             : }
     748             : 
     749             : static inline ParseNode*
     750           0 : SkipEmptyStatements(ParseNode* pn)
     751             : {
     752           0 :     while (pn && IsEmptyStatement(pn))
     753           0 :         pn = pn->pn_next;
     754           0 :     return pn;
     755             : }
     756             : 
     757             : static inline ParseNode*
     758           0 : NextNonEmptyStatement(ParseNode* pn)
     759             : {
     760           0 :     return SkipEmptyStatements(pn->pn_next);
     761             : }
     762             : 
     763             : static bool
     764           0 : GetToken(AsmJSParser& parser, TokenKind* tkp)
     765             : {
     766           0 :     TokenStream& ts = parser.tokenStream;
     767             :     TokenKind tk;
     768             :     while (true) {
     769           0 :         if (!ts.getToken(&tk, TokenStream::Operand))
     770           0 :             return false;
     771           0 :         if (tk != TOK_SEMI)
     772           0 :             break;
     773             :     }
     774           0 :     *tkp = tk;
     775           0 :     return true;
     776             : }
     777             : 
     778             : static bool
     779           0 : PeekToken(AsmJSParser& parser, TokenKind* tkp)
     780             : {
     781           0 :     TokenStream& ts = parser.tokenStream;
     782             :     TokenKind tk;
     783             :     while (true) {
     784           0 :         if (!ts.peekToken(&tk, TokenStream::Operand))
     785           0 :             return false;
     786           0 :         if (tk != TOK_SEMI)
     787           0 :             break;
     788           0 :         ts.consumeKnownToken(TOK_SEMI, TokenStream::Operand);
     789             :     }
     790           0 :     *tkp = tk;
     791           0 :     return true;
     792             : }
     793             : 
     794             : static bool
     795           0 : ParseVarOrConstStatement(AsmJSParser& parser, ParseNode** var)
     796             : {
     797             :     TokenKind tk;
     798           0 :     if (!PeekToken(parser, &tk))
     799           0 :         return false;
     800           0 :     if (tk != TOK_VAR && tk != TOK_CONST) {
     801           0 :         *var = nullptr;
     802           0 :         return true;
     803             :     }
     804             : 
     805           0 :     *var = parser.statementListItem(YieldIsName);
     806           0 :     if (!*var)
     807           0 :         return false;
     808             : 
     809           0 :     MOZ_ASSERT((*var)->isKind(PNK_VAR) || (*var)->isKind(PNK_CONST));
     810           0 :     return true;
     811             : }
     812             : 
     813             : /*****************************************************************************/
     814             : 
     815             : // Represents the type and value of an asm.js numeric literal.
     816             : //
     817             : // A literal is a double iff the literal contains a decimal point (even if the
     818             : // fractional part is 0). Otherwise, integers may be classified:
     819             : //  fixnum: [0, 2^31)
     820             : //  negative int: [-2^31, 0)
     821             : //  big unsigned: [2^31, 2^32)
     822             : //  out of range: otherwise
     823             : // Lastly, a literal may be a float literal which is any double or integer
     824             : // literal coerced with Math.fround.
     825             : //
     826             : // This class distinguishes between signed and unsigned integer SIMD types like
     827             : // Int32x4 and Uint32x4, and so does Type below. The wasm ValType and ExprType
     828             : // enums, and the wasm::Val class do not.
     829             : class NumLit
     830             : {
     831             :   public:
     832             :     enum Which {
     833             :         Fixnum,
     834             :         NegativeInt,
     835             :         BigUnsigned,
     836             :         Double,
     837             :         Float,
     838             :         Int8x16,
     839             :         Int16x8,
     840             :         Int32x4,
     841             :         Uint8x16,
     842             :         Uint16x8,
     843             :         Uint32x4,
     844             :         Float32x4,
     845             :         Bool8x16,
     846             :         Bool16x8,
     847             :         Bool32x4,
     848             :         OutOfRangeInt = -1
     849             :     };
     850             : 
     851             :   private:
     852             :     Which which_;
     853           0 :     union {
     854             :         Value scalar_;
     855             :         SimdConstant simd_;
     856             :     } u;
     857             : 
     858             :   public:
     859           0 :     NumLit() = default;
     860             : 
     861           0 :     NumLit(Which w, const Value& v) : which_(w) {
     862           0 :         u.scalar_ = v;
     863           0 :         MOZ_ASSERT(!isSimd());
     864           0 :     }
     865             : 
     866           0 :     NumLit(Which w, SimdConstant c) : which_(w) {
     867           0 :         u.simd_ = c;
     868           0 :         MOZ_ASSERT(isSimd());
     869           0 :     }
     870             : 
     871           0 :     Which which() const {
     872           0 :         return which_;
     873             :     }
     874             : 
     875           0 :     int32_t toInt32() const {
     876           0 :         MOZ_ASSERT(which_ == Fixnum || which_ == NegativeInt || which_ == BigUnsigned);
     877           0 :         return u.scalar_.toInt32();
     878             :     }
     879             : 
     880           0 :     uint32_t toUint32() const {
     881           0 :         return (uint32_t)toInt32();
     882             :     }
     883             : 
     884           0 :     double toDouble() const {
     885           0 :         MOZ_ASSERT(which_ == Double);
     886           0 :         return u.scalar_.toDouble();
     887             :     }
     888             : 
     889           0 :     float toFloat() const {
     890           0 :         MOZ_ASSERT(which_ == Float);
     891           0 :         return float(u.scalar_.toDouble());
     892             :     }
     893             : 
     894             :     Value scalarValue() const {
     895             :         MOZ_ASSERT(which_ != OutOfRangeInt);
     896             :         return u.scalar_;
     897             :     }
     898             : 
     899           0 :     bool isSimd() const
     900             :     {
     901           0 :         return which_ == Int8x16 || which_ == Uint8x16 || which_ == Int16x8 ||
     902           0 :                which_ == Uint16x8 || which_ == Int32x4 || which_ == Uint32x4 ||
     903           0 :                which_ == Float32x4 || which_ == Bool8x16 || which_ == Bool16x8 ||
     904           0 :                which_ == Bool32x4;
     905             :     }
     906             : 
     907           0 :     const SimdConstant& simdValue() const {
     908           0 :         MOZ_ASSERT(isSimd());
     909           0 :         return u.simd_;
     910             :     }
     911             : 
     912           0 :     bool valid() const {
     913           0 :         return which_ != OutOfRangeInt;
     914             :     }
     915             : 
     916           0 :     bool isZeroBits() const {
     917           0 :         MOZ_ASSERT(valid());
     918           0 :         switch (which()) {
     919             :           case NumLit::Fixnum:
     920             :           case NumLit::NegativeInt:
     921             :           case NumLit::BigUnsigned:
     922           0 :             return toInt32() == 0;
     923             :           case NumLit::Double:
     924           0 :             return IsPositiveZero(toDouble());
     925             :           case NumLit::Float:
     926           0 :             return IsPositiveZero(toFloat());
     927             :           case NumLit::Int8x16:
     928             :           case NumLit::Uint8x16:
     929             :           case NumLit::Bool8x16:
     930           0 :             return simdValue() == SimdConstant::SplatX16(0);
     931             :           case NumLit::Int16x8:
     932             :           case NumLit::Uint16x8:
     933             :           case NumLit::Bool16x8:
     934           0 :             return simdValue() == SimdConstant::SplatX8(0);
     935             :           case NumLit::Int32x4:
     936             :           case NumLit::Uint32x4:
     937             :           case NumLit::Bool32x4:
     938           0 :             return simdValue() == SimdConstant::SplatX4(0);
     939             :           case NumLit::Float32x4:
     940           0 :             return simdValue() == SimdConstant::SplatX4(0.f);
     941             :           case NumLit::OutOfRangeInt:
     942           0 :             MOZ_CRASH("can't be here because of valid() check above");
     943             :         }
     944           0 :         return false;
     945             :     }
     946             : 
     947           0 :     Val value() const {
     948           0 :         switch (which_) {
     949             :           case NumLit::Fixnum:
     950             :           case NumLit::NegativeInt:
     951             :           case NumLit::BigUnsigned:
     952           0 :             return Val(toUint32());
     953             :           case NumLit::Float:
     954           0 :             return Val(toFloat());
     955             :           case NumLit::Double:
     956           0 :             return Val(toDouble());
     957             :           case NumLit::Int8x16:
     958             :           case NumLit::Uint8x16:
     959           0 :             return Val(simdValue().asInt8x16());
     960             :           case NumLit::Int16x8:
     961             :           case NumLit::Uint16x8:
     962           0 :             return Val(simdValue().asInt16x8());
     963             :           case NumLit::Int32x4:
     964             :           case NumLit::Uint32x4:
     965           0 :             return Val(simdValue().asInt32x4());
     966             :           case NumLit::Float32x4:
     967           0 :             return Val(simdValue().asFloat32x4());
     968             :           case NumLit::Bool8x16:
     969           0 :             return Val(simdValue().asInt8x16(), ValType::B8x16);
     970             :           case NumLit::Bool16x8:
     971           0 :             return Val(simdValue().asInt16x8(), ValType::B16x8);
     972             :           case NumLit::Bool32x4:
     973           0 :             return Val(simdValue().asInt32x4(), ValType::B32x4);
     974             :           case NumLit::OutOfRangeInt:;
     975             :         }
     976           0 :         MOZ_CRASH("bad literal");
     977             :     }
     978             : };
     979             : 
     980             : // Represents the type of a general asm.js expression.
     981             : //
     982             : // A canonical subset of types representing the coercion targets: Int, Float,
     983             : // Double, and the SIMD types. This is almost equivalent to wasm::ValType,
     984             : // except the integer SIMD types have signed/unsigned variants.
     985             : //
     986             : // Void is also part of the canonical subset which then maps to wasm::ExprType.
     987             : //
     988             : // Note that while the canonical subset distinguishes signed and unsigned SIMD
     989             : // types, it only uses |Int| to represent signed and unsigned 32-bit integers.
     990             : // This is because the scalar coersions x|0 and x>>>0 work with any kind of
     991             : // integer input, while the SIMD check functions throw a TypeError if the passed
     992             : // type doesn't match.
     993             : //
     994             : class Type
     995             : {
     996             :   public:
     997             :     enum Which {
     998             :         Fixnum = NumLit::Fixnum,
     999             :         Signed = NumLit::NegativeInt,
    1000             :         Unsigned = NumLit::BigUnsigned,
    1001             :         DoubleLit = NumLit::Double,
    1002             :         Float = NumLit::Float,
    1003             :         Int8x16 = NumLit::Int8x16,
    1004             :         Int16x8 = NumLit::Int16x8,
    1005             :         Int32x4 = NumLit::Int32x4,
    1006             :         Uint8x16 = NumLit::Uint8x16,
    1007             :         Uint16x8 = NumLit::Uint16x8,
    1008             :         Uint32x4 = NumLit::Uint32x4,
    1009             :         Float32x4 = NumLit::Float32x4,
    1010             :         Bool8x16 = NumLit::Bool8x16,
    1011             :         Bool16x8 = NumLit::Bool16x8,
    1012             :         Bool32x4 = NumLit::Bool32x4,
    1013             :         Double,
    1014             :         MaybeDouble,
    1015             :         MaybeFloat,
    1016             :         Floatish,
    1017             :         Int,
    1018             :         Intish,
    1019             :         Void
    1020             :     };
    1021             : 
    1022             :   private:
    1023             :     Which which_;
    1024             : 
    1025             :   public:
    1026           0 :     Type() = default;
    1027           0 :     MOZ_IMPLICIT Type(Which w) : which_(w) {}
    1028           0 :     MOZ_IMPLICIT Type(SimdType type) {
    1029           0 :         switch (type) {
    1030           0 :           case SimdType::Int8x16:   which_ = Int8x16;   return;
    1031           0 :           case SimdType::Int16x8:   which_ = Int16x8;   return;
    1032           0 :           case SimdType::Int32x4:   which_ = Int32x4;   return;
    1033           0 :           case SimdType::Uint8x16:  which_ = Uint8x16;  return;
    1034           0 :           case SimdType::Uint16x8:  which_ = Uint16x8;  return;
    1035           0 :           case SimdType::Uint32x4:  which_ = Uint32x4;  return;
    1036           0 :           case SimdType::Float32x4: which_ = Float32x4; return;
    1037           0 :           case SimdType::Bool8x16:  which_ = Bool8x16;  return;
    1038           0 :           case SimdType::Bool16x8:  which_ = Bool16x8;  return;
    1039           0 :           case SimdType::Bool32x4:  which_ = Bool32x4;  return;
    1040           0 :           default:                  break;
    1041             :         }
    1042           0 :         MOZ_MAKE_COMPILER_ASSUME_IS_UNREACHABLE("bad SimdType");
    1043             :     }
    1044             : 
    1045             :     // Map an already canonicalized Type to the return type of a function call.
    1046           0 :     static Type ret(Type t) {
    1047           0 :         MOZ_ASSERT(t.isCanonical());
    1048             :         // The 32-bit external type is Signed, not Int.
    1049           0 :         return t.isInt() ? Signed: t;
    1050             :     }
    1051             : 
    1052           0 :     static Type lit(const NumLit& lit) {
    1053           0 :         MOZ_ASSERT(lit.valid());
    1054           0 :         Which which = Type::Which(lit.which());
    1055           0 :         MOZ_ASSERT(which >= Fixnum && which <= Bool32x4);
    1056           0 :         Type t;
    1057           0 :         t.which_ = which;
    1058           0 :         return t;
    1059             :     }
    1060             : 
    1061             :     // Map |t| to one of the canonical vartype representations of a
    1062             :     // wasm::ExprType.
    1063           0 :     static Type canonicalize(Type t) {
    1064           0 :         switch(t.which()) {
    1065             :           case Fixnum:
    1066             :           case Signed:
    1067             :           case Unsigned:
    1068             :           case Int:
    1069           0 :             return Int;
    1070             : 
    1071             :           case Float:
    1072           0 :             return Float;
    1073             : 
    1074             :           case DoubleLit:
    1075             :           case Double:
    1076           0 :             return Double;
    1077             : 
    1078             :           case Void:
    1079           0 :             return Void;
    1080             : 
    1081             :           case Int8x16:
    1082             :           case Int16x8:
    1083             :           case Int32x4:
    1084             :           case Uint8x16:
    1085             :           case Uint16x8:
    1086             :           case Uint32x4:
    1087             :           case Float32x4:
    1088             :           case Bool8x16:
    1089             :           case Bool16x8:
    1090             :           case Bool32x4:
    1091           0 :             return t;
    1092             : 
    1093             :           case MaybeDouble:
    1094             :           case MaybeFloat:
    1095             :           case Floatish:
    1096             :           case Intish:
    1097             :             // These types need some kind of coercion, they can't be mapped
    1098             :             // to an ExprType.
    1099           0 :             break;
    1100             :         }
    1101           0 :         MOZ_CRASH("Invalid vartype");
    1102             :     }
    1103             : 
    1104           0 :     Which which() const { return which_; }
    1105             : 
    1106           0 :     bool operator==(Type rhs) const { return which_ == rhs.which_; }
    1107           0 :     bool operator!=(Type rhs) const { return which_ != rhs.which_; }
    1108             : 
    1109           0 :     bool operator<=(Type rhs) const {
    1110           0 :         switch (rhs.which_) {
    1111           0 :           case Signed:      return isSigned();
    1112           0 :           case Unsigned:    return isUnsigned();
    1113           0 :           case DoubleLit:   return isDoubleLit();
    1114           0 :           case Double:      return isDouble();
    1115           0 :           case Float:       return isFloat();
    1116           0 :           case Int8x16:     return isInt8x16();
    1117           0 :           case Int16x8:     return isInt16x8();
    1118           0 :           case Int32x4:     return isInt32x4();
    1119           0 :           case Uint8x16:    return isUint8x16();
    1120           0 :           case Uint16x8:    return isUint16x8();
    1121           0 :           case Uint32x4:    return isUint32x4();
    1122           0 :           case Float32x4:   return isFloat32x4();
    1123           0 :           case Bool8x16:    return isBool8x16();
    1124           0 :           case Bool16x8:    return isBool16x8();
    1125           0 :           case Bool32x4:    return isBool32x4();
    1126           0 :           case MaybeDouble: return isMaybeDouble();
    1127           0 :           case MaybeFloat:  return isMaybeFloat();
    1128           0 :           case Floatish:    return isFloatish();
    1129           0 :           case Int:         return isInt();
    1130           0 :           case Intish:      return isIntish();
    1131           0 :           case Fixnum:      return isFixnum();
    1132           0 :           case Void:        return isVoid();
    1133             :         }
    1134           0 :         MOZ_MAKE_COMPILER_ASSUME_IS_UNREACHABLE("unexpected rhs type");
    1135             :     }
    1136             : 
    1137           0 :     bool isFixnum() const {
    1138           0 :         return which_ == Fixnum;
    1139             :     }
    1140             : 
    1141           0 :     bool isSigned() const {
    1142           0 :         return which_ == Signed || which_ == Fixnum;
    1143             :     }
    1144             : 
    1145           0 :     bool isUnsigned() const {
    1146           0 :         return which_ == Unsigned || which_ == Fixnum;
    1147             :     }
    1148             : 
    1149           0 :     bool isInt() const {
    1150           0 :         return isSigned() || isUnsigned() || which_ == Int;
    1151             :     }
    1152             : 
    1153           0 :     bool isIntish() const {
    1154           0 :         return isInt() || which_ == Intish;
    1155             :     }
    1156             : 
    1157           0 :     bool isDoubleLit() const {
    1158           0 :         return which_ == DoubleLit;
    1159             :     }
    1160             : 
    1161           0 :     bool isDouble() const {
    1162           0 :         return isDoubleLit() || which_ == Double;
    1163             :     }
    1164             : 
    1165           0 :     bool isMaybeDouble() const {
    1166           0 :         return isDouble() || which_ == MaybeDouble;
    1167             :     }
    1168             : 
    1169           0 :     bool isFloat() const {
    1170           0 :         return which_ == Float;
    1171             :     }
    1172             : 
    1173           0 :     bool isMaybeFloat() const {
    1174           0 :         return isFloat() || which_ == MaybeFloat;
    1175             :     }
    1176             : 
    1177           0 :     bool isFloatish() const {
    1178           0 :         return isMaybeFloat() || which_ == Floatish;
    1179             :     }
    1180             : 
    1181           0 :     bool isVoid() const {
    1182           0 :         return which_ == Void;
    1183             :     }
    1184             : 
    1185           0 :     bool isExtern() const {
    1186           0 :         return isDouble() || isSigned();
    1187             :     }
    1188             : 
    1189           0 :     bool isInt8x16() const {
    1190           0 :         return which_ == Int8x16;
    1191             :     }
    1192             : 
    1193           0 :     bool isInt16x8() const {
    1194           0 :         return which_ == Int16x8;
    1195             :     }
    1196             : 
    1197           0 :     bool isInt32x4() const {
    1198           0 :         return which_ == Int32x4;
    1199             :     }
    1200             : 
    1201           0 :     bool isUint8x16() const {
    1202           0 :         return which_ == Uint8x16;
    1203             :     }
    1204             : 
    1205           0 :     bool isUint16x8() const {
    1206           0 :         return which_ == Uint16x8;
    1207             :     }
    1208             : 
    1209           0 :     bool isUint32x4() const {
    1210           0 :         return which_ == Uint32x4;
    1211             :     }
    1212             : 
    1213           0 :     bool isFloat32x4() const {
    1214           0 :         return which_ == Float32x4;
    1215             :     }
    1216             : 
    1217           0 :     bool isBool8x16() const {
    1218           0 :         return which_ == Bool8x16;
    1219             :     }
    1220             : 
    1221           0 :     bool isBool16x8() const {
    1222           0 :         return which_ == Bool16x8;
    1223             :     }
    1224             : 
    1225           0 :     bool isBool32x4() const {
    1226           0 :         return which_ == Bool32x4;
    1227             :     }
    1228             : 
    1229           0 :     bool isSimd() const {
    1230           0 :         return isInt8x16() || isInt16x8() || isInt32x4() || isUint8x16() || isUint16x8() ||
    1231           0 :                isUint32x4() || isFloat32x4() || isBool8x16() || isBool16x8() || isBool32x4();
    1232             :     }
    1233             : 
    1234           0 :     bool isUnsignedSimd() const {
    1235           0 :         return isUint8x16() || isUint16x8() || isUint32x4();
    1236             :     }
    1237             : 
    1238             :     // Check if this is one of the valid types for a function argument.
    1239           0 :     bool isArgType() const {
    1240           0 :         return isInt() || isFloat() || isDouble() || (isSimd() && !isUnsignedSimd());
    1241             :     }
    1242             : 
    1243             :     // Check if this is one of the valid types for a function return value.
    1244           0 :     bool isReturnType() const {
    1245           0 :         return isSigned() || isFloat() || isDouble() || (isSimd() && !isUnsignedSimd()) ||
    1246           0 :                isVoid();
    1247             :     }
    1248             : 
    1249             :     // Check if this is one of the valid types for a global variable.
    1250           0 :     bool isGlobalVarType() const {
    1251           0 :         return isArgType();
    1252             :     }
    1253             : 
    1254             :     // Check if this is one of the canonical vartype representations of a
    1255             :     // wasm::ExprType. See Type::canonicalize().
    1256           0 :     bool isCanonical() const {
    1257           0 :         switch (which()) {
    1258             :           case Int:
    1259             :           case Float:
    1260             :           case Double:
    1261             :           case Void:
    1262           0 :             return true;
    1263             :           default:
    1264           0 :             return isSimd();
    1265             :         }
    1266             :     }
    1267             : 
    1268             :     // Check if this is a canonical representation of a wasm::ValType.
    1269           0 :     bool isCanonicalValType() const {
    1270           0 :         return !isVoid() && isCanonical();
    1271             :     }
    1272             : 
    1273             :     // Convert this canonical type to a wasm::ExprType.
    1274           0 :     ExprType canonicalToExprType() const {
    1275           0 :         switch (which()) {
    1276           0 :           case Int:       return ExprType::I32;
    1277           0 :           case Float:     return ExprType::F32;
    1278           0 :           case Double:    return ExprType::F64;
    1279           0 :           case Void:      return ExprType::Void;
    1280             :           case Uint8x16:
    1281           0 :           case Int8x16:   return ExprType::I8x16;
    1282             :           case Uint16x8:
    1283           0 :           case Int16x8:   return ExprType::I16x8;
    1284             :           case Uint32x4:
    1285           0 :           case Int32x4:   return ExprType::I32x4;
    1286           0 :           case Float32x4: return ExprType::F32x4;
    1287           0 :           case Bool8x16:  return ExprType::B8x16;
    1288           0 :           case Bool16x8:  return ExprType::B16x8;
    1289           0 :           case Bool32x4:  return ExprType::B32x4;
    1290           0 :           default:        MOZ_CRASH("Need canonical type");
    1291             :         }
    1292             :     }
    1293             : 
    1294             :     // Convert this canonical type to a wasm::ValType.
    1295           0 :     ValType canonicalToValType() const {
    1296           0 :         return NonVoidToValType(canonicalToExprType());
    1297             :     }
    1298             : 
    1299             :     // Convert this type to a wasm::ExprType for use in a wasm
    1300             :     // block signature. This works for all types, including non-canonical
    1301             :     // ones. Consequently, the type isn't valid for subsequent asm.js
    1302             :     // validation; it's only valid for use in producing wasm.
    1303           0 :     ExprType toWasmBlockSignatureType() const {
    1304           0 :         switch (which()) {
    1305             :           case Fixnum:
    1306             :           case Signed:
    1307             :           case Unsigned:
    1308             :           case Int:
    1309             :           case Intish:
    1310           0 :             return ExprType::I32;
    1311             : 
    1312             :           case Float:
    1313             :           case MaybeFloat:
    1314             :           case Floatish:
    1315           0 :             return ExprType::F32;
    1316             : 
    1317             :           case DoubleLit:
    1318             :           case Double:
    1319             :           case MaybeDouble:
    1320           0 :             return ExprType::F64;
    1321             : 
    1322             :           case Void:
    1323           0 :             return ExprType::Void;
    1324             : 
    1325             :           case Uint8x16:
    1326           0 :           case Int8x16:   return ExprType::I8x16;
    1327             :           case Uint16x8:
    1328           0 :           case Int16x8:   return ExprType::I16x8;
    1329             :           case Uint32x4:
    1330           0 :           case Int32x4:   return ExprType::I32x4;
    1331           0 :           case Float32x4: return ExprType::F32x4;
    1332           0 :           case Bool8x16:  return ExprType::B8x16;
    1333           0 :           case Bool16x8:  return ExprType::B16x8;
    1334           0 :           case Bool32x4:  return ExprType::B32x4;
    1335             :         }
    1336           0 :         MOZ_CRASH("Invalid Type");
    1337             :     }
    1338             : 
    1339           0 :     const char* toChars() const {
    1340           0 :         switch (which_) {
    1341           0 :           case Double:      return "double";
    1342           0 :           case DoubleLit:   return "doublelit";
    1343           0 :           case MaybeDouble: return "double?";
    1344           0 :           case Float:       return "float";
    1345           0 :           case Floatish:    return "floatish";
    1346           0 :           case MaybeFloat:  return "float?";
    1347           0 :           case Fixnum:      return "fixnum";
    1348           0 :           case Int:         return "int";
    1349           0 :           case Signed:      return "signed";
    1350           0 :           case Unsigned:    return "unsigned";
    1351           0 :           case Intish:      return "intish";
    1352           0 :           case Int8x16:     return "int8x16";
    1353           0 :           case Int16x8:     return "int16x8";
    1354           0 :           case Int32x4:     return "int32x4";
    1355           0 :           case Uint8x16:    return "uint8x16";
    1356           0 :           case Uint16x8:    return "uint16x8";
    1357           0 :           case Uint32x4:    return "uint32x4";
    1358           0 :           case Float32x4:   return "float32x4";
    1359           0 :           case Bool8x16:    return "bool8x16";
    1360           0 :           case Bool16x8:    return "bool16x8";
    1361           0 :           case Bool32x4:    return "bool32x4";
    1362           0 :           case Void:        return "void";
    1363             :         }
    1364           0 :         MOZ_CRASH("Invalid Type");
    1365             :     }
    1366             : };
    1367             : 
    1368             : static const unsigned VALIDATION_LIFO_DEFAULT_CHUNK_SIZE = 4 * 1024;
    1369             : 
    1370             : // The ModuleValidator encapsulates the entire validation of an asm.js module.
    1371             : // Its lifetime goes from the validation of the top components of an asm.js
    1372             : // module (all the globals), the emission of bytecode for all the functions in
    1373             : // the module and the validation of function's pointer tables. It also finishes
    1374             : // the compilation of all the module's stubs.
    1375             : //
    1376             : // Rooting note: ModuleValidator is a stack class that contains unrooted
    1377             : // PropertyName (JSAtom) pointers.  This is safe because it cannot be
    1378             : // constructed without a TokenStream reference.  TokenStream is itself a stack
    1379             : // class that cannot be constructed without an AutoKeepAtoms being live on the
    1380             : // stack, which prevents collection of atoms.
    1381             : //
    1382             : // ModuleValidator is marked as rooted in the rooting analysis.  Don't add
    1383             : // non-JSAtom pointers, or this will break!
    1384             : class MOZ_STACK_CLASS ModuleValidator
    1385             : {
    1386             :   public:
    1387             :     class Func
    1388             :     {
    1389             :         PropertyName* name_;
    1390             :         uint32_t firstUse_;
    1391             :         uint32_t index_;
    1392             :         uint32_t srcBegin_;
    1393             :         uint32_t srcEnd_;
    1394             :         bool defined_;
    1395             : 
    1396             :       public:
    1397           0 :         Func(PropertyName* name, uint32_t firstUse, uint32_t index)
    1398           0 :           : name_(name), firstUse_(firstUse), index_(index),
    1399           0 :             srcBegin_(0), srcEnd_(0), defined_(false)
    1400           0 :         {}
    1401             : 
    1402           0 :         PropertyName* name() const { return name_; }
    1403           0 :         uint32_t firstUse() const { return firstUse_; }
    1404           0 :         bool defined() const { return defined_; }
    1405           0 :         uint32_t index() const { return index_; }
    1406             : 
    1407           0 :         void define(ParseNode* fn) {
    1408           0 :             MOZ_ASSERT(!defined_);
    1409           0 :             defined_ = true;
    1410           0 :             srcBegin_ = fn->pn_pos.begin;
    1411           0 :             srcEnd_ = fn->pn_pos.end;
    1412           0 :         }
    1413             : 
    1414           0 :         uint32_t srcBegin() const { MOZ_ASSERT(defined_); return srcBegin_; }
    1415           0 :         uint32_t srcEnd() const { MOZ_ASSERT(defined_); return srcEnd_; }
    1416             :     };
    1417             : 
    1418             :     typedef Vector<const Func*> ConstFuncVector;
    1419             :     typedef Vector<Func*> FuncVector;
    1420             : 
    1421             :     class FuncPtrTable
    1422             :     {
    1423             :         uint32_t sigIndex_;
    1424             :         PropertyName* name_;
    1425             :         uint32_t firstUse_;
    1426             :         uint32_t mask_;
    1427             :         bool defined_;
    1428             : 
    1429             :         FuncPtrTable(FuncPtrTable&& rhs) = delete;
    1430             : 
    1431             :       public:
    1432           0 :         FuncPtrTable(uint32_t sigIndex, PropertyName* name, uint32_t firstUse, uint32_t mask)
    1433           0 :           : sigIndex_(sigIndex), name_(name), firstUse_(firstUse), mask_(mask), defined_(false)
    1434           0 :         {}
    1435             : 
    1436           0 :         uint32_t sigIndex() const { return sigIndex_; }
    1437           0 :         PropertyName* name() const { return name_; }
    1438           0 :         uint32_t firstUse() const { return firstUse_; }
    1439           0 :         unsigned mask() const { return mask_; }
    1440           0 :         bool defined() const { return defined_; }
    1441           0 :         void define() { MOZ_ASSERT(!defined_); defined_ = true; }
    1442             :     };
    1443             : 
    1444             :     typedef Vector<FuncPtrTable*> FuncPtrTableVector;
    1445             : 
    1446             :     class Global
    1447             :     {
    1448             :       public:
    1449             :         enum Which {
    1450             :             Variable,
    1451             :             ConstantLiteral,
    1452             :             ConstantImport,
    1453             :             Function,
    1454             :             FuncPtrTable,
    1455             :             FFI,
    1456             :             ArrayView,
    1457             :             ArrayViewCtor,
    1458             :             MathBuiltinFunction,
    1459             :             AtomicsBuiltinFunction,
    1460             :             SimdCtor,
    1461             :             SimdOp
    1462             :         };
    1463             : 
    1464             :       private:
    1465             :         Which which_;
    1466           0 :         union {
    1467             :             struct {
    1468             :                 Type::Which type_;
    1469             :                 unsigned index_;
    1470             :                 NumLit literalValue_;
    1471             :             } varOrConst;
    1472             :             uint32_t funcIndex_;
    1473             :             uint32_t funcPtrTableIndex_;
    1474             :             uint32_t ffiIndex_;
    1475             :             struct {
    1476             :                 Scalar::Type viewType_;
    1477             :             } viewInfo;
    1478             :             AsmJSMathBuiltinFunction mathBuiltinFunc_;
    1479             :             AsmJSAtomicsBuiltinFunction atomicsBuiltinFunc_;
    1480             :             SimdType simdCtorType_;
    1481             :             struct {
    1482             :                 SimdType type_;
    1483             :                 SimdOperation which_;
    1484             :             } simdOp;
    1485             :         } u;
    1486             : 
    1487             :         friend class ModuleValidator;
    1488             :         friend class js::LifoAlloc;
    1489             : 
    1490           0 :         explicit Global(Which which) : which_(which) {}
    1491             : 
    1492             :       public:
    1493           0 :         Which which() const {
    1494           0 :             return which_;
    1495             :         }
    1496           0 :         Type varOrConstType() const {
    1497           0 :             MOZ_ASSERT(which_ == Variable || which_ == ConstantLiteral || which_ == ConstantImport);
    1498           0 :             return u.varOrConst.type_;
    1499             :         }
    1500           0 :         unsigned varOrConstIndex() const {
    1501           0 :             MOZ_ASSERT(which_ == Variable || which_ == ConstantImport);
    1502           0 :             return u.varOrConst.index_;
    1503             :         }
    1504             :         bool isConst() const {
    1505             :             return which_ == ConstantLiteral || which_ == ConstantImport;
    1506             :         }
    1507           0 :         NumLit constLiteralValue() const {
    1508           0 :             MOZ_ASSERT(which_ == ConstantLiteral);
    1509           0 :             return u.varOrConst.literalValue_;
    1510             :         }
    1511           0 :         uint32_t funcIndex() const {
    1512           0 :             MOZ_ASSERT(which_ == Function);
    1513           0 :             return u.funcIndex_;
    1514             :         }
    1515           0 :         uint32_t funcPtrTableIndex() const {
    1516           0 :             MOZ_ASSERT(which_ == FuncPtrTable);
    1517           0 :             return u.funcPtrTableIndex_;
    1518             :         }
    1519           0 :         unsigned ffiIndex() const {
    1520           0 :             MOZ_ASSERT(which_ == FFI);
    1521           0 :             return u.ffiIndex_;
    1522             :         }
    1523           0 :         bool isAnyArrayView() const {
    1524           0 :             return which_ == ArrayView || which_ == ArrayViewCtor;
    1525             :         }
    1526           0 :         Scalar::Type viewType() const {
    1527           0 :             MOZ_ASSERT(isAnyArrayView());
    1528           0 :             return u.viewInfo.viewType_;
    1529             :         }
    1530           0 :         bool isMathFunction() const {
    1531           0 :             return which_ == MathBuiltinFunction;
    1532             :         }
    1533           0 :         AsmJSMathBuiltinFunction mathBuiltinFunction() const {
    1534           0 :             MOZ_ASSERT(which_ == MathBuiltinFunction);
    1535           0 :             return u.mathBuiltinFunc_;
    1536             :         }
    1537           0 :         bool isAtomicsFunction() const {
    1538           0 :             return which_ == AtomicsBuiltinFunction;
    1539             :         }
    1540           0 :         AsmJSAtomicsBuiltinFunction atomicsBuiltinFunction() const {
    1541           0 :             MOZ_ASSERT(which_ == AtomicsBuiltinFunction);
    1542           0 :             return u.atomicsBuiltinFunc_;
    1543             :         }
    1544           0 :         bool isSimdCtor() const {
    1545           0 :             return which_ == SimdCtor;
    1546             :         }
    1547           0 :         SimdType simdCtorType() const {
    1548           0 :             MOZ_ASSERT(which_ == SimdCtor);
    1549           0 :             return u.simdCtorType_;
    1550             :         }
    1551           0 :         bool isSimdOperation() const {
    1552           0 :             return which_ == SimdOp;
    1553             :         }
    1554           0 :         SimdOperation simdOperation() const {
    1555           0 :             MOZ_ASSERT(which_ == SimdOp);
    1556           0 :             return u.simdOp.which_;
    1557             :         }
    1558           0 :         SimdType simdOperationType() const {
    1559           0 :             MOZ_ASSERT(which_ == SimdOp);
    1560           0 :             return u.simdOp.type_;
    1561             :         }
    1562             :     };
    1563             : 
    1564             :     struct MathBuiltin
    1565             :     {
    1566             :         enum Kind { Function, Constant };
    1567             :         Kind kind;
    1568             : 
    1569             :         union {
    1570             :             double cst;
    1571             :             AsmJSMathBuiltinFunction func;
    1572             :         } u;
    1573             : 
    1574           0 :         MathBuiltin() : kind(Kind(-1)) {}
    1575           0 :         explicit MathBuiltin(double cst) : kind(Constant) {
    1576           0 :             u.cst = cst;
    1577           0 :         }
    1578           0 :         explicit MathBuiltin(AsmJSMathBuiltinFunction func) : kind(Function) {
    1579           0 :             u.func = func;
    1580           0 :         }
    1581             :     };
    1582             : 
    1583             :     struct ArrayView
    1584             :     {
    1585           0 :         ArrayView(PropertyName* name, Scalar::Type type)
    1586           0 :           : name(name), type(type)
    1587           0 :         {}
    1588             : 
    1589             :         PropertyName* name;
    1590             :         Scalar::Type type;
    1591             :     };
    1592             : 
    1593             :   private:
    1594             :     class NamedSig
    1595             :     {
    1596             :         PropertyName* name_;
    1597             :         const SigWithId* sig_;
    1598             : 
    1599             :       public:
    1600           0 :         NamedSig(PropertyName* name, const SigWithId& sig)
    1601           0 :           : name_(name), sig_(&sig)
    1602           0 :         {}
    1603             :         PropertyName* name() const {
    1604             :             return name_;
    1605             :         }
    1606             :         const Sig& sig() const {
    1607             :             return *sig_;
    1608             :         }
    1609             : 
    1610             :         // Implement HashPolicy:
    1611             :         struct Lookup {
    1612             :             PropertyName* name;
    1613             :             const Sig& sig;
    1614           0 :             Lookup(PropertyName* name, const Sig& sig) : name(name), sig(sig) {}
    1615             :         };
    1616           0 :         static HashNumber hash(Lookup l) {
    1617           0 :             return HashGeneric(l.name, l.sig.hash());
    1618             :         }
    1619           0 :         static bool match(NamedSig lhs, Lookup rhs) {
    1620           0 :             return lhs.name_ == rhs.name && *lhs.sig_ == rhs.sig;
    1621             :         }
    1622             :     };
    1623             :     typedef HashMap<NamedSig, uint32_t, NamedSig> ImportMap;
    1624             :     typedef HashMap<const SigWithId*, uint32_t, SigHashPolicy> SigMap;
    1625             :     typedef HashMap<PropertyName*, Global*> GlobalMap;
    1626             :     typedef HashMap<PropertyName*, MathBuiltin> MathNameMap;
    1627             :     typedef HashMap<PropertyName*, AsmJSAtomicsBuiltinFunction> AtomicsNameMap;
    1628             :     typedef HashMap<PropertyName*, SimdOperation> SimdOperationNameMap;
    1629             :     typedef Vector<ArrayView> ArrayViewVector;
    1630             : 
    1631             :     JSContext*            cx_;
    1632             :     AsmJSParser&          parser_;
    1633             :     ParseNode*            moduleFunctionNode_;
    1634             :     PropertyName*         moduleFunctionName_;
    1635             :     PropertyName*         globalArgumentName_;
    1636             :     PropertyName*         importArgumentName_;
    1637             :     PropertyName*         bufferArgumentName_;
    1638             :     MathNameMap           standardLibraryMathNames_;
    1639             :     AtomicsNameMap        standardLibraryAtomicsNames_;
    1640             :     SimdOperationNameMap  standardLibrarySimdOpNames_;
    1641             :     RootedFunction        dummyFunction_;
    1642             : 
    1643             :     // Validation-internal state:
    1644             :     LifoAlloc             validationLifo_;
    1645             :     FuncVector            functions_;
    1646             :     FuncPtrTableVector    funcPtrTables_;
    1647             :     GlobalMap             globalMap_;
    1648             :     SigMap                sigMap_;
    1649             :     ImportMap             importMap_;
    1650             :     ArrayViewVector       arrayViews_;
    1651             :     bool                  atomicsPresent_;
    1652             :     bool                  simdPresent_;
    1653             : 
    1654             :     // State used to build the AsmJSModule in finish():
    1655             :     ModuleGenerator       mg_;
    1656             :     MutableAsmJSMetadata  asmJSMetadata_;
    1657             : 
    1658             :     // Error reporting:
    1659             :     UniqueChars           errorString_;
    1660             :     uint32_t              errorOffset_;
    1661             :     bool                  errorOverRecursed_;
    1662             : 
    1663             :     // Helpers:
    1664           0 :     bool addStandardLibraryMathName(const char* name, AsmJSMathBuiltinFunction func) {
    1665           0 :         JSAtom* atom = Atomize(cx_, name, strlen(name));
    1666           0 :         if (!atom)
    1667           0 :             return false;
    1668           0 :         MathBuiltin builtin(func);
    1669           0 :         return standardLibraryMathNames_.putNew(atom->asPropertyName(), builtin);
    1670             :     }
    1671           0 :     bool addStandardLibraryMathName(const char* name, double cst) {
    1672           0 :         JSAtom* atom = Atomize(cx_, name, strlen(name));
    1673           0 :         if (!atom)
    1674           0 :             return false;
    1675           0 :         MathBuiltin builtin(cst);
    1676           0 :         return standardLibraryMathNames_.putNew(atom->asPropertyName(), builtin);
    1677             :     }
    1678           0 :     bool addStandardLibraryAtomicsName(const char* name, AsmJSAtomicsBuiltinFunction func) {
    1679           0 :         JSAtom* atom = Atomize(cx_, name, strlen(name));
    1680           0 :         if (!atom)
    1681           0 :             return false;
    1682           0 :         return standardLibraryAtomicsNames_.putNew(atom->asPropertyName(), func);
    1683             :     }
    1684           0 :     bool addStandardLibrarySimdOpName(const char* name, SimdOperation op) {
    1685           0 :         JSAtom* atom = Atomize(cx_, name, strlen(name));
    1686           0 :         if (!atom)
    1687           0 :             return false;
    1688           0 :         return standardLibrarySimdOpNames_.putNew(atom->asPropertyName(), op);
    1689             :     }
    1690           0 :     bool newSig(Sig&& sig, uint32_t* sigIndex) {
    1691           0 :         *sigIndex = 0;
    1692           0 :         if (mg_.numSigs() >= AsmJSMaxTypes)
    1693           0 :             return failCurrentOffset("too many signatures");
    1694             : 
    1695           0 :         *sigIndex = mg_.numSigs();
    1696           0 :         mg_.initSig(*sigIndex, Move(sig));
    1697           0 :         return true;
    1698             :     }
    1699           0 :     bool declareSig(Sig&& sig, uint32_t* sigIndex) {
    1700           0 :         SigMap::AddPtr p = sigMap_.lookupForAdd(sig);
    1701           0 :         if (p) {
    1702           0 :             *sigIndex = p->value();
    1703           0 :             MOZ_ASSERT(mg_.sig(*sigIndex) == sig);
    1704           0 :             return true;
    1705             :         }
    1706             : 
    1707           0 :         return newSig(Move(sig), sigIndex) &&
    1708           0 :                sigMap_.add(p, &mg_.sig(*sigIndex), *sigIndex);
    1709             :     }
    1710             : 
    1711             :   public:
    1712           0 :     ModuleValidator(JSContext* cx, AsmJSParser& parser, ParseNode* moduleFunctionNode)
    1713           0 :       : cx_(cx),
    1714             :         parser_(parser),
    1715             :         moduleFunctionNode_(moduleFunctionNode),
    1716           0 :         moduleFunctionName_(FunctionName(moduleFunctionNode)),
    1717             :         globalArgumentName_(nullptr),
    1718             :         importArgumentName_(nullptr),
    1719             :         bufferArgumentName_(nullptr),
    1720             :         standardLibraryMathNames_(cx),
    1721             :         standardLibraryAtomicsNames_(cx),
    1722             :         standardLibrarySimdOpNames_(cx),
    1723             :         dummyFunction_(cx),
    1724             :         validationLifo_(VALIDATION_LIFO_DEFAULT_CHUNK_SIZE),
    1725             :         functions_(cx),
    1726             :         funcPtrTables_(cx),
    1727             :         globalMap_(cx),
    1728             :         sigMap_(cx),
    1729             :         importMap_(cx),
    1730             :         arrayViews_(cx),
    1731             :         atomicsPresent_(false),
    1732             :         simdPresent_(false),
    1733             :         mg_(nullptr),
    1734             :         errorString_(nullptr),
    1735             :         errorOffset_(UINT32_MAX),
    1736           0 :         errorOverRecursed_(false)
    1737           0 :     {}
    1738             : 
    1739           0 :     ~ModuleValidator() {
    1740           0 :         if (errorString_) {
    1741           0 :             MOZ_ASSERT(errorOffset_ != UINT32_MAX);
    1742           0 :             typeFailure(errorOffset_, errorString_.get());
    1743             :         }
    1744           0 :         if (errorOverRecursed_)
    1745           0 :             ReportOverRecursed(cx_);
    1746           0 :     }
    1747             : 
    1748             :   private:
    1749           0 :     void typeFailure(uint32_t offset, ...) {
    1750             :         va_list args;
    1751           0 :         va_start(args, offset);
    1752             : 
    1753           0 :         TokenStream& ts = tokenStream();
    1754           0 :         ErrorMetadata metadata;
    1755           0 :         if (ts.computeErrorMetadata(&metadata, offset)) {
    1756           0 :             if (ts.options().throwOnAsmJSValidationFailureOption) {
    1757           0 :                 ReportCompileError(cx_, Move(metadata), nullptr, JSREPORT_ERROR,
    1758           0 :                                    JSMSG_USE_ASM_TYPE_FAIL, args);
    1759             :             } else {
    1760             :                 // asm.js type failure is indicated by calling one of the fail*
    1761             :                 // functions below.  These functions always return false to
    1762             :                 // halt asm.js parsing.  Whether normal parsing is attempted as
    1763             :                 // fallback, depends whether an exception is also set.
    1764             :                 //
    1765             :                 // If warning succeeds, no exception is set.  If warning fails,
    1766             :                 // an exception is set and execution will halt.  Thus it's safe
    1767             :                 // and correct to ignore the return value here.
    1768           0 :                 Unused << ts.compileWarning(Move(metadata), nullptr, JSREPORT_WARNING,
    1769             :                                             JSMSG_USE_ASM_TYPE_FAIL, args);
    1770             :             }
    1771             :         }
    1772             : 
    1773           0 :         va_end(args);
    1774           0 :     }
    1775             : 
    1776             :   public:
    1777           0 :     bool init() {
    1778           0 :         auto tierMetadata = js::MakeUnique<MetadataTier>(Tier::Ion);
    1779           0 :         if (!tierMetadata)
    1780           0 :             return false;
    1781             : 
    1782           0 :         asmJSMetadata_ = cx_->new_<AsmJSMetadata>(Move(tierMetadata));
    1783           0 :         if (!asmJSMetadata_)
    1784           0 :             return false;
    1785             : 
    1786           0 :         asmJSMetadata_->toStringStart = moduleFunctionNode_->pn_funbox->toStringStart;
    1787           0 :         asmJSMetadata_->srcStart = moduleFunctionNode_->pn_body->pn_pos.begin;
    1788           0 :         asmJSMetadata_->srcBodyStart = parser_.tokenStream.currentToken().pos.end;
    1789           0 :         asmJSMetadata_->strict = parser_.pc->sc()->strict() &&
    1790           0 :                                  !parser_.pc->sc()->hasExplicitUseStrict();
    1791           0 :         asmJSMetadata_->scriptSource.reset(parser_.ss);
    1792             : 
    1793           0 :         if (!globalMap_.init() || !sigMap_.init() || !importMap_.init())
    1794           0 :             return false;
    1795             : 
    1796           0 :         if (!standardLibraryMathNames_.init() ||
    1797           0 :             !addStandardLibraryMathName("sin", AsmJSMathBuiltin_sin) ||
    1798           0 :             !addStandardLibraryMathName("cos", AsmJSMathBuiltin_cos) ||
    1799           0 :             !addStandardLibraryMathName("tan", AsmJSMathBuiltin_tan) ||
    1800           0 :             !addStandardLibraryMathName("asin", AsmJSMathBuiltin_asin) ||
    1801           0 :             !addStandardLibraryMathName("acos", AsmJSMathBuiltin_acos) ||
    1802           0 :             !addStandardLibraryMathName("atan", AsmJSMathBuiltin_atan) ||
    1803           0 :             !addStandardLibraryMathName("ceil", AsmJSMathBuiltin_ceil) ||
    1804           0 :             !addStandardLibraryMathName("floor", AsmJSMathBuiltin_floor) ||
    1805           0 :             !addStandardLibraryMathName("exp", AsmJSMathBuiltin_exp) ||
    1806           0 :             !addStandardLibraryMathName("log", AsmJSMathBuiltin_log) ||
    1807           0 :             !addStandardLibraryMathName("pow", AsmJSMathBuiltin_pow) ||
    1808           0 :             !addStandardLibraryMathName("sqrt", AsmJSMathBuiltin_sqrt) ||
    1809           0 :             !addStandardLibraryMathName("abs", AsmJSMathBuiltin_abs) ||
    1810           0 :             !addStandardLibraryMathName("atan2", AsmJSMathBuiltin_atan2) ||
    1811           0 :             !addStandardLibraryMathName("imul", AsmJSMathBuiltin_imul) ||
    1812           0 :             !addStandardLibraryMathName("clz32", AsmJSMathBuiltin_clz32) ||
    1813           0 :             !addStandardLibraryMathName("fround", AsmJSMathBuiltin_fround) ||
    1814           0 :             !addStandardLibraryMathName("min", AsmJSMathBuiltin_min) ||
    1815           0 :             !addStandardLibraryMathName("max", AsmJSMathBuiltin_max) ||
    1816           0 :             !addStandardLibraryMathName("E", M_E) ||
    1817           0 :             !addStandardLibraryMathName("LN10", M_LN10) ||
    1818           0 :             !addStandardLibraryMathName("LN2", M_LN2) ||
    1819           0 :             !addStandardLibraryMathName("LOG2E", M_LOG2E) ||
    1820           0 :             !addStandardLibraryMathName("LOG10E", M_LOG10E) ||
    1821           0 :             !addStandardLibraryMathName("PI", M_PI) ||
    1822           0 :             !addStandardLibraryMathName("SQRT1_2", M_SQRT1_2) ||
    1823           0 :             !addStandardLibraryMathName("SQRT2", M_SQRT2))
    1824             :         {
    1825           0 :             return false;
    1826             :         }
    1827             : 
    1828           0 :         if (!standardLibraryAtomicsNames_.init() ||
    1829           0 :             !addStandardLibraryAtomicsName("compareExchange", AsmJSAtomicsBuiltin_compareExchange) ||
    1830           0 :             !addStandardLibraryAtomicsName("exchange", AsmJSAtomicsBuiltin_exchange) ||
    1831           0 :             !addStandardLibraryAtomicsName("load", AsmJSAtomicsBuiltin_load) ||
    1832           0 :             !addStandardLibraryAtomicsName("store", AsmJSAtomicsBuiltin_store) ||
    1833           0 :             !addStandardLibraryAtomicsName("add", AsmJSAtomicsBuiltin_add) ||
    1834           0 :             !addStandardLibraryAtomicsName("sub", AsmJSAtomicsBuiltin_sub) ||
    1835           0 :             !addStandardLibraryAtomicsName("and", AsmJSAtomicsBuiltin_and) ||
    1836           0 :             !addStandardLibraryAtomicsName("or", AsmJSAtomicsBuiltin_or) ||
    1837           0 :             !addStandardLibraryAtomicsName("xor", AsmJSAtomicsBuiltin_xor) ||
    1838           0 :             !addStandardLibraryAtomicsName("isLockFree", AsmJSAtomicsBuiltin_isLockFree))
    1839             :         {
    1840           0 :             return false;
    1841             :         }
    1842             : 
    1843             : #define ADDSTDLIBSIMDOPNAME(op) || !addStandardLibrarySimdOpName(#op, SimdOperation::Fn_##op)
    1844           0 :         if (!standardLibrarySimdOpNames_.init()
    1845           0 :             FORALL_SIMD_ASMJS_OP(ADDSTDLIBSIMDOPNAME))
    1846             :         {
    1847           0 :             return false;
    1848             :         }
    1849             : #undef ADDSTDLIBSIMDOPNAME
    1850             : 
    1851             :         // This flows into FunctionBox, so must be tenured.
    1852           0 :         dummyFunction_ = NewScriptedFunction(cx_, 0, JSFunction::INTERPRETED, nullptr,
    1853             :                                              /* proto = */ nullptr, gc::AllocKind::FUNCTION,
    1854           0 :                                              TenuredObject);
    1855           0 :         if (!dummyFunction_)
    1856           0 :             return false;
    1857             : 
    1858           0 :         ScriptedCaller scriptedCaller;
    1859           0 :         if (parser_.ss->filename()) {
    1860           0 :             scriptedCaller.line = scriptedCaller.column = 0;  // unused
    1861           0 :             scriptedCaller.filename = DuplicateString(parser_.ss->filename());
    1862           0 :             if (!scriptedCaller.filename)
    1863           0 :                 return false;
    1864             :         }
    1865             : 
    1866           0 :         CompileArgs args;
    1867           0 :         if (!args.initFromContext(cx_, Move(scriptedCaller)))
    1868           0 :             return false;
    1869             : 
    1870           0 :         auto env = MakeUnique<ModuleEnvironment>(ModuleKind::AsmJS);
    1871           0 :         if (!env ||
    1872           0 :             !env->sigs.resize(AsmJSMaxTypes) ||
    1873           0 :             !env->funcSigs.resize(AsmJSMaxFuncs) ||
    1874           0 :             !env->funcImportGlobalDataOffsets.resize(AsmJSMaxImports) ||
    1875           0 :             !env->tables.resize(AsmJSMaxTables) ||
    1876           0 :             !env->asmJSSigToTableIndex.resize(AsmJSMaxTypes))
    1877             :         {
    1878           0 :             return false;
    1879             :         }
    1880             : 
    1881           0 :         env->minMemoryLength = RoundUpToNextValidAsmJSHeapLength(0);
    1882             : 
    1883           0 :         if (!mg_.init(Move(env), args, asmJSMetadata_.get()))
    1884           0 :             return false;
    1885             : 
    1886           0 :         return true;
    1887             :     }
    1888             : 
    1889           0 :     JSContext* cx() const                    { return cx_; }
    1890           0 :     PropertyName* moduleFunctionName() const { return moduleFunctionName_; }
    1891           0 :     PropertyName* globalArgumentName() const { return globalArgumentName_; }
    1892           0 :     PropertyName* importArgumentName() const { return importArgumentName_; }
    1893           0 :     PropertyName* bufferArgumentName() const { return bufferArgumentName_; }
    1894           0 :     ModuleGenerator& mg()                    { return mg_; }
    1895           0 :     AsmJSParser& parser() const              { return parser_; }
    1896           0 :     TokenStream& tokenStream() const         { return parser_.tokenStream; }
    1897           0 :     RootedFunction& dummyFunction()          { return dummyFunction_; }
    1898           0 :     bool supportsSimd() const                { return cx_->jitSupportsSimd(); }
    1899           0 :     bool atomicsPresent() const              { return atomicsPresent_; }
    1900             :     uint32_t minMemoryLength() const         { return mg_.minMemoryLength(); }
    1901             : 
    1902             :     void initModuleFunctionName(PropertyName* name) {
    1903             :         MOZ_ASSERT(!moduleFunctionName_);
    1904             :         moduleFunctionName_ = name;
    1905             :     }
    1906           0 :     MOZ_MUST_USE bool initGlobalArgumentName(PropertyName* n) {
    1907           0 :         MOZ_ASSERT(n->isTenured());
    1908           0 :         globalArgumentName_ = n;
    1909           0 :         if (n) {
    1910           0 :             asmJSMetadata_->globalArgumentName = StringToNewUTF8CharsZ(cx_, *n);
    1911           0 :             if (!asmJSMetadata_->globalArgumentName)
    1912           0 :                 return false;
    1913             :         }
    1914           0 :         return true;
    1915             :     }
    1916           0 :     MOZ_MUST_USE bool initImportArgumentName(PropertyName* n) {
    1917           0 :         MOZ_ASSERT(n->isTenured());
    1918           0 :         importArgumentName_ = n;
    1919           0 :         if (n) {
    1920           0 :             asmJSMetadata_->importArgumentName = StringToNewUTF8CharsZ(cx_, *n);
    1921           0 :             if (!asmJSMetadata_->importArgumentName)
    1922           0 :                 return false;
    1923             :         }
    1924           0 :         return true;
    1925             :     }
    1926           0 :     MOZ_MUST_USE bool initBufferArgumentName(PropertyName* n) {
    1927           0 :         MOZ_ASSERT(n->isTenured());
    1928           0 :         bufferArgumentName_ = n;
    1929           0 :         if (n) {
    1930           0 :             asmJSMetadata_->bufferArgumentName = StringToNewUTF8CharsZ(cx_, *n);
    1931           0 :             if (!asmJSMetadata_->bufferArgumentName)
    1932           0 :                 return false;
    1933             :         }
    1934           0 :         return true;
    1935             :     }
    1936           0 :     bool addGlobalVarInit(PropertyName* var, const NumLit& lit, Type type, bool isConst) {
    1937           0 :         MOZ_ASSERT(type.isGlobalVarType());
    1938           0 :         MOZ_ASSERT(type == Type::canonicalize(Type::lit(lit)));
    1939             : 
    1940             :         uint32_t index;
    1941           0 :         if (!mg_.addGlobal(type.canonicalToValType(), isConst, &index))
    1942           0 :             return false;
    1943             : 
    1944           0 :         Global::Which which = isConst ? Global::ConstantLiteral : Global::Variable;
    1945           0 :         Global* global = validationLifo_.new_<Global>(which);
    1946           0 :         if (!global)
    1947           0 :             return false;
    1948           0 :         global->u.varOrConst.index_ = index;
    1949           0 :         global->u.varOrConst.type_ = (isConst ? Type::lit(lit) : type).which();
    1950           0 :         if (isConst)
    1951           0 :             global->u.varOrConst.literalValue_ = lit;
    1952           0 :         if (!globalMap_.putNew(var, global))
    1953           0 :             return false;
    1954             : 
    1955           0 :         AsmJSGlobal g(AsmJSGlobal::Variable, nullptr);
    1956           0 :         g.pod.u.var.initKind_ = AsmJSGlobal::InitConstant;
    1957           0 :         g.pod.u.var.u.val_ = lit.value();
    1958           0 :         return asmJSMetadata_->asmJSGlobals.append(Move(g));
    1959             :     }
    1960           0 :     bool addGlobalVarImport(PropertyName* var, PropertyName* field, Type type, bool isConst) {
    1961           0 :         MOZ_ASSERT(type.isGlobalVarType());
    1962             : 
    1963           0 :         UniqueChars fieldChars = StringToNewUTF8CharsZ(cx_, *field);
    1964           0 :         if (!fieldChars)
    1965           0 :             return false;
    1966             : 
    1967             :         uint32_t index;
    1968           0 :         ValType valType = type.canonicalToValType();
    1969           0 :         if (!mg_.addGlobal(valType, isConst, &index))
    1970           0 :             return false;
    1971             : 
    1972           0 :         Global::Which which = isConst ? Global::ConstantImport : Global::Variable;
    1973           0 :         Global* global = validationLifo_.new_<Global>(which);
    1974           0 :         if (!global)
    1975           0 :             return false;
    1976           0 :         global->u.varOrConst.index_ = index;
    1977           0 :         global->u.varOrConst.type_ = type.which();
    1978           0 :         if (!globalMap_.putNew(var, global))
    1979           0 :             return false;
    1980             : 
    1981           0 :         AsmJSGlobal g(AsmJSGlobal::Variable, Move(fieldChars));
    1982           0 :         g.pod.u.var.initKind_ = AsmJSGlobal::InitImport;
    1983           0 :         g.pod.u.var.u.importType_ = valType;
    1984           0 :         return asmJSMetadata_->asmJSGlobals.append(Move(g));
    1985             :     }
    1986           0 :     bool addArrayView(PropertyName* var, Scalar::Type vt, PropertyName* maybeField) {
    1987           0 :         UniqueChars fieldChars;
    1988           0 :         if (maybeField) {
    1989           0 :             fieldChars = StringToNewUTF8CharsZ(cx_, *maybeField);
    1990           0 :             if (!fieldChars)
    1991           0 :                 return false;
    1992             :         }
    1993             : 
    1994           0 :         if (!arrayViews_.append(ArrayView(var, vt)))
    1995           0 :             return false;
    1996             : 
    1997           0 :         Global* global = validationLifo_.new_<Global>(Global::ArrayView);
    1998           0 :         if (!global)
    1999           0 :             return false;
    2000           0 :         global->u.viewInfo.viewType_ = vt;
    2001           0 :         if (!globalMap_.putNew(var, global))
    2002           0 :             return false;
    2003             : 
    2004           0 :         AsmJSGlobal g(AsmJSGlobal::ArrayView, Move(fieldChars));
    2005           0 :         g.pod.u.viewType_ = vt;
    2006           0 :         return asmJSMetadata_->asmJSGlobals.append(Move(g));
    2007             :     }
    2008           0 :     bool addMathBuiltinFunction(PropertyName* var, AsmJSMathBuiltinFunction func,
    2009             :                                 PropertyName* field)
    2010             :     {
    2011           0 :         UniqueChars fieldChars = StringToNewUTF8CharsZ(cx_, *field);
    2012           0 :         if (!fieldChars)
    2013           0 :             return false;
    2014             : 
    2015           0 :         Global* global = validationLifo_.new_<Global>(Global::MathBuiltinFunction);
    2016           0 :         if (!global)
    2017           0 :             return false;
    2018           0 :         global->u.mathBuiltinFunc_ = func;
    2019           0 :         if (!globalMap_.putNew(var, global))
    2020           0 :             return false;
    2021             : 
    2022           0 :         AsmJSGlobal g(AsmJSGlobal::MathBuiltinFunction, Move(fieldChars));
    2023           0 :         g.pod.u.mathBuiltinFunc_ = func;
    2024           0 :         return asmJSMetadata_->asmJSGlobals.append(Move(g));
    2025             :     }
    2026             :   private:
    2027           0 :     bool addGlobalDoubleConstant(PropertyName* var, double constant) {
    2028           0 :         Global* global = validationLifo_.new_<Global>(Global::ConstantLiteral);
    2029           0 :         if (!global)
    2030           0 :             return false;
    2031           0 :         global->u.varOrConst.type_ = Type::Double;
    2032           0 :         global->u.varOrConst.literalValue_ = NumLit(NumLit::Double, DoubleValue(constant));
    2033           0 :         return globalMap_.putNew(var, global);
    2034             :     }
    2035             :   public:
    2036           0 :     bool addMathBuiltinConstant(PropertyName* var, double constant, PropertyName* field) {
    2037           0 :         UniqueChars fieldChars = StringToNewUTF8CharsZ(cx_, *field);
    2038           0 :         if (!fieldChars)
    2039           0 :             return false;
    2040             : 
    2041           0 :         if (!addGlobalDoubleConstant(var, constant))
    2042           0 :             return false;
    2043             : 
    2044           0 :         AsmJSGlobal g(AsmJSGlobal::Constant, Move(fieldChars));
    2045           0 :         g.pod.u.constant.value_ = constant;
    2046           0 :         g.pod.u.constant.kind_ = AsmJSGlobal::MathConstant;
    2047           0 :         return asmJSMetadata_->asmJSGlobals.append(Move(g));
    2048             :     }
    2049           0 :     bool addGlobalConstant(PropertyName* var, double constant, PropertyName* field) {
    2050           0 :         UniqueChars fieldChars = StringToNewUTF8CharsZ(cx_, *field);
    2051           0 :         if (!fieldChars)
    2052           0 :             return false;
    2053             : 
    2054           0 :         if (!addGlobalDoubleConstant(var, constant))
    2055           0 :             return false;
    2056             : 
    2057           0 :         AsmJSGlobal g(AsmJSGlobal::Constant, Move(fieldChars));
    2058           0 :         g.pod.u.constant.value_ = constant;
    2059           0 :         g.pod.u.constant.kind_ = AsmJSGlobal::GlobalConstant;
    2060           0 :         return asmJSMetadata_->asmJSGlobals.append(Move(g));
    2061             :     }
    2062           0 :     bool addAtomicsBuiltinFunction(PropertyName* var, AsmJSAtomicsBuiltinFunction func,
    2063             :                                    PropertyName* field)
    2064             :     {
    2065           0 :         if (!JitOptions.asmJSAtomicsEnable)
    2066           0 :             return failCurrentOffset("asm.js Atomics only enabled in wasm test mode");
    2067             : 
    2068           0 :         atomicsPresent_ = true;
    2069             : 
    2070           0 :         UniqueChars fieldChars = StringToNewUTF8CharsZ(cx_, *field);
    2071           0 :         if (!fieldChars)
    2072           0 :             return false;
    2073             : 
    2074           0 :         Global* global = validationLifo_.new_<Global>(Global::AtomicsBuiltinFunction);
    2075           0 :         if (!global)
    2076           0 :             return false;
    2077           0 :         global->u.atomicsBuiltinFunc_ = func;
    2078           0 :         if (!globalMap_.putNew(var, global))
    2079           0 :             return false;
    2080             : 
    2081           0 :         AsmJSGlobal g(AsmJSGlobal::AtomicsBuiltinFunction, Move(fieldChars));
    2082           0 :         g.pod.u.atomicsBuiltinFunc_ = func;
    2083           0 :         return asmJSMetadata_->asmJSGlobals.append(Move(g));
    2084             :     }
    2085           0 :     bool addSimdCtor(PropertyName* var, SimdType type, PropertyName* field) {
    2086           0 :         simdPresent_ = true;
    2087             : 
    2088           0 :         UniqueChars fieldChars = StringToNewUTF8CharsZ(cx_, *field);
    2089           0 :         if (!fieldChars)
    2090           0 :             return false;
    2091             : 
    2092           0 :         Global* global = validationLifo_.new_<Global>(Global::SimdCtor);
    2093           0 :         if (!global)
    2094           0 :             return false;
    2095           0 :         global->u.simdCtorType_ = type;
    2096           0 :         if (!globalMap_.putNew(var, global))
    2097           0 :             return false;
    2098             : 
    2099           0 :         AsmJSGlobal g(AsmJSGlobal::SimdCtor, Move(fieldChars));
    2100           0 :         g.pod.u.simdCtorType_ = type;
    2101           0 :         return asmJSMetadata_->asmJSGlobals.append(Move(g));
    2102             :     }
    2103           0 :     bool addSimdOperation(PropertyName* var, SimdType type, SimdOperation op, PropertyName* field) {
    2104           0 :         simdPresent_ = true;
    2105             : 
    2106           0 :         UniqueChars fieldChars = StringToNewUTF8CharsZ(cx_, *field);
    2107           0 :         if (!fieldChars)
    2108           0 :             return false;
    2109             : 
    2110           0 :         Global* global = validationLifo_.new_<Global>(Global::SimdOp);
    2111           0 :         if (!global)
    2112           0 :             return false;
    2113           0 :         global->u.simdOp.type_ = type;
    2114           0 :         global->u.simdOp.which_ = op;
    2115           0 :         if (!globalMap_.putNew(var, global))
    2116           0 :             return false;
    2117             : 
    2118           0 :         AsmJSGlobal g(AsmJSGlobal::SimdOp, Move(fieldChars));
    2119           0 :         g.pod.u.simdOp.type_ = type;
    2120           0 :         g.pod.u.simdOp.which_ = op;
    2121           0 :         return asmJSMetadata_->asmJSGlobals.append(Move(g));
    2122             :     }
    2123           0 :     bool addArrayViewCtor(PropertyName* var, Scalar::Type vt, PropertyName* field) {
    2124           0 :         UniqueChars fieldChars = StringToNewUTF8CharsZ(cx_, *field);
    2125           0 :         if (!fieldChars)
    2126           0 :             return false;
    2127             : 
    2128           0 :         Global* global = validationLifo_.new_<Global>(Global::ArrayViewCtor);
    2129           0 :         if (!global)
    2130           0 :             return false;
    2131           0 :         global->u.viewInfo.viewType_ = vt;
    2132           0 :         if (!globalMap_.putNew(var, global))
    2133           0 :             return false;
    2134             : 
    2135           0 :         AsmJSGlobal g(AsmJSGlobal::ArrayViewCtor, Move(fieldChars));
    2136           0 :         g.pod.u.viewType_ = vt;
    2137           0 :         return asmJSMetadata_->asmJSGlobals.append(Move(g));
    2138             :     }
    2139           0 :     bool addFFI(PropertyName* var, PropertyName* field) {
    2140           0 :         UniqueChars fieldChars = StringToNewUTF8CharsZ(cx_, *field);
    2141           0 :         if (!fieldChars)
    2142           0 :             return false;
    2143             : 
    2144           0 :         if (asmJSMetadata_->numFFIs == UINT32_MAX)
    2145           0 :             return false;
    2146           0 :         uint32_t ffiIndex = asmJSMetadata_->numFFIs++;
    2147             : 
    2148           0 :         Global* global = validationLifo_.new_<Global>(Global::FFI);
    2149           0 :         if (!global)
    2150           0 :             return false;
    2151           0 :         global->u.ffiIndex_ = ffiIndex;
    2152           0 :         if (!globalMap_.putNew(var, global))
    2153           0 :             return false;
    2154             : 
    2155           0 :         AsmJSGlobal g(AsmJSGlobal::FFI, Move(fieldChars));
    2156           0 :         g.pod.u.ffiIndex_ = ffiIndex;
    2157           0 :         return asmJSMetadata_->asmJSGlobals.append(Move(g));
    2158             :     }
    2159           0 :     bool addExportField(ParseNode* pn, const Func& func, PropertyName* maybeField) {
    2160             :         // Record the field name of this export.
    2161           0 :         CacheableChars fieldChars;
    2162           0 :         if (maybeField)
    2163           0 :             fieldChars = StringToNewUTF8CharsZ(cx_, *maybeField);
    2164             :         else
    2165           0 :             fieldChars = DuplicateString("");
    2166           0 :         if (!fieldChars)
    2167           0 :             return false;
    2168             : 
    2169             :         // Declare which function is exported which gives us an index into the
    2170             :         // module ExportVector.
    2171           0 :         if (!mg_.addExport(Move(fieldChars), func.index()))
    2172           0 :             return false;
    2173             : 
    2174             :         // The exported function might have already been exported in which case
    2175             :         // the index will refer into the range of AsmJSExports.
    2176           0 :         return asmJSMetadata_->asmJSExports.emplaceBack(func.index(),
    2177           0 :                                                         func.srcBegin() - asmJSMetadata_->srcStart,
    2178           0 :                                                         func.srcEnd() - asmJSMetadata_->srcStart);
    2179             :     }
    2180           0 :     bool addFunction(PropertyName* name, uint32_t firstUse, Sig&& sig, Func** func) {
    2181             :         uint32_t sigIndex;
    2182           0 :         if (!declareSig(Move(sig), &sigIndex))
    2183           0 :             return false;
    2184           0 :         uint32_t funcIndex = AsmJSFirstDefFuncIndex + numFunctions();
    2185           0 :         if (funcIndex >= AsmJSMaxFuncs)
    2186           0 :             return failCurrentOffset("too many functions");
    2187           0 :         mg_.initFuncSig(funcIndex, sigIndex);
    2188           0 :         Global* global = validationLifo_.new_<Global>(Global::Function);
    2189           0 :         if (!global)
    2190           0 :             return false;
    2191           0 :         global->u.funcIndex_ = funcIndex;
    2192           0 :         if (!globalMap_.putNew(name, global))
    2193           0 :             return false;
    2194           0 :         *func = validationLifo_.new_<Func>(name, firstUse, funcIndex);
    2195           0 :         return *func && functions_.append(*func);
    2196             :     }
    2197           0 :     bool declareFuncPtrTable(Sig&& sig, PropertyName* name, uint32_t firstUse, uint32_t mask,
    2198             :                              uint32_t* index)
    2199             :     {
    2200           0 :         if (mask > MaxTableInitialLength)
    2201           0 :             return failCurrentOffset("function pointer table too big");
    2202             :         uint32_t sigIndex;
    2203           0 :         if (!newSig(Move(sig), &sigIndex))
    2204           0 :             return false;
    2205           0 :         if (!mg_.initSigTableLength(sigIndex, mask + 1))
    2206           0 :             return false;
    2207           0 :         Global* global = validationLifo_.new_<Global>(Global::FuncPtrTable);
    2208           0 :         if (!global)
    2209           0 :             return false;
    2210           0 :         global->u.funcPtrTableIndex_ = *index = funcPtrTables_.length();
    2211           0 :         if (!globalMap_.putNew(name, global))
    2212           0 :             return false;
    2213           0 :         FuncPtrTable* t = validationLifo_.new_<FuncPtrTable>(sigIndex, name, firstUse, mask);
    2214           0 :         return t && funcPtrTables_.append(t);
    2215             :     }
    2216           0 :     bool defineFuncPtrTable(uint32_t funcPtrTableIndex, Uint32Vector&& elems) {
    2217           0 :         FuncPtrTable& table = *funcPtrTables_[funcPtrTableIndex];
    2218           0 :         if (table.defined())
    2219           0 :             return false;
    2220           0 :         table.define();
    2221           0 :         return mg_.initSigTableElems(table.sigIndex(), Move(elems));
    2222             :     }
    2223           0 :     bool declareImport(PropertyName* name, Sig&& sig, unsigned ffiIndex, uint32_t* funcIndex) {
    2224           0 :         ImportMap::AddPtr p = importMap_.lookupForAdd(NamedSig::Lookup(name, sig));
    2225           0 :         if (p) {
    2226           0 :             *funcIndex = p->value();
    2227           0 :             return true;
    2228             :         }
    2229           0 :         *funcIndex = asmJSMetadata_->asmJSImports.length();
    2230           0 :         if (*funcIndex > AsmJSMaxImports)
    2231           0 :             return failCurrentOffset("too many imports");
    2232           0 :         if (!asmJSMetadata_->asmJSImports.emplaceBack(ffiIndex))
    2233           0 :             return false;
    2234             :         uint32_t sigIndex;
    2235           0 :         if (!declareSig(Move(sig), &sigIndex))
    2236           0 :             return false;
    2237           0 :         if (!mg_.initImport(*funcIndex, sigIndex))
    2238           0 :             return false;
    2239           0 :         return importMap_.add(p, NamedSig(name, mg_.sig(sigIndex)), *funcIndex);
    2240             :     }
    2241             : 
    2242           0 :     bool tryConstantAccess(uint64_t start, uint64_t width) {
    2243           0 :         MOZ_ASSERT(UINT64_MAX - start > width);
    2244           0 :         uint64_t len = start + width;
    2245           0 :         if (len > uint64_t(INT32_MAX) + 1)
    2246           0 :             return false;
    2247           0 :         len = RoundUpToNextValidAsmJSHeapLength(len);
    2248           0 :         if (len > mg_.minMemoryLength())
    2249           0 :             mg_.bumpMinMemoryLength(len);
    2250           0 :         return true;
    2251             :     }
    2252             : 
    2253             :     // Error handling.
    2254           0 :     bool hasAlreadyFailed() const {
    2255           0 :         return !!errorString_;
    2256             :     }
    2257             : 
    2258           0 :     bool failOffset(uint32_t offset, const char* str) {
    2259           0 :         MOZ_ASSERT(!hasAlreadyFailed());
    2260           0 :         MOZ_ASSERT(errorOffset_ == UINT32_MAX);
    2261           0 :         MOZ_ASSERT(str);
    2262           0 :         errorOffset_ = offset;
    2263           0 :         errorString_ = DuplicateString(str);
    2264           0 :         return false;
    2265             :     }
    2266             : 
    2267           0 :     bool failCurrentOffset(const char* str) {
    2268           0 :         return failOffset(tokenStream().currentToken().pos.begin, str);
    2269             :     }
    2270             : 
    2271           0 :     bool fail(ParseNode* pn, const char* str) {
    2272           0 :         return failOffset(pn->pn_pos.begin, str);
    2273             :     }
    2274             : 
    2275           0 :     bool failfVAOffset(uint32_t offset, const char* fmt, va_list ap) MOZ_FORMAT_PRINTF(3, 0) {
    2276           0 :         MOZ_ASSERT(!hasAlreadyFailed());
    2277           0 :         MOZ_ASSERT(errorOffset_ == UINT32_MAX);
    2278           0 :         MOZ_ASSERT(fmt);
    2279           0 :         errorOffset_ = offset;
    2280           0 :         errorString_ = JS_vsmprintf(fmt, ap);
    2281           0 :         return false;
    2282             :     }
    2283             : 
    2284           0 :     bool failfOffset(uint32_t offset, const char* fmt, ...) MOZ_FORMAT_PRINTF(3, 4) {
    2285             :         va_list ap;
    2286           0 :         va_start(ap, fmt);
    2287           0 :         failfVAOffset(offset, fmt, ap);
    2288           0 :         va_end(ap);
    2289           0 :         return false;
    2290             :     }
    2291             : 
    2292           0 :     bool failf(ParseNode* pn, const char* fmt, ...) MOZ_FORMAT_PRINTF(3, 4) {
    2293             :         va_list ap;
    2294           0 :         va_start(ap, fmt);
    2295           0 :         failfVAOffset(pn->pn_pos.begin, fmt, ap);
    2296           0 :         va_end(ap);
    2297           0 :         return false;
    2298             :     }
    2299             : 
    2300           0 :     bool failNameOffset(uint32_t offset, const char* fmt, PropertyName* name) {
    2301             :         // This function is invoked without the caller properly rooting its locals.
    2302           0 :         gc::AutoSuppressGC suppress(cx_);
    2303           0 :         JSAutoByteString bytes;
    2304           0 :         if (AtomToPrintableString(cx_, name, &bytes))
    2305           0 :             failfOffset(offset, fmt, bytes.ptr());
    2306           0 :         return false;
    2307             :     }
    2308             : 
    2309           0 :     bool failName(ParseNode* pn, const char* fmt, PropertyName* name) {
    2310           0 :         return failNameOffset(pn->pn_pos.begin, fmt, name);
    2311             :     }
    2312             : 
    2313           0 :     bool failOverRecursed() {
    2314           0 :         errorOverRecursed_ = true;
    2315           0 :         return false;
    2316             :     }
    2317             : 
    2318             :     unsigned numArrayViews() const {
    2319             :         return arrayViews_.length();
    2320             :     }
    2321             :     const ArrayView& arrayView(unsigned i) const {
    2322             :         return arrayViews_[i];
    2323             :     }
    2324           0 :     unsigned numFunctions() const {
    2325           0 :         return functions_.length();
    2326             :     }
    2327           0 :     Func& function(unsigned i) const {
    2328           0 :         return *functions_[i];
    2329             :     }
    2330           0 :     unsigned numFuncPtrTables() const {
    2331           0 :         return funcPtrTables_.length();
    2332             :     }
    2333           0 :     FuncPtrTable& funcPtrTable(unsigned i) const {
    2334           0 :         return *funcPtrTables_[i];
    2335             :     }
    2336             : 
    2337           0 :     const Global* lookupGlobal(PropertyName* name) const {
    2338           0 :         if (GlobalMap::Ptr p = globalMap_.lookup(name))
    2339           0 :             return p->value();
    2340           0 :         return nullptr;
    2341             :     }
    2342             : 
    2343           0 :     Func* lookupFunction(PropertyName* name) {
    2344           0 :         if (GlobalMap::Ptr p = globalMap_.lookup(name)) {
    2345           0 :             Global* value = p->value();
    2346           0 :             if (value->which() == Global::Function) {
    2347           0 :                 MOZ_ASSERT(value->funcIndex() >= AsmJSFirstDefFuncIndex);
    2348           0 :                 return functions_[value->funcIndex() - AsmJSFirstDefFuncIndex];
    2349             :             }
    2350             :         }
    2351           0 :         return nullptr;
    2352             :     }
    2353             : 
    2354           0 :     bool lookupStandardLibraryMathName(PropertyName* name, MathBuiltin* mathBuiltin) const {
    2355           0 :         if (MathNameMap::Ptr p = standardLibraryMathNames_.lookup(name)) {
    2356           0 :             *mathBuiltin = p->value();
    2357           0 :             return true;
    2358             :         }
    2359           0 :         return false;
    2360             :     }
    2361           0 :     bool lookupStandardLibraryAtomicsName(PropertyName* name, AsmJSAtomicsBuiltinFunction* atomicsBuiltin) const {
    2362           0 :         if (AtomicsNameMap::Ptr p = standardLibraryAtomicsNames_.lookup(name)) {
    2363           0 :             *atomicsBuiltin = p->value();
    2364           0 :             return true;
    2365             :         }
    2366           0 :         return false;
    2367             :     }
    2368           0 :     bool lookupStandardSimdOpName(PropertyName* name, SimdOperation* op) const {
    2369           0 :         if (SimdOperationNameMap::Ptr p = standardLibrarySimdOpNames_.lookup(name)) {
    2370           0 :             *op = p->value();
    2371           0 :             return true;
    2372             :         }
    2373           0 :         return false;
    2374             :     }
    2375             : 
    2376           0 :     bool startFunctionBodies() {
    2377           0 :         if (!arrayViews_.empty())
    2378           0 :             mg_.initMemoryUsage(atomicsPresent_ ? MemoryUsage::Shared : MemoryUsage::Unshared);
    2379             : 
    2380           0 :         return mg_.startFuncDefs();
    2381             :     }
    2382           0 :     bool finishFunctionBodies() {
    2383           0 :         return mg_.finishFuncDefs();
    2384             :     }
    2385           0 :     SharedModule finish() {
    2386           0 :         asmJSMetadata_->usesSimd = simdPresent_;
    2387             : 
    2388           0 :         MOZ_ASSERT(asmJSMetadata_->asmJSFuncNames.empty());
    2389           0 :         for (const Func* func : functions_) {
    2390           0 :             CacheableChars funcName = StringToNewUTF8CharsZ(cx_, *func->name());
    2391           0 :             if (!funcName || !asmJSMetadata_->asmJSFuncNames.emplaceBack(Move(funcName)))
    2392           0 :                 return nullptr;
    2393             :         }
    2394             : 
    2395           0 :         uint32_t endBeforeCurly = tokenStream().currentToken().pos.end;
    2396           0 :         asmJSMetadata_->srcLength = endBeforeCurly - asmJSMetadata_->srcStart;
    2397             : 
    2398           0 :         TokenPos pos;
    2399           0 :         JS_ALWAYS_TRUE(tokenStream().peekTokenPos(&pos, TokenStream::Operand));
    2400           0 :         uint32_t endAfterCurly = pos.end;
    2401           0 :         asmJSMetadata_->srcLengthWithRightBrace = endAfterCurly - asmJSMetadata_->srcStart;
    2402             : 
    2403             :         // asm.js does not have any wasm bytecode to save; view-source is
    2404             :         // provided through the ScriptSource.
    2405           0 :         SharedBytes bytes = js_new<ShareableBytes>();
    2406           0 :         if (!bytes)
    2407           0 :             return nullptr;
    2408             : 
    2409           0 :         return mg_.finish(*bytes);
    2410             :     }
    2411             : };
    2412             : 
    2413             : /*****************************************************************************/
    2414             : // Numeric literal utilities
    2415             : 
    2416             : static bool
    2417           0 : IsNumericNonFloatLiteral(ParseNode* pn)
    2418             : {
    2419             :     // Note: '-' is never rolled into the number; numbers are always positive
    2420             :     // and negations must be applied manually.
    2421           0 :     return pn->isKind(PNK_NUMBER) ||
    2422           0 :            (pn->isKind(PNK_NEG) && UnaryKid(pn)->isKind(PNK_NUMBER));
    2423             : }
    2424             : 
    2425             : static bool
    2426           0 : IsCallToGlobal(ModuleValidator& m, ParseNode* pn, const ModuleValidator::Global** global)
    2427             : {
    2428           0 :     if (!pn->isKind(PNK_CALL))
    2429           0 :         return false;
    2430             : 
    2431           0 :     ParseNode* callee = CallCallee(pn);
    2432           0 :     if (!callee->isKind(PNK_NAME))
    2433           0 :         return false;
    2434             : 
    2435           0 :     *global = m.lookupGlobal(callee->name());
    2436           0 :     return !!*global;
    2437             : }
    2438             : 
    2439             : static bool
    2440           0 : IsCoercionCall(ModuleValidator& m, ParseNode* pn, Type* coerceTo, ParseNode** coercedExpr)
    2441             : {
    2442             :     const ModuleValidator::Global* global;
    2443           0 :     if (!IsCallToGlobal(m, pn, &global))
    2444           0 :         return false;
    2445             : 
    2446           0 :     if (CallArgListLength(pn) != 1)
    2447           0 :         return false;
    2448             : 
    2449           0 :     if (coercedExpr)
    2450           0 :         *coercedExpr = CallArgList(pn);
    2451             : 
    2452           0 :     if (global->isMathFunction() && global->mathBuiltinFunction() == AsmJSMathBuiltin_fround) {
    2453           0 :         *coerceTo = Type::Float;
    2454           0 :         return true;
    2455             :     }
    2456             : 
    2457           0 :     if (global->isSimdOperation() && global->simdOperation() == SimdOperation::Fn_check) {
    2458           0 :         *coerceTo = global->simdOperationType();
    2459           0 :         return true;
    2460             :     }
    2461             : 
    2462           0 :     return false;
    2463             : }
    2464             : 
    2465             : static bool
    2466           0 : IsFloatLiteral(ModuleValidator& m, ParseNode* pn)
    2467             : {
    2468             :     ParseNode* coercedExpr;
    2469           0 :     Type coerceTo;
    2470           0 :     if (!IsCoercionCall(m, pn, &coerceTo, &coercedExpr))
    2471           0 :         return false;
    2472             :     // Don't fold into || to avoid clang/memcheck bug (bug 1077031).
    2473           0 :     if (!coerceTo.isFloat())
    2474           0 :         return false;
    2475           0 :     return IsNumericNonFloatLiteral(coercedExpr);
    2476             : }
    2477             : 
    2478             : static bool
    2479           0 : IsSimdTuple(ModuleValidator& m, ParseNode* pn, SimdType* type)
    2480             : {
    2481             :     const ModuleValidator::Global* global;
    2482           0 :     if (!IsCallToGlobal(m, pn, &global))
    2483           0 :         return false;
    2484             : 
    2485           0 :     if (!global->isSimdCtor())
    2486           0 :         return false;
    2487             : 
    2488           0 :     if (CallArgListLength(pn) != GetSimdLanes(global->simdCtorType()))
    2489           0 :         return false;
    2490             : 
    2491           0 :     *type = global->simdCtorType();
    2492           0 :     return true;
    2493             : }
    2494             : 
    2495             : static bool
    2496             : IsNumericLiteral(ModuleValidator& m, ParseNode* pn, bool* isSimd = nullptr);
    2497             : 
    2498             : static NumLit
    2499             : ExtractNumericLiteral(ModuleValidator& m, ParseNode* pn);
    2500             : 
    2501             : static inline bool
    2502             : IsLiteralInt(ModuleValidator& m, ParseNode* pn, uint32_t* u32);
    2503             : 
    2504             : static bool
    2505           0 : IsSimdLiteral(ModuleValidator& m, ParseNode* pn)
    2506             : {
    2507             :     SimdType type;
    2508           0 :     if (!IsSimdTuple(m, pn, &type))
    2509           0 :         return false;
    2510             : 
    2511           0 :     ParseNode* arg = CallArgList(pn);
    2512           0 :     unsigned length = GetSimdLanes(type);
    2513           0 :     for (unsigned i = 0; i < length; i++) {
    2514           0 :         if (!IsNumericLiteral(m, arg))
    2515           0 :             return false;
    2516             : 
    2517             :         uint32_t _;
    2518           0 :         switch (type) {
    2519             :           case SimdType::Int8x16:
    2520             :           case SimdType::Int16x8:
    2521             :           case SimdType::Int32x4:
    2522             :           case SimdType::Uint8x16:
    2523             :           case SimdType::Uint16x8:
    2524             :           case SimdType::Uint32x4:
    2525             :           case SimdType::Bool8x16:
    2526             :           case SimdType::Bool16x8:
    2527             :           case SimdType::Bool32x4:
    2528           0 :             if (!IsLiteralInt(m, arg, &_))
    2529           0 :                 return false;
    2530           0 :             break;
    2531             :           case SimdType::Float32x4:
    2532           0 :             if (!IsNumericNonFloatLiteral(arg))
    2533           0 :                 return false;
    2534           0 :             break;
    2535             :           default:
    2536           0 :             MOZ_CRASH("unhandled simd type");
    2537             :         }
    2538             : 
    2539           0 :         arg = NextNode(arg);
    2540             :     }
    2541             : 
    2542           0 :     MOZ_ASSERT(arg == nullptr);
    2543           0 :     return true;
    2544             : }
    2545             : 
    2546             : static bool
    2547           0 : IsNumericLiteral(ModuleValidator& m, ParseNode* pn, bool* isSimd)
    2548             : {
    2549           0 :     if (IsNumericNonFloatLiteral(pn) || IsFloatLiteral(m, pn))
    2550           0 :         return true;
    2551           0 :     if (IsSimdLiteral(m, pn)) {
    2552           0 :         if (isSimd)
    2553           0 :             *isSimd = true;
    2554           0 :         return true;
    2555             :     }
    2556           0 :     return false;
    2557             : }
    2558             : 
    2559             : // The JS grammar treats -42 as -(42) (i.e., with separate grammar
    2560             : // productions) for the unary - and literal 42). However, the asm.js spec
    2561             : // recognizes -42 (modulo parens, so -(42) and -((42))) as a single literal
    2562             : // so fold the two potential parse nodes into a single double value.
    2563             : static double
    2564           0 : ExtractNumericNonFloatValue(ParseNode* pn, ParseNode** out = nullptr)
    2565             : {
    2566           0 :     MOZ_ASSERT(IsNumericNonFloatLiteral(pn));
    2567             : 
    2568           0 :     if (pn->isKind(PNK_NEG)) {
    2569           0 :         pn = UnaryKid(pn);
    2570           0 :         if (out)
    2571           0 :             *out = pn;
    2572           0 :         return -NumberNodeValue(pn);
    2573             :     }
    2574             : 
    2575           0 :     return NumberNodeValue(pn);
    2576             : }
    2577             : 
    2578             : static NumLit
    2579           0 : ExtractSimdValue(ModuleValidator& m, ParseNode* pn)
    2580             : {
    2581           0 :     MOZ_ASSERT(IsSimdLiteral(m, pn));
    2582             : 
    2583           0 :     SimdType type = SimdType::Count;
    2584           0 :     JS_ALWAYS_TRUE(IsSimdTuple(m, pn, &type));
    2585           0 :     MOZ_ASSERT(CallArgListLength(pn) == GetSimdLanes(type));
    2586             : 
    2587           0 :     ParseNode* arg = CallArgList(pn);
    2588           0 :     switch (type) {
    2589             :       case SimdType::Int8x16:
    2590             :       case SimdType::Uint8x16: {
    2591           0 :         MOZ_ASSERT(GetSimdLanes(type) == 16);
    2592             :         int8_t val[16];
    2593           0 :         for (size_t i = 0; i < 16; i++, arg = NextNode(arg)) {
    2594             :             uint32_t u32;
    2595           0 :             JS_ALWAYS_TRUE(IsLiteralInt(m, arg, &u32));
    2596           0 :             val[i] = int8_t(u32);
    2597             :         }
    2598           0 :         MOZ_ASSERT(arg == nullptr);
    2599           0 :         NumLit::Which w = type == SimdType::Uint8x16 ? NumLit::Uint8x16 : NumLit::Int8x16;
    2600           0 :         return NumLit(w, SimdConstant::CreateX16(val));
    2601             :       }
    2602             :       case SimdType::Int16x8:
    2603             :       case SimdType::Uint16x8: {
    2604           0 :         MOZ_ASSERT(GetSimdLanes(type) == 8);
    2605             :         int16_t val[8];
    2606           0 :         for (size_t i = 0; i < 8; i++, arg = NextNode(arg)) {
    2607             :             uint32_t u32;
    2608           0 :             JS_ALWAYS_TRUE(IsLiteralInt(m, arg, &u32));
    2609           0 :             val[i] = int16_t(u32);
    2610             :         }
    2611           0 :         MOZ_ASSERT(arg == nullptr);
    2612           0 :         NumLit::Which w = type == SimdType::Uint16x8 ? NumLit::Uint16x8 : NumLit::Int16x8;
    2613           0 :         return NumLit(w, SimdConstant::CreateX8(val));
    2614             :       }
    2615             :       case SimdType::Int32x4:
    2616             :       case SimdType::Uint32x4: {
    2617           0 :         MOZ_ASSERT(GetSimdLanes(type) == 4);
    2618             :         int32_t val[4];
    2619           0 :         for (size_t i = 0; i < 4; i++, arg = NextNode(arg)) {
    2620             :             uint32_t u32;
    2621           0 :             JS_ALWAYS_TRUE(IsLiteralInt(m, arg, &u32));
    2622           0 :             val[i] = int32_t(u32);
    2623             :         }
    2624           0 :         MOZ_ASSERT(arg == nullptr);
    2625           0 :         NumLit::Which w = type == SimdType::Uint32x4 ? NumLit::Uint32x4 : NumLit::Int32x4;
    2626           0 :         return NumLit(w, SimdConstant::CreateX4(val));
    2627             :       }
    2628             :       case SimdType::Float32x4: {
    2629           0 :         MOZ_ASSERT(GetSimdLanes(type) == 4);
    2630             :         float val[4];
    2631           0 :         for (size_t i = 0; i < 4; i++, arg = NextNode(arg))
    2632           0 :             val[i] = float(ExtractNumericNonFloatValue(arg));
    2633           0 :         MOZ_ASSERT(arg == nullptr);
    2634           0 :         return NumLit(NumLit::Float32x4, SimdConstant::CreateX4(val));
    2635             :       }
    2636             :       case SimdType::Bool8x16: {
    2637           0 :         MOZ_ASSERT(GetSimdLanes(type) == 16);
    2638             :         int8_t val[16];
    2639           0 :         for (size_t i = 0; i < 16; i++, arg = NextNode(arg)) {
    2640             :             uint32_t u32;
    2641           0 :             JS_ALWAYS_TRUE(IsLiteralInt(m, arg, &u32));
    2642           0 :             val[i] = u32 ? -1 : 0;
    2643             :         }
    2644           0 :         MOZ_ASSERT(arg == nullptr);
    2645           0 :         return NumLit(NumLit::Bool8x16, SimdConstant::CreateX16(val));
    2646             :       }
    2647             :       case SimdType::Bool16x8: {
    2648           0 :         MOZ_ASSERT(GetSimdLanes(type) == 8);
    2649             :         int16_t val[8];
    2650           0 :         for (size_t i = 0; i < 8; i++, arg = NextNode(arg)) {
    2651             :             uint32_t u32;
    2652           0 :             JS_ALWAYS_TRUE(IsLiteralInt(m, arg, &u32));
    2653           0 :             val[i] = u32 ? -1 : 0;
    2654             :         }
    2655           0 :         MOZ_ASSERT(arg == nullptr);
    2656           0 :         return NumLit(NumLit::Bool16x8, SimdConstant::CreateX8(val));
    2657             :       }
    2658             :       case SimdType::Bool32x4: {
    2659           0 :         MOZ_ASSERT(GetSimdLanes(type) == 4);
    2660             :         int32_t val[4];
    2661           0 :         for (size_t i = 0; i < 4; i++, arg = NextNode(arg)) {
    2662             :             uint32_t u32;
    2663           0 :             JS_ALWAYS_TRUE(IsLiteralInt(m, arg, &u32));
    2664           0 :             val[i] = u32 ? -1 : 0;
    2665             :         }
    2666           0 :         MOZ_ASSERT(arg == nullptr);
    2667           0 :         return NumLit(NumLit::Bool32x4, SimdConstant::CreateX4(val));
    2668             :       }
    2669             :       default:
    2670           0 :         break;
    2671             :     }
    2672             : 
    2673           0 :     MOZ_CRASH("Unexpected SIMD type.");
    2674             : }
    2675             : 
    2676             : static NumLit
    2677           0 : ExtractNumericLiteral(ModuleValidator& m, ParseNode* pn)
    2678             : {
    2679           0 :     MOZ_ASSERT(IsNumericLiteral(m, pn));
    2680             : 
    2681           0 :     if (pn->isKind(PNK_CALL)) {
    2682             :         // Float literals are explicitly coerced and thus the coerced literal may be
    2683             :         // any valid (non-float) numeric literal.
    2684           0 :         if (CallArgListLength(pn) == 1) {
    2685           0 :             pn = CallArgList(pn);
    2686           0 :             double d = ExtractNumericNonFloatValue(pn);
    2687           0 :             return NumLit(NumLit::Float, DoubleValue(d));
    2688             :         }
    2689             : 
    2690           0 :         return ExtractSimdValue(m, pn);
    2691             :     }
    2692             : 
    2693           0 :     double d = ExtractNumericNonFloatValue(pn, &pn);
    2694             : 
    2695             :     // The asm.js spec syntactically distinguishes any literal containing a
    2696             :     // decimal point or the literal -0 as having double type.
    2697           0 :     if (NumberNodeHasFrac(pn) || IsNegativeZero(d))
    2698           0 :         return NumLit(NumLit::Double, DoubleValue(d));
    2699             : 
    2700             :     // The syntactic checks above rule out these double values.
    2701           0 :     MOZ_ASSERT(!IsNegativeZero(d));
    2702           0 :     MOZ_ASSERT(!IsNaN(d));
    2703             : 
    2704             :     // Although doubles can only *precisely* represent 53-bit integers, they
    2705             :     // can *imprecisely* represent integers much bigger than an int64_t.
    2706             :     // Furthermore, d may be inf or -inf. In both cases, casting to an int64_t
    2707             :     // is undefined, so test against the integer bounds using doubles.
    2708           0 :     if (d < double(INT32_MIN) || d > double(UINT32_MAX))
    2709           0 :         return NumLit(NumLit::OutOfRangeInt, UndefinedValue());
    2710             : 
    2711             :     // With the above syntactic and range limitations, d is definitely an
    2712             :     // integer in the range [INT32_MIN, UINT32_MAX] range.
    2713           0 :     int64_t i64 = int64_t(d);
    2714           0 :     if (i64 >= 0) {
    2715           0 :         if (i64 <= INT32_MAX)
    2716           0 :             return NumLit(NumLit::Fixnum, Int32Value(i64));
    2717           0 :         MOZ_ASSERT(i64 <= UINT32_MAX);
    2718           0 :         return NumLit(NumLit::BigUnsigned, Int32Value(uint32_t(i64)));
    2719             :     }
    2720           0 :     MOZ_ASSERT(i64 >= INT32_MIN);
    2721           0 :     return NumLit(NumLit::NegativeInt, Int32Value(i64));
    2722             : }
    2723             : 
    2724             : static inline bool
    2725           0 : IsLiteralInt(const NumLit& lit, uint32_t* u32)
    2726             : {
    2727           0 :     switch (lit.which()) {
    2728             :       case NumLit::Fixnum:
    2729             :       case NumLit::BigUnsigned:
    2730             :       case NumLit::NegativeInt:
    2731           0 :         *u32 = lit.toUint32();
    2732           0 :         return true;
    2733             :       case NumLit::Double:
    2734             :       case NumLit::Float:
    2735             :       case NumLit::OutOfRangeInt:
    2736             :       case NumLit::Int8x16:
    2737             :       case NumLit::Uint8x16:
    2738             :       case NumLit::Int16x8:
    2739             :       case NumLit::Uint16x8:
    2740             :       case NumLit::Int32x4:
    2741             :       case NumLit::Uint32x4:
    2742             :       case NumLit::Float32x4:
    2743             :       case NumLit::Bool8x16:
    2744             :       case NumLit::Bool16x8:
    2745             :       case NumLit::Bool32x4:
    2746           0 :         return false;
    2747             :     }
    2748           0 :     MOZ_MAKE_COMPILER_ASSUME_IS_UNREACHABLE("Bad literal type");
    2749             : }
    2750             : 
    2751             : static inline bool
    2752           0 : IsLiteralInt(ModuleValidator& m, ParseNode* pn, uint32_t* u32)
    2753             : {
    2754           0 :     return IsNumericLiteral(m, pn) &&
    2755           0 :            IsLiteralInt(ExtractNumericLiteral(m, pn), u32);
    2756             : }
    2757             : 
    2758             : /*****************************************************************************/
    2759             : 
    2760             : namespace {
    2761             : 
    2762             : #define CASE(TYPE, OP) case SimdOperation::Fn_##OP: return MozOp::TYPE##OP;
    2763             : #define I8x16CASE(OP) CASE(I8x16, OP)
    2764             : #define I16x8CASE(OP) CASE(I16x8, OP)
    2765             : #define I32x4CASE(OP) CASE(I32x4, OP)
    2766             : #define F32x4CASE(OP) CASE(F32x4, OP)
    2767             : #define B8x16CASE(OP) CASE(B8x16, OP)
    2768             : #define B16x8CASE(OP) CASE(B16x8, OP)
    2769             : #define B32x4CASE(OP) CASE(B32x4, OP)
    2770             : #define ENUMERATE(TYPE, FOR_ALL, DO)                                     \
    2771             :     switch(op) {                                                         \
    2772             :         case SimdOperation::Constructor: return MozOp::TYPE##Constructor;\
    2773             :         FOR_ALL(DO)                                                      \
    2774             :         default: break;                                                  \
    2775             :     }
    2776             : 
    2777             : static inline MozOp
    2778           0 : SimdToOp(SimdType type, SimdOperation op)
    2779             : {
    2780           0 :     switch (type) {
    2781             :       case SimdType::Uint8x16:
    2782             :         // Handle the special unsigned opcodes, then fall through to Int8x16.
    2783           0 :         switch (op) {
    2784           0 :           case SimdOperation::Fn_addSaturate:        return MozOp::I8x16addSaturateU;
    2785           0 :           case SimdOperation::Fn_subSaturate:        return MozOp::I8x16subSaturateU;
    2786           0 :           case SimdOperation::Fn_extractLane:        return MozOp::I8x16extractLaneU;
    2787           0 :           case SimdOperation::Fn_shiftRightByScalar: return MozOp::I8x16shiftRightByScalarU;
    2788           0 :           case SimdOperation::Fn_lessThan:           return MozOp::I8x16lessThanU;
    2789           0 :           case SimdOperation::Fn_lessThanOrEqual:    return MozOp::I8x16lessThanOrEqualU;
    2790           0 :           case SimdOperation::Fn_greaterThan:        return MozOp::I8x16greaterThanU;
    2791           0 :           case SimdOperation::Fn_greaterThanOrEqual: return MozOp::I8x16greaterThanOrEqualU;
    2792           0 :           case SimdOperation::Fn_fromInt8x16Bits:    return MozOp::Limit;
    2793           0 :           default: break;
    2794             :         }
    2795             :         MOZ_FALLTHROUGH;
    2796             :       case SimdType::Int8x16:
    2797             :         // Bitcasts Uint8x16 <--> Int8x16 become noops.
    2798           0 :         switch (op) {
    2799           0 :           case SimdOperation::Fn_fromUint8x16Bits: return MozOp::Limit;
    2800           0 :           case SimdOperation::Fn_fromUint16x8Bits: return MozOp::I8x16fromInt16x8Bits;
    2801           0 :           case SimdOperation::Fn_fromUint32x4Bits: return MozOp::I8x16fromInt32x4Bits;
    2802           0 :           default: break;
    2803             :         }
    2804           0 :         ENUMERATE(I8x16, FORALL_INT8X16_ASMJS_OP, I8x16CASE)
    2805           0 :         break;
    2806             : 
    2807             :       case SimdType::Uint16x8:
    2808             :         // Handle the special unsigned opcodes, then fall through to Int16x8.
    2809           0 :         switch(op) {
    2810           0 :           case SimdOperation::Fn_addSaturate:        return MozOp::I16x8addSaturateU;
    2811           0 :           case SimdOperation::Fn_subSaturate:        return MozOp::I16x8subSaturateU;
    2812           0 :           case SimdOperation::Fn_extractLane:        return MozOp::I16x8extractLaneU;
    2813           0 :           case SimdOperation::Fn_shiftRightByScalar: return MozOp::I16x8shiftRightByScalarU;
    2814           0 :           case SimdOperation::Fn_lessThan:           return MozOp::I16x8lessThanU;
    2815           0 :           case SimdOperation::Fn_lessThanOrEqual:    return MozOp::I16x8lessThanOrEqualU;
    2816           0 :           case SimdOperation::Fn_greaterThan:        return MozOp::I16x8greaterThanU;
    2817           0 :           case SimdOperation::Fn_greaterThanOrEqual: return MozOp::I16x8greaterThanOrEqualU;
    2818           0 :           case SimdOperation::Fn_fromInt16x8Bits:    return MozOp::Limit;
    2819           0 :           default: break;
    2820             :         }
    2821             :         MOZ_FALLTHROUGH;
    2822             :       case SimdType::Int16x8:
    2823             :         // Bitcasts Uint16x8 <--> Int16x8 become noops.
    2824           0 :         switch (op) {
    2825           0 :           case SimdOperation::Fn_fromUint8x16Bits: return MozOp::I16x8fromInt8x16Bits;
    2826           0 :           case SimdOperation::Fn_fromUint16x8Bits: return MozOp::Limit;
    2827           0 :           case SimdOperation::Fn_fromUint32x4Bits: return MozOp::I16x8fromInt32x4Bits;
    2828           0 :           default: break;
    2829             :         }
    2830           0 :         ENUMERATE(I16x8, FORALL_INT16X8_ASMJS_OP, I16x8CASE)
    2831           0 :         break;
    2832             : 
    2833             :       case SimdType::Uint32x4:
    2834             :         // Handle the special unsigned opcodes, then fall through to Int32x4.
    2835           0 :         switch(op) {
    2836           0 :           case SimdOperation::Fn_shiftRightByScalar: return MozOp::I32x4shiftRightByScalarU;
    2837           0 :           case SimdOperation::Fn_lessThan:           return MozOp::I32x4lessThanU;
    2838           0 :           case SimdOperation::Fn_lessThanOrEqual:    return MozOp::I32x4lessThanOrEqualU;
    2839           0 :           case SimdOperation::Fn_greaterThan:        return MozOp::I32x4greaterThanU;
    2840           0 :           case SimdOperation::Fn_greaterThanOrEqual: return MozOp::I32x4greaterThanOrEqualU;
    2841           0 :           case SimdOperation::Fn_fromFloat32x4:      return MozOp::I32x4fromFloat32x4U;
    2842           0 :           case SimdOperation::Fn_fromInt32x4Bits:    return MozOp::Limit;
    2843           0 :           default: break;
    2844             :         }
    2845             :         MOZ_FALLTHROUGH;
    2846             :       case SimdType::Int32x4:
    2847             :         // Bitcasts Uint32x4 <--> Int32x4 become noops.
    2848           0 :         switch (op) {
    2849           0 :           case SimdOperation::Fn_fromUint8x16Bits: return MozOp::I32x4fromInt8x16Bits;
    2850           0 :           case SimdOperation::Fn_fromUint16x8Bits: return MozOp::I32x4fromInt16x8Bits;
    2851           0 :           case SimdOperation::Fn_fromUint32x4Bits: return MozOp::Limit;
    2852           0 :           default: break;
    2853             :         }
    2854           0 :         ENUMERATE(I32x4, FORALL_INT32X4_ASMJS_OP, I32x4CASE)
    2855           0 :         break;
    2856             : 
    2857             :       case SimdType::Float32x4:
    2858           0 :         switch (op) {
    2859           0 :           case SimdOperation::Fn_fromUint8x16Bits: return MozOp::F32x4fromInt8x16Bits;
    2860           0 :           case SimdOperation::Fn_fromUint16x8Bits: return MozOp::F32x4fromInt16x8Bits;
    2861           0 :           case SimdOperation::Fn_fromUint32x4Bits: return MozOp::F32x4fromInt32x4Bits;
    2862           0 :           default: break;
    2863             :         }
    2864           0 :         ENUMERATE(F32x4, FORALL_FLOAT32X4_ASMJS_OP, F32x4CASE)
    2865           0 :         break;
    2866             : 
    2867             :       case SimdType::Bool8x16:
    2868           0 :         ENUMERATE(B8x16, FORALL_BOOL_SIMD_OP, B8x16CASE)
    2869           0 :         break;
    2870             : 
    2871             :       case SimdType::Bool16x8:
    2872           0 :         ENUMERATE(B16x8, FORALL_BOOL_SIMD_OP, B16x8CASE)
    2873           0 :         break;
    2874             : 
    2875             :       case SimdType::Bool32x4:
    2876           0 :         ENUMERATE(B32x4, FORALL_BOOL_SIMD_OP, B32x4CASE)
    2877           0 :         break;
    2878             : 
    2879           0 :       default: break;
    2880             :     }
    2881           0 :     MOZ_CRASH("unexpected SIMD (type, operator) combination");
    2882             : }
    2883             : 
    2884             : #undef CASE
    2885             : #undef I8x16CASE
    2886             : #undef I16x8CASE
    2887             : #undef I32x4CASE
    2888             : #undef F32x4CASE
    2889             : #undef B8x16CASE
    2890             : #undef B16x8CASE
    2891             : #undef B32x4CASE
    2892             : #undef ENUMERATE
    2893             : 
    2894             : typedef Vector<PropertyName*, 4, SystemAllocPolicy> NameVector;
    2895             : 
    2896             : // Encapsulates the building of an asm bytecode function from an asm.js function
    2897             : // source code, packing the asm.js code into the asm bytecode form that can
    2898             : // be decoded and compiled with a FunctionCompiler.
    2899           0 : class MOZ_STACK_CLASS FunctionValidator
    2900             : {
    2901             :   public:
    2902             :     struct Local
    2903             :     {
    2904             :         Type type;
    2905             :         unsigned slot;
    2906           0 :         Local(Type t, unsigned slot) : type(t), slot(slot) {
    2907           0 :             MOZ_ASSERT(type.isCanonicalValType());
    2908           0 :         }
    2909             :     };
    2910             : 
    2911             :   private:
    2912             :     typedef HashMap<PropertyName*, Local> LocalMap;
    2913             :     typedef HashMap<PropertyName*, uint32_t> LabelMap;
    2914             : 
    2915             :     ModuleValidator&  m_;
    2916             :     ParseNode*        fn_;
    2917             : 
    2918             :     FunctionGenerator fg_;
    2919             :     Maybe<Encoder>    encoder_;
    2920             : 
    2921             :     LocalMap          locals_;
    2922             : 
    2923             :     // Labels
    2924             :     LabelMap          breakLabels_;
    2925             :     LabelMap          continueLabels_;
    2926             :     Uint32Vector      breakableStack_;
    2927             :     Uint32Vector      continuableStack_;
    2928             :     uint32_t          blockDepth_;
    2929             : 
    2930             :     bool              hasAlreadyReturned_;
    2931             :     ExprType          ret_;
    2932             : 
    2933             :   public:
    2934           0 :     FunctionValidator(ModuleValidator& m, ParseNode* fn)
    2935           0 :       : m_(m),
    2936             :         fn_(fn),
    2937             :         locals_(m.cx()),
    2938             :         breakLabels_(m.cx()),
    2939             :         continueLabels_(m.cx()),
    2940             :         blockDepth_(0),
    2941             :         hasAlreadyReturned_(false),
    2942           0 :         ret_(ExprType::Limit)
    2943           0 :     {}
    2944             : 
    2945           0 :     ModuleValidator& m() const        { return m_; }
    2946           0 :     JSContext* cx() const             { return m_.cx(); }
    2947           0 :     ParseNode* fn() const             { return fn_; }
    2948             : 
    2949           0 :     bool init(PropertyName* name, unsigned line) {
    2950           0 :         if (!locals_.init() || !breakLabels_.init() || !continueLabels_.init())
    2951           0 :             return false;
    2952             : 
    2953           0 :         if (!m_.mg().startFuncDef(line, &fg_))
    2954           0 :             return false;
    2955             : 
    2956           0 :         encoder_.emplace(fg_.bytes());
    2957           0 :         return true;
    2958             :     }
    2959             : 
    2960           0 :     bool finish(uint32_t funcIndex) {
    2961           0 :         MOZ_ASSERT(!blockDepth_);
    2962           0 :         MOZ_ASSERT(breakableStack_.empty());
    2963           0 :         MOZ_ASSERT(continuableStack_.empty());
    2964           0 :         MOZ_ASSERT(breakLabels_.empty());
    2965           0 :         MOZ_ASSERT(continueLabels_.empty());
    2966           0 :         for (auto iter = locals_.all(); !iter.empty(); iter.popFront()) {
    2967           0 :             if (iter.front().value().type.isSimd()) {
    2968           0 :                 setUsesSimd();
    2969           0 :                 break;
    2970             :             }
    2971             :         }
    2972             : 
    2973           0 :         return m_.mg().finishFuncDef(funcIndex, &fg_);
    2974             :     }
    2975             : 
    2976           0 :     bool fail(ParseNode* pn, const char* str) {
    2977           0 :         return m_.fail(pn, str);
    2978             :     }
    2979             : 
    2980           0 :     bool failf(ParseNode* pn, const char* fmt, ...) MOZ_FORMAT_PRINTF(3, 4) {
    2981             :         va_list ap;
    2982           0 :         va_start(ap, fmt);
    2983           0 :         m_.failfVAOffset(pn->pn_pos.begin, fmt, ap);
    2984           0 :         va_end(ap);
    2985           0 :         return false;
    2986             :     }
    2987             : 
    2988           0 :     bool failName(ParseNode* pn, const char* fmt, PropertyName* name) {
    2989           0 :         return m_.failName(pn, fmt, name);
    2990             :     }
    2991             : 
    2992             :     /***************************************************** Attributes */
    2993             : 
    2994           0 :     void setUsesSimd() {
    2995           0 :         fg_.setUsesSimd();
    2996           0 :     }
    2997             : 
    2998           0 :     void setUsesAtomics() {
    2999           0 :         fg_.setUsesAtomics();
    3000           0 :     }
    3001             : 
    3002             :     /***************************************************** Local scope setup */
    3003             : 
    3004           0 :     bool addLocal(ParseNode* pn, PropertyName* name, Type type) {
    3005           0 :         LocalMap::AddPtr p = locals_.lookupForAdd(name);
    3006           0 :         if (p)
    3007           0 :             return failName(pn, "duplicate local name '%s' not allowed", name);
    3008           0 :         return locals_.add(p, name, Local(type, locals_.count()));
    3009             :     }
    3010             : 
    3011             :     /****************************** For consistency of returns in a function */
    3012             : 
    3013           0 :     bool hasAlreadyReturned() const {
    3014           0 :         return hasAlreadyReturned_;
    3015             :     }
    3016             : 
    3017           0 :     ExprType returnedType() const {
    3018           0 :         return ret_;
    3019             :     }
    3020             : 
    3021           0 :     void setReturnedType(ExprType ret) {
    3022           0 :         ret_ = ret;
    3023           0 :         hasAlreadyReturned_ = true;
    3024           0 :     }
    3025             : 
    3026             :     /**************************************************************** Labels */
    3027             :   private:
    3028           0 :     bool writeBr(uint32_t absolute, Op op = Op::Br) {
    3029           0 :         MOZ_ASSERT(op == Op::Br || op == Op::BrIf);
    3030           0 :         MOZ_ASSERT(absolute < blockDepth_);
    3031           0 :         return encoder().writeOp(op) &&
    3032           0 :                encoder().writeVarU32(blockDepth_ - 1 - absolute);
    3033             :     }
    3034           0 :     void removeLabel(PropertyName* label, LabelMap* map) {
    3035           0 :         LabelMap::Ptr p = map->lookup(label);
    3036           0 :         MOZ_ASSERT(p);
    3037           0 :         map->remove(p);
    3038           0 :     }
    3039             : 
    3040             :   public:
    3041           0 :     bool pushBreakableBlock() {
    3042           0 :         return encoder().writeOp(Op::Block) &&
    3043           0 :                encoder().writeFixedU8(uint8_t(ExprType::Void)) &&
    3044           0 :                breakableStack_.append(blockDepth_++);
    3045             :     }
    3046           0 :     bool popBreakableBlock() {
    3047           0 :         JS_ALWAYS_TRUE(breakableStack_.popCopy() == --blockDepth_);
    3048           0 :         return encoder().writeOp(Op::End);
    3049             :     }
    3050             : 
    3051           0 :     bool pushUnbreakableBlock(const NameVector* labels = nullptr) {
    3052           0 :         if (labels) {
    3053           0 :             for (PropertyName* label : *labels) {
    3054           0 :                 if (!breakLabels_.putNew(label, blockDepth_))
    3055           0 :                     return false;
    3056             :             }
    3057             :         }
    3058           0 :         blockDepth_++;
    3059           0 :         return encoder().writeOp(Op::Block) &&
    3060           0 :                encoder().writeFixedU8(uint8_t(ExprType::Void));
    3061             :     }
    3062           0 :     bool popUnbreakableBlock(const NameVector* labels = nullptr) {
    3063           0 :         if (labels) {
    3064           0 :             for (PropertyName* label : *labels)
    3065           0 :                 removeLabel(label, &breakLabels_);
    3066             :         }
    3067           0 :         --blockDepth_;
    3068           0 :         return encoder().writeOp(Op::End);
    3069             :     }
    3070             : 
    3071           0 :     bool pushContinuableBlock() {
    3072           0 :         return encoder().writeOp(Op::Block) &&
    3073           0 :                encoder().writeFixedU8(uint8_t(ExprType::Void)) &&
    3074           0 :                continuableStack_.append(blockDepth_++);
    3075             :     }
    3076           0 :     bool popContinuableBlock() {
    3077           0 :         JS_ALWAYS_TRUE(continuableStack_.popCopy() == --blockDepth_);
    3078           0 :         return encoder().writeOp(Op::End);
    3079             :     }
    3080             : 
    3081           0 :     bool pushLoop() {
    3082           0 :         return encoder().writeOp(Op::Block) &&
    3083           0 :                encoder().writeFixedU8(uint8_t(ExprType::Void)) &&
    3084           0 :                encoder().writeOp(Op::Loop) &&
    3085           0 :                encoder().writeFixedU8(uint8_t(ExprType::Void)) &&
    3086           0 :                breakableStack_.append(blockDepth_++) &&
    3087           0 :                continuableStack_.append(blockDepth_++);
    3088             :     }
    3089           0 :     bool popLoop() {
    3090           0 :         JS_ALWAYS_TRUE(continuableStack_.popCopy() == --blockDepth_);
    3091           0 :         JS_ALWAYS_TRUE(breakableStack_.popCopy() == --blockDepth_);
    3092           0 :         return encoder().writeOp(Op::End) &&
    3093           0 :                encoder().writeOp(Op::End);
    3094             :     }
    3095             : 
    3096           0 :     bool pushIf(size_t* typeAt) {
    3097           0 :         ++blockDepth_;
    3098           0 :         return encoder().writeOp(Op::If) &&
    3099           0 :                encoder().writePatchableFixedU7(typeAt);
    3100             :     }
    3101           0 :     bool switchToElse() {
    3102           0 :         MOZ_ASSERT(blockDepth_ > 0);
    3103           0 :         return encoder().writeOp(Op::Else);
    3104             :     }
    3105           0 :     void setIfType(size_t typeAt, ExprType type) {
    3106           0 :         encoder().patchFixedU7(typeAt, uint8_t(type));
    3107           0 :     }
    3108           0 :     bool popIf() {
    3109           0 :         MOZ_ASSERT(blockDepth_ > 0);
    3110           0 :         --blockDepth_;
    3111           0 :         return encoder().writeOp(Op::End);
    3112             :     }
    3113           0 :     bool popIf(size_t typeAt, ExprType type) {
    3114           0 :         MOZ_ASSERT(blockDepth_ > 0);
    3115           0 :         --blockDepth_;
    3116           0 :         if (!encoder().writeOp(Op::End))
    3117           0 :             return false;
    3118             : 
    3119           0 :         setIfType(typeAt, type);
    3120           0 :         return true;
    3121             :     }
    3122             : 
    3123           0 :     bool writeBreakIf() {
    3124           0 :         return writeBr(breakableStack_.back(), Op::BrIf);
    3125             :     }
    3126           0 :     bool writeContinueIf() {
    3127           0 :         return writeBr(continuableStack_.back(), Op::BrIf);
    3128             :     }
    3129           0 :     bool writeUnlabeledBreakOrContinue(bool isBreak) {
    3130           0 :         return writeBr(isBreak? breakableStack_.back() : continuableStack_.back());
    3131             :     }
    3132           0 :     bool writeContinue() {
    3133           0 :         return writeBr(continuableStack_.back());
    3134             :     }
    3135             : 
    3136           0 :     bool addLabels(const NameVector& labels, uint32_t relativeBreakDepth,
    3137             :                    uint32_t relativeContinueDepth)
    3138             :     {
    3139           0 :         for (PropertyName* label : labels) {
    3140           0 :             if (!breakLabels_.putNew(label, blockDepth_ + relativeBreakDepth))
    3141           0 :                 return false;
    3142           0 :             if (!continueLabels_.putNew(label, blockDepth_ + relativeContinueDepth))
    3143           0 :                 return false;
    3144             :         }
    3145           0 :         return true;
    3146             :     }
    3147           0 :     void removeLabels(const NameVector& labels) {
    3148           0 :         for (PropertyName* label : labels) {
    3149           0 :             removeLabel(label, &breakLabels_);
    3150           0 :             removeLabel(label, &continueLabels_);
    3151             :         }
    3152           0 :     }
    3153           0 :     bool writeLabeledBreakOrContinue(PropertyName* label, bool isBreak) {
    3154           0 :         LabelMap& map = isBreak ? breakLabels_ : continueLabels_;
    3155           0 :         if (LabelMap::Ptr p = map.lookup(label))
    3156           0 :             return writeBr(p->value());
    3157           0 :         MOZ_CRASH("nonexistent label");
    3158             :     }
    3159             : 
    3160             :     /*************************************************** Read-only interface */
    3161             : 
    3162           0 :     const Local* lookupLocal(PropertyName* name) const {
    3163           0 :         if (auto p = locals_.lookup(name))
    3164           0 :             return &p->value();
    3165           0 :         return nullptr;
    3166             :     }
    3167             : 
    3168           0 :     const ModuleValidator::Global* lookupGlobal(PropertyName* name) const {
    3169           0 :         if (locals_.has(name))
    3170           0 :             return nullptr;
    3171           0 :         return m_.lookupGlobal(name);
    3172             :     }
    3173             : 
    3174           0 :     size_t numLocals() const { return locals_.count(); }
    3175             : 
    3176             :     /**************************************************** Encoding interface */
    3177             : 
    3178           0 :     Encoder& encoder() { return *encoder_; }
    3179             : 
    3180           0 :     MOZ_MUST_USE bool writeInt32Lit(int32_t i32) {
    3181           0 :         return encoder().writeOp(Op::I32Const) &&
    3182           0 :                encoder().writeVarS32(i32);
    3183             :     }
    3184           0 :     MOZ_MUST_USE bool writeConstExpr(const NumLit& lit) {
    3185           0 :         switch (lit.which()) {
    3186             :           case NumLit::Fixnum:
    3187             :           case NumLit::NegativeInt:
    3188             :           case NumLit::BigUnsigned:
    3189           0 :             return writeInt32Lit(lit.toInt32());
    3190             :           case NumLit::Float:
    3191           0 :             return encoder().writeOp(Op::F32Const) &&
    3192           0 :                    encoder().writeFixedF32(lit.toFloat());
    3193             :           case NumLit::Double:
    3194           0 :             return encoder().writeOp(Op::F64Const) &&
    3195           0 :                    encoder().writeFixedF64(lit.toDouble());
    3196             :           case NumLit::Int8x16:
    3197             :           case NumLit::Uint8x16:
    3198           0 :             return encoder().writeOp(MozOp::I8x16Const) &&
    3199           0 :                    encoder().writeFixedI8x16(lit.simdValue().asInt8x16());
    3200             :           case NumLit::Int16x8:
    3201             :           case NumLit::Uint16x8:
    3202           0 :             return encoder().writeOp(MozOp::I16x8Const) &&
    3203           0 :                    encoder().writeFixedI16x8(lit.simdValue().asInt16x8());
    3204             :           case NumLit::Int32x4:
    3205             :           case NumLit::Uint32x4:
    3206           0 :             return encoder().writeOp(MozOp::I32x4Const) &&
    3207           0 :                    encoder().writeFixedI32x4(lit.simdValue().asInt32x4());
    3208             :           case NumLit::Float32x4:
    3209           0 :             return encoder().writeOp(MozOp::F32x4Const) &&
    3210           0 :                    encoder().writeFixedF32x4(lit.simdValue().asFloat32x4());
    3211             :           case NumLit::Bool8x16:
    3212             :             // Boolean vectors use the Int8x16 memory representation.
    3213           0 :             return encoder().writeOp(MozOp::B8x16Const) &&
    3214           0 :                    encoder().writeFixedI8x16(lit.simdValue().asInt8x16());
    3215             :           case NumLit::Bool16x8:
    3216             :             // Boolean vectors use the Int16x8 memory representation.
    3217           0 :             return encoder().writeOp(MozOp::B16x8Const) &&
    3218           0 :                    encoder().writeFixedI16x8(lit.simdValue().asInt16x8());
    3219             :           case NumLit::Bool32x4:
    3220             :             // Boolean vectors use the Int32x4 memory representation.
    3221           0 :             return encoder().writeOp(MozOp::B32x4Const) &&
    3222           0 :                    encoder().writeFixedI32x4(lit.simdValue().asInt32x4());
    3223             :           case NumLit::OutOfRangeInt:
    3224           0 :             break;
    3225             :         }
    3226           0 :         MOZ_CRASH("unexpected literal type");
    3227             :     }
    3228           0 :     MOZ_MUST_USE bool writeCall(ParseNode* pn, Op op) {
    3229           0 :         return encoder().writeOp(op) &&
    3230           0 :                fg_.addCallSiteLineNum(m().tokenStream().srcCoords.lineNum(pn->pn_pos.begin));
    3231             :     }
    3232           0 :     MOZ_MUST_USE bool writeCall(ParseNode* pn, MozOp op) {
    3233           0 :         return encoder().writeOp(op) &&
    3234           0 :                fg_.addCallSiteLineNum(m().tokenStream().srcCoords.lineNum(pn->pn_pos.begin));
    3235             :     }
    3236           0 :     MOZ_MUST_USE bool prepareCall(ParseNode* pn) {
    3237           0 :         return fg_.addCallSiteLineNum(m().tokenStream().srcCoords.lineNum(pn->pn_pos.begin));
    3238             :     }
    3239           0 :     MOZ_MUST_USE bool writeSimdOp(SimdType simdType, SimdOperation simdOp) {
    3240           0 :         MozOp op = SimdToOp(simdType, simdOp);
    3241           0 :         if (op == MozOp::Limit)
    3242           0 :             return true;
    3243           0 :         return encoder().writeOp(op);
    3244             :     }
    3245             : };
    3246             : 
    3247             : } /* anonymous namespace */
    3248             : 
    3249             : /*****************************************************************************/
    3250             : // asm.js type-checking and code-generation algorithm
    3251             : 
    3252             : static bool
    3253           0 : CheckIdentifier(ModuleValidator& m, ParseNode* usepn, PropertyName* name)
    3254             : {
    3255           0 :     if (name == m.cx()->names().arguments || name == m.cx()->names().eval)
    3256           0 :         return m.failName(usepn, "'%s' is not an allowed identifier", name);
    3257           0 :     return true;
    3258             : }
    3259             : 
    3260             : static bool
    3261           0 : CheckModuleLevelName(ModuleValidator& m, ParseNode* usepn, PropertyName* name)
    3262             : {
    3263           0 :     if (!CheckIdentifier(m, usepn, name))
    3264           0 :         return false;
    3265             : 
    3266           0 :     if (name == m.moduleFunctionName() ||
    3267           0 :         name == m.globalArgumentName() ||
    3268           0 :         name == m.importArgumentName() ||
    3269           0 :         name == m.bufferArgumentName() ||
    3270           0 :         m.lookupGlobal(name))
    3271             :     {
    3272           0 :         return m.failName(usepn, "duplicate name '%s' not allowed", name);
    3273             :     }
    3274             : 
    3275           0 :     return true;
    3276             : }
    3277             : 
    3278             : static bool
    3279           0 : CheckFunctionHead(ModuleValidator& m, ParseNode* fn)
    3280             : {
    3281           0 :     if (fn->pn_funbox->hasRest())
    3282           0 :         return m.fail(fn, "rest args not allowed");
    3283           0 :     if (fn->pn_funbox->isExprBody())
    3284           0 :         return m.fail(fn, "expression closures not allowed");
    3285           0 :     if (fn->pn_funbox->hasDestructuringArgs)
    3286           0 :         return m.fail(fn, "destructuring args not allowed");
    3287           0 :     return true;
    3288             : }
    3289             : 
    3290             : static bool
    3291           0 : CheckArgument(ModuleValidator& m, ParseNode* arg, PropertyName** name)
    3292             : {
    3293           0 :     *name = nullptr;
    3294             : 
    3295           0 :     if (!arg->isKind(PNK_NAME))
    3296           0 :         return m.fail(arg, "argument is not a plain name");
    3297             : 
    3298           0 :     if (!CheckIdentifier(m, arg, arg->name()))
    3299           0 :         return false;
    3300             : 
    3301           0 :     *name = arg->name();
    3302           0 :     return true;
    3303             : }
    3304             : 
    3305             : static bool
    3306           0 : CheckModuleArgument(ModuleValidator& m, ParseNode* arg, PropertyName** name)
    3307             : {
    3308           0 :     if (!CheckArgument(m, arg, name))
    3309           0 :         return false;
    3310             : 
    3311           0 :     if (!CheckModuleLevelName(m, arg, *name))
    3312           0 :         return false;
    3313             : 
    3314           0 :     return true;
    3315             : }
    3316             : 
    3317             : static bool
    3318           0 : CheckModuleArguments(ModuleValidator& m, ParseNode* fn)
    3319             : {
    3320             :     unsigned numFormals;
    3321           0 :     ParseNode* arg1 = FunctionFormalParametersList(fn, &numFormals);
    3322           0 :     ParseNode* arg2 = arg1 ? NextNode(arg1) : nullptr;
    3323           0 :     ParseNode* arg3 = arg2 ? NextNode(arg2) : nullptr;
    3324             : 
    3325           0 :     if (numFormals > 3)
    3326           0 :         return m.fail(fn, "asm.js modules takes at most 3 argument");
    3327             : 
    3328           0 :     PropertyName* arg1Name = nullptr;
    3329           0 :     if (arg1 && !CheckModuleArgument(m, arg1, &arg1Name))
    3330           0 :         return false;
    3331           0 :     if (!m.initGlobalArgumentName(arg1Name))
    3332           0 :         return false;
    3333             : 
    3334           0 :     PropertyName* arg2Name = nullptr;
    3335           0 :     if (arg2 && !CheckModuleArgument(m, arg2, &arg2Name))
    3336           0 :         return false;
    3337           0 :     if (!m.initImportArgumentName(arg2Name))
    3338           0 :         return false;
    3339             : 
    3340           0 :     PropertyName* arg3Name = nullptr;
    3341           0 :     if (arg3 && !CheckModuleArgument(m, arg3, &arg3Name))
    3342           0 :         return false;
    3343           0 :     if (!m.initBufferArgumentName(arg3Name))
    3344           0 :         return false;
    3345             : 
    3346           0 :     return true;
    3347             : }
    3348             : 
    3349             : static bool
    3350           0 : CheckPrecedingStatements(ModuleValidator& m, ParseNode* stmtList)
    3351             : {
    3352           0 :     MOZ_ASSERT(stmtList->isKind(PNK_STATEMENTLIST));
    3353             : 
    3354           0 :     ParseNode* stmt = ListHead(stmtList);
    3355           0 :     for (unsigned i = 0, n = ListLength(stmtList); i < n; i++) {
    3356           0 :         if (!IsIgnoredDirective(m.cx(), stmt))
    3357           0 :             return m.fail(stmt, "invalid asm.js statement");
    3358             :     }
    3359             : 
    3360           0 :     return true;
    3361             : }
    3362             : 
    3363             : static bool
    3364           0 : CheckGlobalVariableInitConstant(ModuleValidator& m, PropertyName* varName, ParseNode* initNode,
    3365             :                                 bool isConst)
    3366             : {
    3367           0 :     NumLit lit = ExtractNumericLiteral(m, initNode);
    3368           0 :     if (!lit.valid())
    3369           0 :         return m.fail(initNode, "global initializer is out of representable integer range");
    3370             : 
    3371           0 :     Type canonicalType = Type::canonicalize(Type::lit(lit));
    3372           0 :     if (!canonicalType.isGlobalVarType())
    3373           0 :         return m.fail(initNode, "global variable type not allowed");
    3374             : 
    3375           0 :     return m.addGlobalVarInit(varName, lit, canonicalType, isConst);
    3376             : }
    3377             : 
    3378             : static bool
    3379           0 : CheckTypeAnnotation(ModuleValidator& m, ParseNode* coercionNode, Type* coerceTo,
    3380             :                     ParseNode** coercedExpr = nullptr)
    3381             : {
    3382           0 :     switch (coercionNode->getKind()) {
    3383             :       case PNK_BITOR: {
    3384           0 :         ParseNode* rhs = BitwiseRight(coercionNode);
    3385             :         uint32_t i;
    3386           0 :         if (!IsLiteralInt(m, rhs, &i) || i != 0)
    3387           0 :             return m.fail(rhs, "must use |0 for argument/return coercion");
    3388           0 :         *coerceTo = Type::Int;
    3389           0 :         if (coercedExpr)
    3390           0 :             *coercedExpr = BitwiseLeft(coercionNode);
    3391           0 :         return true;
    3392             :       }
    3393             :       case PNK_POS: {
    3394           0 :         *coerceTo = Type::Double;
    3395           0 :         if (coercedExpr)
    3396           0 :             *coercedExpr = UnaryKid(coercionNode);
    3397           0 :         return true;
    3398             :       }
    3399             :       case PNK_CALL: {
    3400           0 :         if (IsCoercionCall(m, coercionNode, coerceTo, coercedExpr))
    3401           0 :             return true;
    3402           0 :         break;
    3403             :       }
    3404             :       default:;
    3405             :     }
    3406             : 
    3407           0 :     return m.fail(coercionNode, "must be of the form +x, x|0, fround(x), or a SIMD check(x)");
    3408             : }
    3409             : 
    3410             : static bool
    3411           0 : CheckGlobalVariableInitImport(ModuleValidator& m, PropertyName* varName, ParseNode* initNode,
    3412             :                               bool isConst)
    3413             : {
    3414           0 :     Type coerceTo;
    3415             :     ParseNode* coercedExpr;
    3416           0 :     if (!CheckTypeAnnotation(m, initNode, &coerceTo, &coercedExpr))
    3417           0 :         return false;
    3418             : 
    3419           0 :     if (!coercedExpr->isKind(PNK_DOT))
    3420           0 :         return m.failName(coercedExpr, "invalid import expression for global '%s'", varName);
    3421             : 
    3422           0 :     if (!coerceTo.isGlobalVarType())
    3423           0 :         return m.fail(initNode, "global variable type not allowed");
    3424             : 
    3425           0 :     ParseNode* base = DotBase(coercedExpr);
    3426           0 :     PropertyName* field = DotMember(coercedExpr);
    3427             : 
    3428           0 :     PropertyName* importName = m.importArgumentName();
    3429           0 :     if (!importName)
    3430           0 :         return m.fail(coercedExpr, "cannot import without an asm.js foreign parameter");
    3431           0 :     if (!IsUseOfName(base, importName))
    3432           0 :         return m.failName(coercedExpr, "base of import expression must be '%s'", importName);
    3433             : 
    3434           0 :     return m.addGlobalVarImport(varName, field, coerceTo, isConst);
    3435             : }
    3436             : 
    3437             : static bool
    3438           0 : IsArrayViewCtorName(ModuleValidator& m, PropertyName* name, Scalar::Type* type)
    3439             : {
    3440           0 :     JSAtomState& names = m.cx()->names();
    3441           0 :     if (name == names.Int8Array) {
    3442           0 :         *type = Scalar::Int8;
    3443           0 :     } else if (name == names.Uint8Array) {
    3444           0 :         *type = Scalar::Uint8;
    3445           0 :     } else if (name == names.Int16Array) {
    3446           0 :         *type = Scalar::Int16;
    3447           0 :     } else if (name == names.Uint16Array) {
    3448           0 :         *type = Scalar::Uint16;
    3449           0 :     } else if (name == names.Int32Array) {
    3450           0 :         *type = Scalar::Int32;
    3451           0 :     } else if (name == names.Uint32Array) {
    3452           0 :         *type = Scalar::Uint32;
    3453           0 :     } else if (name == names.Float32Array) {
    3454           0 :         *type = Scalar::Float32;
    3455           0 :     } else if (name == names.Float64Array) {
    3456           0 :         *type = Scalar::Float64;
    3457             :     } else {
    3458           0 :         return false;
    3459             :     }
    3460           0 :     return true;
    3461             : }
    3462             : 
    3463             : static bool
    3464           0 : CheckNewArrayViewArgs(ModuleValidator& m, ParseNode* ctorExpr, PropertyName* bufferName)
    3465             : {
    3466           0 :     ParseNode* bufArg = NextNode(ctorExpr);
    3467           0 :     if (!bufArg || NextNode(bufArg) != nullptr)
    3468           0 :         return m.fail(ctorExpr, "array view constructor takes exactly one argument");
    3469             : 
    3470           0 :     if (!IsUseOfName(bufArg, bufferName))
    3471           0 :         return m.failName(bufArg, "argument to array view constructor must be '%s'", bufferName);
    3472             : 
    3473           0 :     return true;
    3474             : }
    3475             : 
    3476             : static bool
    3477           0 : CheckNewArrayView(ModuleValidator& m, PropertyName* varName, ParseNode* newExpr)
    3478             : {
    3479           0 :     PropertyName* globalName = m.globalArgumentName();
    3480           0 :     if (!globalName)
    3481           0 :         return m.fail(newExpr, "cannot create array view without an asm.js global parameter");
    3482             : 
    3483           0 :     PropertyName* bufferName = m.bufferArgumentName();
    3484           0 :     if (!bufferName)
    3485           0 :         return m.fail(newExpr, "cannot create array view without an asm.js heap parameter");
    3486             : 
    3487           0 :     ParseNode* ctorExpr = ListHead(newExpr);
    3488             : 
    3489             :     PropertyName* field;
    3490             :     Scalar::Type type;
    3491           0 :     if (ctorExpr->isKind(PNK_DOT)) {
    3492           0 :         ParseNode* base = DotBase(ctorExpr);
    3493             : 
    3494           0 :         if (!IsUseOfName(base, globalName))
    3495           0 :             return m.failName(base, "expecting '%s.*Array", globalName);
    3496             : 
    3497           0 :         field = DotMember(ctorExpr);
    3498           0 :         if (!IsArrayViewCtorName(m, field, &type))
    3499           0 :             return m.fail(ctorExpr, "could not match typed array name");
    3500             :     } else {
    3501           0 :         if (!ctorExpr->isKind(PNK_NAME))
    3502           0 :             return m.fail(ctorExpr, "expecting name of imported array view constructor");
    3503             : 
    3504           0 :         PropertyName* globalName = ctorExpr->name();
    3505           0 :         const ModuleValidator::Global* global = m.lookupGlobal(globalName);
    3506           0 :         if (!global)
    3507           0 :             return m.failName(ctorExpr, "%s not found in module global scope", globalName);
    3508             : 
    3509           0 :         if (global->which() != ModuleValidator::Global::ArrayViewCtor)
    3510           0 :             return m.failName(ctorExpr, "%s must be an imported array view constructor", globalName);
    3511             : 
    3512           0 :         field = nullptr;
    3513           0 :         type = global->viewType();
    3514             :     }
    3515             : 
    3516           0 :     if (!CheckNewArrayViewArgs(m, ctorExpr, bufferName))
    3517           0 :         return false;
    3518             : 
    3519           0 :     return m.addArrayView(varName, type, field);
    3520             : }
    3521             : 
    3522             : static bool
    3523           0 : IsSimdValidOperationType(SimdType type, SimdOperation op)
    3524             : {
    3525             : #define CASE(op) case SimdOperation::Fn_##op:
    3526           0 :     switch(type) {
    3527             :       case SimdType::Int8x16:
    3528           0 :         switch (op) {
    3529             :           case SimdOperation::Constructor:
    3530             :           case SimdOperation::Fn_fromUint8x16Bits:
    3531             :           case SimdOperation::Fn_fromUint16x8Bits:
    3532             :           case SimdOperation::Fn_fromUint32x4Bits:
    3533           0 :           FORALL_INT8X16_ASMJS_OP(CASE) return true;
    3534           0 :           default: return false;
    3535             :         }
    3536             :         break;
    3537             :       case SimdType::Int16x8:
    3538           0 :         switch (op) {
    3539             :           case SimdOperation::Constructor:
    3540             :           case SimdOperation::Fn_fromUint8x16Bits:
    3541             :           case SimdOperation::Fn_fromUint16x8Bits:
    3542             :           case SimdOperation::Fn_fromUint32x4Bits:
    3543           0 :           FORALL_INT16X8_ASMJS_OP(CASE) return true;
    3544           0 :           default: return false;
    3545             :         }
    3546             :         break;
    3547             :       case SimdType::Int32x4:
    3548           0 :         switch (op) {
    3549             :           case SimdOperation::Constructor:
    3550             :           case SimdOperation::Fn_fromUint8x16Bits:
    3551             :           case SimdOperation::Fn_fromUint16x8Bits:
    3552             :           case SimdOperation::Fn_fromUint32x4Bits:
    3553           0 :           FORALL_INT32X4_ASMJS_OP(CASE) return true;
    3554           0 :           default: return false;
    3555             :         }
    3556             :         break;
    3557             :       case SimdType::Uint8x16:
    3558           0 :         switch (op) {
    3559             :           case SimdOperation::Constructor:
    3560             :           case SimdOperation::Fn_fromInt8x16Bits:
    3561             :           case SimdOperation::Fn_fromUint16x8Bits:
    3562             :           case SimdOperation::Fn_fromUint32x4Bits:
    3563           0 :           FORALL_INT8X16_ASMJS_OP(CASE) return true;
    3564           0 :           default: return false;
    3565             :         }
    3566             :         break;
    3567             :       case SimdType::Uint16x8:
    3568           0 :         switch (op) {
    3569             :           case SimdOperation::Constructor:
    3570             :           case SimdOperation::Fn_fromUint8x16Bits:
    3571             :           case SimdOperation::Fn_fromInt16x8Bits:
    3572             :           case SimdOperation::Fn_fromUint32x4Bits:
    3573           0 :           FORALL_INT16X8_ASMJS_OP(CASE) return true;
    3574           0 :           default: return false;
    3575             :         }
    3576             :         break;
    3577             :       case SimdType::Uint32x4:
    3578           0 :         switch (op) {
    3579             :           case SimdOperation::Constructor:
    3580             :           case SimdOperation::Fn_fromUint8x16Bits:
    3581             :           case SimdOperation::Fn_fromUint16x8Bits:
    3582             :           case SimdOperation::Fn_fromInt32x4Bits:
    3583           0 :           FORALL_INT32X4_ASMJS_OP(CASE) return true;
    3584           0 :           default: return false;
    3585             :         }
    3586             :         break;
    3587             :       case SimdType::Float32x4:
    3588           0 :         switch (op) {
    3589             :           case SimdOperation::Constructor:
    3590             :           case SimdOperation::Fn_fromUint8x16Bits:
    3591             :           case SimdOperation::Fn_fromUint16x8Bits:
    3592             :           case SimdOperation::Fn_fromUint32x4Bits:
    3593           0 :           FORALL_FLOAT32X4_ASMJS_OP(CASE) return true;
    3594           0 :           default: return false;
    3595             :         }
    3596             :         break;
    3597             :       case SimdType::Bool8x16:
    3598             :       case SimdType::Bool16x8:
    3599             :       case SimdType::Bool32x4:
    3600           0 :         switch (op) {
    3601             :           case SimdOperation::Constructor:
    3602           0 :           FORALL_BOOL_SIMD_OP(CASE) return true;
    3603           0 :           default: return false;
    3604             :         }
    3605             :         break;
    3606             :       default:
    3607             :         // Unimplemented SIMD type.
    3608           0 :         return false;
    3609             :     }
    3610             : #undef CASE
    3611             : }
    3612             : 
    3613             : static bool
    3614           0 : CheckGlobalMathImport(ModuleValidator& m, ParseNode* initNode, PropertyName* varName,
    3615             :                       PropertyName* field)
    3616             : {
    3617             :     // Math builtin, with the form glob.Math.[[builtin]]
    3618           0 :     ModuleValidator::MathBuiltin mathBuiltin;
    3619           0 :     if (!m.lookupStandardLibraryMathName(field, &mathBuiltin))
    3620           0 :         return m.failName(initNode, "'%s' is not a standard Math builtin", field);
    3621             : 
    3622           0 :     switch (mathBuiltin.kind) {
    3623             :       case ModuleValidator::MathBuiltin::Function:
    3624           0 :         return m.addMathBuiltinFunction(varName, mathBuiltin.u.func, field);
    3625             :       case ModuleValidator::MathBuiltin::Constant:
    3626           0 :         return m.addMathBuiltinConstant(varName, mathBuiltin.u.cst, field);
    3627             :       default:
    3628           0 :         break;
    3629             :     }
    3630           0 :     MOZ_CRASH("unexpected or uninitialized math builtin type");
    3631             : }
    3632             : 
    3633             : static bool
    3634           0 : CheckGlobalAtomicsImport(ModuleValidator& m, ParseNode* initNode, PropertyName* varName,
    3635             :                          PropertyName* field)
    3636             : {
    3637             :     // Atomics builtin, with the form glob.Atomics.[[builtin]]
    3638             :     AsmJSAtomicsBuiltinFunction func;
    3639           0 :     if (!m.lookupStandardLibraryAtomicsName(field, &func))
    3640           0 :         return m.failName(initNode, "'%s' is not a standard Atomics builtin", field);
    3641             : 
    3642           0 :     return m.addAtomicsBuiltinFunction(varName, func, field);
    3643             : }
    3644             : 
    3645             : static bool
    3646           0 : CheckGlobalSimdImport(ModuleValidator& m, ParseNode* initNode, PropertyName* varName,
    3647             :                       PropertyName* field)
    3648             : {
    3649           0 :     if (!m.supportsSimd())
    3650           0 :         return m.fail(initNode, "SIMD is not supported on this platform");
    3651             : 
    3652             :     // SIMD constructor, with the form glob.SIMD.[[type]]
    3653             :     SimdType simdType;
    3654           0 :     if (!IsSimdTypeName(m.cx()->names(), field, &simdType))
    3655           0 :         return m.failName(initNode, "'%s' is not a standard SIMD type", field);
    3656             : 
    3657             :     // IsSimdTypeName will return true for any SIMD type supported by the VM.
    3658             :     //
    3659             :     // Since we may not support all of those SIMD types in asm.js, use the
    3660             :     // asm.js-specific IsSimdValidOperationType() to check if this specific
    3661             :     // constructor is supported in asm.js.
    3662           0 :     if (!IsSimdValidOperationType(simdType, SimdOperation::Constructor))
    3663           0 :         return m.failName(initNode, "'%s' is not a supported SIMD type", field);
    3664             : 
    3665           0 :     return m.addSimdCtor(varName, simdType, field);
    3666             : }
    3667             : 
    3668             : static bool
    3669           0 : CheckGlobalSimdOperationImport(ModuleValidator& m, const ModuleValidator::Global* global,
    3670             :                                ParseNode* initNode, PropertyName* varName, PropertyName* opName)
    3671             : {
    3672           0 :     SimdType simdType = global->simdCtorType();
    3673             :     SimdOperation simdOp;
    3674           0 :     if (!m.lookupStandardSimdOpName(opName, &simdOp))
    3675           0 :         return m.failName(initNode, "'%s' is not a standard SIMD operation", opName);
    3676           0 :     if (!IsSimdValidOperationType(simdType, simdOp))
    3677           0 :         return m.failName(initNode, "'%s' is not an operation supported by the SIMD type", opName);
    3678           0 :     return m.addSimdOperation(varName, simdType, simdOp, opName);
    3679             : }
    3680             : 
    3681             : static bool
    3682           0 : CheckGlobalDotImport(ModuleValidator& m, PropertyName* varName, ParseNode* initNode)
    3683             : {
    3684           0 :     ParseNode* base = DotBase(initNode);
    3685           0 :     PropertyName* field = DotMember(initNode);
    3686             : 
    3687           0 :     if (base->isKind(PNK_DOT)) {
    3688           0 :         ParseNode* global = DotBase(base);
    3689           0 :         PropertyName* mathOrAtomicsOrSimd = DotMember(base);
    3690             : 
    3691           0 :         PropertyName* globalName = m.globalArgumentName();
    3692           0 :         if (!globalName)
    3693           0 :             return m.fail(base, "import statement requires the module have a stdlib parameter");
    3694             : 
    3695           0 :         if (!IsUseOfName(global, globalName)) {
    3696           0 :             if (global->isKind(PNK_DOT)) {
    3697             :                 return m.failName(base, "imports can have at most two dot accesses "
    3698           0 :                                         "(e.g. %s.Math.sin)", globalName);
    3699             :             }
    3700           0 :             return m.failName(base, "expecting %s.*", globalName);
    3701             :         }
    3702             : 
    3703           0 :         if (mathOrAtomicsOrSimd == m.cx()->names().Math)
    3704           0 :             return CheckGlobalMathImport(m, initNode, varName, field);
    3705           0 :         if (mathOrAtomicsOrSimd == m.cx()->names().Atomics)
    3706           0 :             return CheckGlobalAtomicsImport(m, initNode, varName, field);
    3707           0 :         if (mathOrAtomicsOrSimd == m.cx()->names().SIMD)
    3708           0 :             return CheckGlobalSimdImport(m, initNode, varName, field);
    3709           0 :         return m.failName(base, "expecting %s.{Math|SIMD}", globalName);
    3710             :     }
    3711             : 
    3712           0 :     if (!base->isKind(PNK_NAME))
    3713           0 :         return m.fail(base, "expected name of variable or parameter");
    3714             : 
    3715           0 :     if (base->name() == m.globalArgumentName()) {
    3716           0 :         if (field == m.cx()->names().NaN)
    3717           0 :             return m.addGlobalConstant(varName, GenericNaN(), field);
    3718           0 :         if (field == m.cx()->names().Infinity)
    3719           0 :             return m.addGlobalConstant(varName, PositiveInfinity<double>(), field);
    3720             : 
    3721             :         Scalar::Type type;
    3722           0 :         if (IsArrayViewCtorName(m, field, &type))
    3723           0 :             return m.addArrayViewCtor(varName, type, field);
    3724             : 
    3725           0 :         return m.failName(initNode, "'%s' is not a standard constant or typed array name", field);
    3726             :     }
    3727             : 
    3728           0 :     if (base->name() == m.importArgumentName())
    3729           0 :         return m.addFFI(varName, field);
    3730             : 
    3731           0 :     const ModuleValidator::Global* global = m.lookupGlobal(base->name());
    3732           0 :     if (!global)
    3733           0 :         return m.failName(initNode, "%s not found in module global scope", base->name());
    3734             : 
    3735           0 :     if (!global->isSimdCtor())
    3736           0 :         return m.failName(base, "expecting SIMD constructor name, got %s", field);
    3737             : 
    3738           0 :     return CheckGlobalSimdOperationImport(m, global, initNode, varName, field);
    3739             : }
    3740             : 
    3741             : static bool
    3742           0 : CheckModuleGlobal(ModuleValidator& m, ParseNode* var, bool isConst)
    3743             : {
    3744           0 :     if (!var->isKind(PNK_NAME))
    3745           0 :         return m.fail(var, "import variable is not a plain name");
    3746             : 
    3747           0 :     if (!CheckModuleLevelName(m, var, var->name()))
    3748           0 :         return false;
    3749             : 
    3750           0 :     ParseNode* initNode = MaybeInitializer(var);
    3751           0 :     if (!initNode)
    3752           0 :         return m.fail(var, "module import needs initializer");
    3753             : 
    3754           0 :     if (IsNumericLiteral(m, initNode))
    3755           0 :         return CheckGlobalVariableInitConstant(m, var->name(), initNode, isConst);
    3756             : 
    3757           0 :     if (initNode->isKind(PNK_BITOR) || initNode->isKind(PNK_POS) || initNode->isKind(PNK_CALL))
    3758           0 :         return CheckGlobalVariableInitImport(m, var->name(), initNode, isConst);
    3759             : 
    3760           0 :     if (initNode->isKind(PNK_NEW))
    3761           0 :         return CheckNewArrayView(m, var->name(), initNode);
    3762             : 
    3763           0 :     if (initNode->isKind(PNK_DOT))
    3764           0 :         return CheckGlobalDotImport(m, var->name(), initNode);
    3765             : 
    3766           0 :     return m.fail(initNode, "unsupported import expression");
    3767             : }
    3768             : 
    3769             : static bool
    3770           0 : CheckModuleProcessingDirectives(ModuleValidator& m)
    3771             : {
    3772           0 :     TokenStream& ts = m.parser().tokenStream;
    3773             :     while (true) {
    3774             :         bool matched;
    3775           0 :         if (!ts.matchToken(&matched, TOK_STRING, TokenStream::Operand))
    3776           0 :             return false;
    3777           0 :         if (!matched)
    3778           0 :             return true;
    3779             : 
    3780           0 :         if (!IsIgnoredDirectiveName(m.cx(), ts.currentToken().atom()))
    3781           0 :             return m.failCurrentOffset("unsupported processing directive");
    3782             : 
    3783             :         TokenKind tt;
    3784           0 :         if (!ts.getToken(&tt))
    3785           0 :             return false;
    3786           0 :         if (tt != TOK_SEMI)
    3787           0 :             return m.failCurrentOffset("expected semicolon after string literal");
    3788           0 :     }
    3789             : }
    3790             : 
    3791             : static bool
    3792           0 : CheckModuleGlobals(ModuleValidator& m)
    3793             : {
    3794             :     while (true) {
    3795             :         ParseNode* varStmt;
    3796           0 :         if (!ParseVarOrConstStatement(m.parser(), &varStmt))
    3797           0 :             return false;
    3798           0 :         if (!varStmt)
    3799           0 :             break;
    3800           0 :         for (ParseNode* var = VarListHead(varStmt); var; var = NextNode(var)) {
    3801           0 :             if (!CheckModuleGlobal(m, var, varStmt->isKind(PNK_CONST)))
    3802           0 :                 return false;
    3803             :         }
    3804           0 :     }
    3805             : 
    3806           0 :     return true;
    3807             : }
    3808             : 
    3809             : static bool
    3810           0 : ArgFail(FunctionValidator& f, PropertyName* argName, ParseNode* stmt)
    3811             : {
    3812             :     return f.failName(stmt, "expecting argument type declaration for '%s' of the "
    3813           0 :                       "form 'arg = arg|0' or 'arg = +arg' or 'arg = fround(arg)'", argName);
    3814             : }
    3815             : 
    3816             : static bool
    3817           0 : CheckArgumentType(FunctionValidator& f, ParseNode* stmt, PropertyName* name, Type* type)
    3818             : {
    3819           0 :     if (!stmt || !IsExpressionStatement(stmt))
    3820           0 :         return ArgFail(f, name, stmt ? stmt : f.fn());
    3821             : 
    3822           0 :     ParseNode* initNode = ExpressionStatementExpr(stmt);
    3823           0 :     if (!initNode || !initNode->isKind(PNK_ASSIGN))
    3824           0 :         return ArgFail(f, name, stmt);
    3825             : 
    3826           0 :     ParseNode* argNode = BinaryLeft(initNode);
    3827           0 :     ParseNode* coercionNode = BinaryRight(initNode);
    3828             : 
    3829           0 :     if (!IsUseOfName(argNode, name))
    3830           0 :         return ArgFail(f, name, stmt);
    3831             : 
    3832             :     ParseNode* coercedExpr;
    3833           0 :     if (!CheckTypeAnnotation(f.m(), coercionNode, type, &coercedExpr))
    3834           0 :         return false;
    3835             : 
    3836           0 :     if (!type->isArgType())
    3837           0 :         return f.failName(stmt, "invalid type for argument '%s'", name);
    3838             : 
    3839           0 :     if (!IsUseOfName(coercedExpr, name))
    3840           0 :         return ArgFail(f, name, stmt);
    3841             : 
    3842           0 :     return true;
    3843             : }
    3844             : 
    3845             : static bool
    3846           0 : CheckProcessingDirectives(ModuleValidator& m, ParseNode** stmtIter)
    3847             : {
    3848           0 :     ParseNode* stmt = *stmtIter;
    3849             : 
    3850           0 :     while (stmt && IsIgnoredDirective(m.cx(), stmt))
    3851           0 :         stmt = NextNode(stmt);
    3852             : 
    3853           0 :     *stmtIter = stmt;
    3854           0 :     return true;
    3855             : }
    3856             : 
    3857             : static bool
    3858           0 : CheckArguments(FunctionValidator& f, ParseNode** stmtIter, ValTypeVector* argTypes)
    3859             : {
    3860           0 :     ParseNode* stmt = *stmtIter;
    3861             : 
    3862             :     unsigned numFormals;
    3863           0 :     ParseNode* argpn = FunctionFormalParametersList(f.fn(), &numFormals);
    3864             : 
    3865           0 :     for (unsigned i = 0; i < numFormals; i++, argpn = NextNode(argpn), stmt = NextNode(stmt)) {
    3866             :         PropertyName* name;
    3867           0 :         if (!CheckArgument(f.m(), argpn, &name))
    3868           0 :             return false;
    3869             : 
    3870           0 :         Type type;
    3871           0 :         if (!CheckArgumentType(f, stmt, name, &type))
    3872           0 :             return false;
    3873             : 
    3874           0 :         if (!argTypes->append(type.canonicalToValType()))
    3875           0 :             return false;
    3876             : 
    3877           0 :         if (!f.addLocal(argpn, name, type))
    3878           0 :             return false;
    3879             :     }
    3880             : 
    3881           0 :     *stmtIter = stmt;
    3882           0 :     return true;
    3883             : }
    3884             : 
    3885             : static bool
    3886           0 : IsLiteralOrConst(FunctionValidator& f, ParseNode* pn, NumLit* lit)
    3887             : {
    3888           0 :     if (pn->isKind(PNK_NAME)) {
    3889           0 :         const ModuleValidator::Global* global = f.lookupGlobal(pn->name());
    3890           0 :         if (!global || global->which() != ModuleValidator::Global::ConstantLiteral)
    3891           0 :             return false;
    3892             : 
    3893           0 :         *lit = global->constLiteralValue();
    3894           0 :         return true;
    3895             :     }
    3896             : 
    3897           0 :     bool isSimd = false;
    3898           0 :     if (!IsNumericLiteral(f.m(), pn, &isSimd))
    3899           0 :         return false;
    3900             : 
    3901           0 :     if (isSimd)
    3902           0 :         f.setUsesSimd();
    3903             : 
    3904           0 :     *lit = ExtractNumericLiteral(f.m(), pn);
    3905           0 :     return true;
    3906             : }
    3907             : 
    3908             : static bool
    3909           0 : CheckFinalReturn(FunctionValidator& f, ParseNode* lastNonEmptyStmt)
    3910             : {
    3911           0 :     if (!f.encoder().writeOp(Op::End))
    3912           0 :         return false;
    3913             : 
    3914           0 :     if (!f.hasAlreadyReturned()) {
    3915           0 :         f.setReturnedType(ExprType::Void);
    3916           0 :         return true;
    3917             :     }
    3918             : 
    3919           0 :     if (!lastNonEmptyStmt->isKind(PNK_RETURN) && !IsVoid(f.returnedType()))
    3920           0 :         return f.fail(lastNonEmptyStmt, "void incompatible with previous return type");
    3921             : 
    3922           0 :     return true;
    3923             : }
    3924             : 
    3925             : static bool
    3926           0 : CheckVariable(FunctionValidator& f, ParseNode* var, ValTypeVector* types, Vector<NumLit>* inits)
    3927             : {
    3928           0 :     if (!var->isKind(PNK_NAME))
    3929           0 :         return f.fail(var, "local variable is not a plain name");
    3930             : 
    3931           0 :     PropertyName* name = var->name();
    3932             : 
    3933           0 :     if (!CheckIdentifier(f.m(), var, name))
    3934           0 :         return false;
    3935             : 
    3936           0 :     ParseNode* initNode = MaybeInitializer(var);
    3937           0 :     if (!initNode)
    3938           0 :         return f.failName(var, "var '%s' needs explicit type declaration via an initial value", name);
    3939             : 
    3940           0 :     NumLit lit;
    3941           0 :     if (!IsLiteralOrConst(f, initNode, &lit))
    3942           0 :         return f.failName(var, "var '%s' initializer must be literal or const literal", name);
    3943             : 
    3944           0 :     if (!lit.valid())
    3945           0 :         return f.failName(var, "var '%s' initializer out of range", name);
    3946             : 
    3947           0 :     Type type = Type::canonicalize(Type::lit(lit));
    3948             : 
    3949           0 :     return f.addLocal(var, name, type) &&
    3950           0 :            types->append(type.canonicalToValType()) &&
    3951           0 :            inits->append(lit);
    3952             : }
    3953             : 
    3954             : static bool
    3955           0 : CheckVariables(FunctionValidator& f, ParseNode** stmtIter)
    3956             : {
    3957           0 :     ParseNode* stmt = *stmtIter;
    3958             : 
    3959           0 :     uint32_t firstVar = f.numLocals();
    3960             : 
    3961           0 :     ValTypeVector types;
    3962           0 :     Vector<NumLit> inits(f.cx());
    3963             : 
    3964           0 :     for (; stmt && stmt->isKind(PNK_VAR); stmt = NextNonEmptyStatement(stmt)) {
    3965           0 :         for (ParseNode* var = VarListHead(stmt); var; var = NextNode(var)) {
    3966           0 :             if (!CheckVariable(f, var, &types, &inits))
    3967           0 :                 return false;
    3968             :         }
    3969             :     }
    3970             : 
    3971           0 :     MOZ_ASSERT(f.encoder().empty());
    3972             : 
    3973           0 :     if (!EncodeLocalEntries(f.encoder(), types))
    3974           0 :         return false;
    3975             : 
    3976           0 :     for (uint32_t i = 0; i < inits.length(); i++) {
    3977           0 :         NumLit lit = inits[i];
    3978           0 :         if (lit.isZeroBits())
    3979           0 :             continue;
    3980           0 :         if (!f.writeConstExpr(lit))
    3981           0 :             return false;
    3982           0 :         if (!f.encoder().writeOp(Op::SetLocal))
    3983           0 :             return false;
    3984           0 :         if (!f.encoder().writeVarU32(firstVar + i))
    3985           0 :             return false;
    3986             :     }
    3987             : 
    3988           0 :     *stmtIter = stmt;
    3989           0 :     return true;
    3990             : }
    3991             : 
    3992             : static bool
    3993             : CheckExpr(FunctionValidator& f, ParseNode* op, Type* type);
    3994             : 
    3995             : static bool
    3996           0 : CheckNumericLiteral(FunctionValidator& f, ParseNode* num, Type* type)
    3997             : {
    3998           0 :     NumLit lit = ExtractNumericLiteral(f.m(), num);
    3999           0 :     if (!lit.valid())
    4000           0 :         return f.fail(num, "numeric literal out of representable integer range");
    4001           0 :     *type = Type::lit(lit);
    4002           0 :     return f.writeConstExpr(lit);
    4003             : }
    4004             : 
    4005             : static bool
    4006           0 : CheckVarRef(FunctionValidator& f, ParseNode* varRef, Type* type)
    4007             : {
    4008           0 :     PropertyName* name = varRef->name();
    4009             : 
    4010           0 :     if (const FunctionValidator::Local* local = f.lookupLocal(name)) {
    4011           0 :         if (!f.encoder().writeOp(Op::GetLocal))
    4012           0 :             return false;
    4013           0 :         if (!f.encoder().writeVarU32(local->slot))
    4014           0 :             return false;
    4015           0 :         *type = local->type;
    4016           0 :         return true;
    4017             :     }
    4018             : 
    4019           0 :     if (const ModuleValidator::Global* global = f.lookupGlobal(name)) {
    4020           0 :         switch (global->which()) {
    4021             :           case ModuleValidator::Global::ConstantLiteral:
    4022           0 :             *type = global->varOrConstType();
    4023           0 :             return f.writeConstExpr(global->constLiteralValue());
    4024             :           case ModuleValidator::Global::ConstantImport:
    4025             :           case ModuleValidator::Global::Variable: {
    4026           0 :             *type = global->varOrConstType();
    4027           0 :             return f.encoder().writeOp(Op::GetGlobal) &&
    4028           0 :                    f.encoder().writeVarU32(global->varOrConstIndex());
    4029             :           }
    4030             :           case ModuleValidator::Global::Function:
    4031             :           case ModuleValidator::Global::FFI:
    4032             :           case ModuleValidator::Global::MathBuiltinFunction:
    4033             :           case ModuleValidator::Global::AtomicsBuiltinFunction:
    4034             :           case ModuleValidator::Global::FuncPtrTable:
    4035             :           case ModuleValidator::Global::ArrayView:
    4036             :           case ModuleValidator::Global::ArrayViewCtor:
    4037             :           case ModuleValidator::Global::SimdCtor:
    4038             :           case ModuleValidator::Global::SimdOp:
    4039           0 :             break;
    4040             :         }
    4041           0 :         return f.failName(varRef, "'%s' may not be accessed by ordinary expressions", name);
    4042             :     }
    4043             : 
    4044           0 :     return f.failName(varRef, "'%s' not found in local or asm.js module scope", name);
    4045             : }
    4046             : 
    4047             : static inline bool
    4048           0 : IsLiteralOrConstInt(FunctionValidator& f, ParseNode* pn, uint32_t* u32)
    4049             : {
    4050           0 :     NumLit lit;
    4051           0 :     if (!IsLiteralOrConst(f, pn, &lit))
    4052           0 :         return false;
    4053             : 
    4054           0 :     return IsLiteralInt(lit, u32);
    4055             : }
    4056             : 
    4057             : static const int32_t NoMask = -1;
    4058             : static const bool YesSimd = true;
    4059             : static const bool NoSimd = false;
    4060             : 
    4061             : static bool
    4062           0 : CheckArrayAccess(FunctionValidator& f, ParseNode* viewName, ParseNode* indexExpr,
    4063             :                  bool isSimd, Scalar::Type* viewType)
    4064             : {
    4065           0 :     if (!viewName->isKind(PNK_NAME))
    4066           0 :         return f.fail(viewName, "base of array access must be a typed array view name");
    4067             : 
    4068           0 :     const ModuleValidator::Global* global = f.lookupGlobal(viewName->name());
    4069           0 :     if (!global || !global->isAnyArrayView())
    4070           0 :         return f.fail(viewName, "base of array access must be a typed array view name");
    4071             : 
    4072           0 :     *viewType = global->viewType();
    4073             : 
    4074             :     uint32_t index;
    4075           0 :     if (IsLiteralOrConstInt(f, indexExpr, &index)) {
    4076           0 :         uint64_t byteOffset = uint64_t(index) << TypedArrayShift(*viewType);
    4077           0 :         uint64_t width = isSimd ? Simd128DataSize : TypedArrayElemSize(*viewType);
    4078           0 :         if (!f.m().tryConstantAccess(byteOffset, width))
    4079           0 :             return f.fail(indexExpr, "constant index out of range");
    4080             : 
    4081           0 :         return f.writeInt32Lit(byteOffset);
    4082             :     }
    4083             : 
    4084             :     // Mask off the low bits to account for the clearing effect of a right shift
    4085             :     // followed by the left shift implicit in the array access. E.g., H32[i>>2]
    4086             :     // loses the low two bits.
    4087           0 :     int32_t mask = ~(TypedArrayElemSize(*viewType) - 1);
    4088             : 
    4089           0 :     if (indexExpr->isKind(PNK_RSH)) {
    4090           0 :         ParseNode* shiftAmountNode = BitwiseRight(indexExpr);
    4091             : 
    4092             :         uint32_t shift;
    4093           0 :         if (!IsLiteralInt(f.m(), shiftAmountNode, &shift))
    4094           0 :             return f.failf(shiftAmountNode, "shift amount must be constant");
    4095             : 
    4096           0 :         unsigned requiredShift = TypedArrayShift(*viewType);
    4097           0 :         if (shift != requiredShift)
    4098           0 :             return f.failf(shiftAmountNode, "shift amount must be %u", requiredShift);
    4099             : 
    4100           0 :         ParseNode* pointerNode = BitwiseLeft(indexExpr);
    4101             : 
    4102           0 :         Type pointerType;
    4103           0 :         if (!CheckExpr(f, pointerNode, &pointerType))
    4104           0 :             return false;
    4105             : 
    4106           0 :         if (!pointerType.isIntish())
    4107           0 :             return f.failf(pointerNode, "%s is not a subtype of int", pointerType.toChars());
    4108             :     } else {
    4109             :         // For SIMD access, and legacy scalar access compatibility, accept
    4110             :         // Int8/Uint8 accesses with no shift.
    4111           0 :         if (TypedArrayShift(*viewType) != 0)
    4112           0 :             return f.fail(indexExpr, "index expression isn't shifted; must be an Int8/Uint8 access");
    4113             : 
    4114           0 :         MOZ_ASSERT(mask == NoMask);
    4115             : 
    4116           0 :         ParseNode* pointerNode = indexExpr;
    4117             : 
    4118           0 :         Type pointerType;
    4119           0 :         if (!CheckExpr(f, pointerNode, &pointerType))
    4120           0 :             return false;
    4121             : 
    4122           0 :         if (isSimd) {
    4123           0 :             if (!pointerType.isIntish())
    4124           0 :                 return f.failf(pointerNode, "%s is not a subtype of intish", pointerType.toChars());
    4125             :         } else {
    4126           0 :             if (!pointerType.isInt())
    4127           0 :                 return f.failf(pointerNode, "%s is not a subtype of int", pointerType.toChars());
    4128             :         }
    4129             :     }
    4130             : 
    4131             :     // Don't generate the mask op if there is no need for it which could happen for
    4132             :     // a shift of zero or a SIMD access.
    4133           0 :     if (mask != NoMask) {
    4134           0 :         return f.writeInt32Lit(mask) &&
    4135           0 :                f.encoder().writeOp(Op::I32And);
    4136             :     }
    4137             : 
    4138           0 :     return true;
    4139             : }
    4140             : 
    4141             : static bool
    4142           0 : CheckAndPrepareArrayAccess(FunctionValidator& f, ParseNode* viewName, ParseNode* indexExpr,
    4143             :                            bool isSimd, Scalar::Type* viewType)
    4144             : {
    4145           0 :     return CheckArrayAccess(f, viewName, indexExpr, isSimd, viewType);
    4146             : }
    4147             : 
    4148             : static bool
    4149           0 : WriteArrayAccessFlags(FunctionValidator& f, Scalar::Type viewType)
    4150             : {
    4151             :     // asm.js only has naturally-aligned accesses.
    4152           0 :     size_t align = TypedArrayElemSize(viewType);
    4153           0 :     MOZ_ASSERT(IsPowerOfTwo(align));
    4154           0 :     if (!f.encoder().writeFixedU8(CeilingLog2(align)))
    4155           0 :         return false;
    4156             : 
    4157             :     // asm.js doesn't have constant offsets, so just encode a 0.
    4158           0 :     if (!f.encoder().writeVarU32(0))
    4159           0 :         return false;
    4160             : 
    4161           0 :     return true;
    4162             : }
    4163             : 
    4164             : static bool
    4165           0 : CheckLoadArray(FunctionValidator& f, ParseNode* elem, Type* type)
    4166             : {
    4167             :     Scalar::Type viewType;
    4168             : 
    4169           0 :     if (!CheckAndPrepareArrayAccess(f, ElemBase(elem), ElemIndex(elem), NoSimd, &viewType))
    4170           0 :         return false;
    4171             : 
    4172           0 :     switch (viewType) {
    4173           0 :       case Scalar::Int8:    if (!f.encoder().writeOp(Op::I32Load8S))  return false; break;
    4174           0 :       case Scalar::Uint8:   if (!f.encoder().writeOp(Op::I32Load8U))  return false; break;
    4175           0 :       case Scalar::Int16:   if (!f.encoder().writeOp(Op::I32Load16S)) return false; break;
    4176           0 :       case Scalar::Uint16:  if (!f.encoder().writeOp(Op::I32Load16U)) return false; break;
    4177             :       case Scalar::Uint32:
    4178           0 :       case Scalar::Int32:   if (!f.encoder().writeOp(Op::I32Load))    return false; break;
    4179           0 :       case Scalar::Float32: if (!f.encoder().writeOp(Op::F32Load))    return false; break;
    4180           0 :       case Scalar::Float64: if (!f.encoder().writeOp(Op::F64Load))    return false; break;
    4181           0 :       default: MOZ_CRASH("unexpected scalar type");
    4182             :     }
    4183             : 
    4184           0 :     switch (viewType) {
    4185             :       case Scalar::Int8:
    4186             :       case Scalar::Int16:
    4187             :       case Scalar::Int32:
    4188             :       case Scalar::Uint8:
    4189             :       case Scalar::Uint16:
    4190             :       case Scalar::Uint32:
    4191           0 :         *type = Type::Intish;
    4192           0 :         break;
    4193             :       case Scalar::Float32:
    4194           0 :         *type = Type::MaybeFloat;
    4195           0 :         break;
    4196             :       case Scalar::Float64:
    4197           0 :         *type = Type::MaybeDouble;
    4198           0 :         break;
    4199           0 :       default: MOZ_CRASH("Unexpected array type");
    4200             :     }
    4201             : 
    4202           0 :     if (!WriteArrayAccessFlags(f, viewType))
    4203           0 :         return false;
    4204             : 
    4205           0 :     return true;
    4206             : }
    4207             : 
    4208             : static bool
    4209           0 : CheckStoreArray(FunctionValidator& f, ParseNode* lhs, ParseNode* rhs, Type* type)
    4210             : {
    4211             :     Scalar::Type viewType;
    4212           0 :     if (!CheckAndPrepareArrayAccess(f, ElemBase(lhs), ElemIndex(lhs), NoSimd, &viewType))
    4213           0 :         return false;
    4214             : 
    4215           0 :     Type rhsType;
    4216           0 :     if (!CheckExpr(f, rhs, &rhsType))
    4217           0 :         return false;
    4218             : 
    4219           0 :     switch (viewType) {
    4220             :       case Scalar::Int8:
    4221             :       case Scalar::Int16:
    4222             :       case Scalar::Int32:
    4223             :       case Scalar::Uint8:
    4224             :       case Scalar::Uint16:
    4225             :       case Scalar::Uint32:
    4226           0 :         if (!rhsType.isIntish())
    4227           0 :             return f.failf(lhs, "%s is not a subtype of intish", rhsType.toChars());
    4228           0 :         break;
    4229             :       case Scalar::Float32:
    4230           0 :         if (!rhsType.isMaybeDouble() && !rhsType.isFloatish())
    4231           0 :             return f.failf(lhs, "%s is not a subtype of double? or floatish", rhsType.toChars());
    4232           0 :         break;
    4233             :       case Scalar::Float64:
    4234           0 :         if (!rhsType.isMaybeFloat() && !rhsType.isMaybeDouble())
    4235           0 :             return f.failf(lhs, "%s is not a subtype of float? or double?", rhsType.toChars());
    4236           0 :         break;
    4237             :       default:
    4238           0 :         MOZ_CRASH("Unexpected view type");
    4239             :     }
    4240             : 
    4241           0 :     switch (viewType) {
    4242             :       case Scalar::Int8:
    4243             :       case Scalar::Uint8:
    4244           0 :         if (!f.encoder().writeOp(MozOp::I32TeeStore8))
    4245           0 :             return false;
    4246           0 :         break;
    4247             :       case Scalar::Int16:
    4248             :       case Scalar::Uint16:
    4249           0 :         if (!f.encoder().writeOp(MozOp::I32TeeStore16))
    4250           0 :             return false;
    4251           0 :         break;
    4252             :       case Scalar::Int32:
    4253             :       case Scalar::Uint32:
    4254           0 :         if (!f.encoder().writeOp(MozOp::I32TeeStore))
    4255           0 :             return false;
    4256           0 :         break;
    4257             :       case Scalar::Float32:
    4258           0 :         if (rhsType.isFloatish()) {
    4259           0 :             if (!f.encoder().writeOp(MozOp::F32TeeStore))
    4260           0 :                 return false;
    4261             :         } else {
    4262           0 :             if (!f.encoder().writeOp(MozOp::F64TeeStoreF32))
    4263           0 :                 return false;
    4264             :         }
    4265           0 :         break;
    4266             :       case Scalar::Float64:
    4267           0 :         if (rhsType.isFloatish()) {
    4268           0 :             if (!f.encoder().writeOp(MozOp::F32TeeStoreF64))
    4269           0 :                 return false;
    4270             :         } else {
    4271           0 :             if (!f.encoder().writeOp(MozOp::F64TeeStore))
    4272           0 :                 return false;
    4273             :         }
    4274           0 :         break;
    4275           0 :       default: MOZ_CRASH("unexpected scalar type");
    4276             :     }
    4277             : 
    4278           0 :     if (!WriteArrayAccessFlags(f, viewType))
    4279           0 :         return false;
    4280             : 
    4281           0 :     *type = rhsType;
    4282           0 :     return true;
    4283             : }
    4284             : 
    4285             : static bool
    4286           0 : CheckAssignName(FunctionValidator& f, ParseNode* lhs, ParseNode* rhs, Type* type)
    4287             : {
    4288           0 :     RootedPropertyName name(f.cx(), lhs->name());
    4289             : 
    4290           0 :     if (const FunctionValidator::Local* lhsVar = f.lookupLocal(name)) {
    4291           0 :         Type rhsType;
    4292           0 :         if (!CheckExpr(f, rhs, &rhsType))
    4293           0 :             return false;
    4294             : 
    4295           0 :         if (!f.encoder().writeOp(Op::TeeLocal))
    4296           0 :             return false;
    4297           0 :         if (!f.encoder().writeVarU32(lhsVar->slot))
    4298           0 :             return false;
    4299             : 
    4300           0 :         if (!(rhsType <= lhsVar->type)) {
    4301           0 :             return f.failf(lhs, "%s is not a subtype of %s",
    4302           0 :                            rhsType.toChars(), lhsVar->type.toChars());
    4303             :         }
    4304           0 :         *type = rhsType;
    4305           0 :         return true;
    4306             :     }
    4307             : 
    4308           0 :     if (const ModuleValidator::Global* global = f.lookupGlobal(name)) {
    4309           0 :         if (global->which() != ModuleValidator::Global::Variable)
    4310           0 :             return f.failName(lhs, "'%s' is not a mutable variable", name);
    4311             : 
    4312           0 :         Type rhsType;
    4313           0 :         if (!CheckExpr(f, rhs, &rhsType))
    4314           0 :             return false;
    4315             : 
    4316           0 :         Type globType = global->varOrConstType();
    4317           0 :         if (!(rhsType <= globType))
    4318           0 :             return f.failf(lhs, "%s is not a subtype of %s", rhsType.toChars(), globType.toChars());
    4319           0 :         if (!f.encoder().writeOp(MozOp::TeeGlobal))
    4320           0 :             return false;
    4321           0 :         if (!f.encoder().writeVarU32(global->varOrConstIndex()))
    4322           0 :             return false;
    4323             : 
    4324           0 :         *type = rhsType;
    4325           0 :         return true;
    4326             :     }
    4327             : 
    4328           0 :     return f.failName(lhs, "'%s' not found in local or asm.js module scope", name);
    4329             : }
    4330             : 
    4331             : static bool
    4332           0 : CheckAssign(FunctionValidator& f, ParseNode* assign, Type* type)
    4333             : {
    4334           0 :     MOZ_ASSERT(assign->isKind(PNK_ASSIGN));
    4335             : 
    4336           0 :     ParseNode* lhs = BinaryLeft(assign);
    4337           0 :     ParseNode* rhs = BinaryRight(assign);
    4338             : 
    4339           0 :     if (lhs->getKind() == PNK_ELEM)
    4340           0 :         return CheckStoreArray(f, lhs, rhs, type);
    4341             : 
    4342           0 :     if (lhs->getKind() == PNK_NAME)
    4343           0 :         return CheckAssignName(f, lhs, rhs, type);
    4344             : 
    4345           0 :     return f.fail(assign, "left-hand side of assignment must be a variable or array access");
    4346             : }
    4347             : 
    4348             : static bool
    4349           0 : CheckMathIMul(FunctionValidator& f, ParseNode* call, Type* type)
    4350             : {
    4351           0 :     if (CallArgListLength(call) != 2)
    4352           0 :         return f.fail(call, "Math.imul must be passed 2 arguments");
    4353             : 
    4354           0 :     ParseNode* lhs = CallArgList(call);
    4355           0 :     ParseNode* rhs = NextNode(lhs);
    4356             : 
    4357           0 :     Type lhsType;
    4358           0 :     if (!CheckExpr(f, lhs, &lhsType))
    4359           0 :         return false;
    4360             : 
    4361           0 :     Type rhsType;
    4362           0 :     if (!CheckExpr(f, rhs, &rhsType))
    4363           0 :         return false;
    4364             : 
    4365           0 :     if (!lhsType.isIntish())
    4366           0 :         return f.failf(lhs, "%s is not a subtype of intish", lhsType.toChars());
    4367           0 :     if (!rhsType.isIntish())
    4368           0 :         return f.failf(rhs, "%s is not a subtype of intish", rhsType.toChars());
    4369             : 
    4370           0 :     *type = Type::Signed;
    4371           0 :     return f.encoder().writeOp(Op::I32Mul);
    4372             : }
    4373             : 
    4374             : static bool
    4375           0 : CheckMathClz32(FunctionValidator& f, ParseNode* call, Type* type)
    4376             : {
    4377           0 :     if (CallArgListLength(call) != 1)
    4378           0 :         return f.fail(call, "Math.clz32 must be passed 1 argument");
    4379             : 
    4380           0 :     ParseNode* arg = CallArgList(call);
    4381             : 
    4382           0 :     Type argType;
    4383           0 :     if (!CheckExpr(f, arg, &argType))
    4384           0 :         return false;
    4385             : 
    4386           0 :     if (!argType.isIntish())
    4387           0 :         return f.failf(arg, "%s is not a subtype of intish", argType.toChars());
    4388             : 
    4389           0 :     *type = Type::Fixnum;
    4390           0 :     return f.encoder().writeOp(Op::I32Clz);
    4391             : }
    4392             : 
    4393             : static bool
    4394           0 : CheckMathAbs(FunctionValidator& f, ParseNode* call, Type* type)
    4395             : {
    4396           0 :     if (CallArgListLength(call) != 1)
    4397           0 :         return f.fail(call, "Math.abs must be passed 1 argument");
    4398             : 
    4399           0 :     ParseNode* arg = CallArgList(call);
    4400             : 
    4401           0 :     Type argType;
    4402           0 :     if (!CheckExpr(f, arg, &argType))
    4403           0 :         return false;
    4404             : 
    4405           0 :     if (argType.isSigned()) {
    4406           0 :         *type = Type::Unsigned;
    4407           0 :         return f.encoder().writeOp(MozOp::I32Abs);
    4408             :     }
    4409             : 
    4410           0 :     if (argType.isMaybeDouble()) {
    4411           0 :         *type = Type::Double;
    4412           0 :         return f.encoder().writeOp(Op::F64Abs);
    4413             :     }
    4414             : 
    4415           0 :     if (argType.isMaybeFloat()) {
    4416           0 :         *type = Type::Floatish;
    4417           0 :         return f.encoder().writeOp(Op::F32Abs);
    4418             :     }
    4419             : 
    4420           0 :     return f.failf(call, "%s is not a subtype of signed, float? or double?", argType.toChars());
    4421             : }
    4422             : 
    4423             : static bool
    4424           0 : CheckMathSqrt(FunctionValidator& f, ParseNode* call, Type* type)
    4425             : {
    4426           0 :     if (CallArgListLength(call) != 1)
    4427           0 :         return f.fail(call, "Math.sqrt must be passed 1 argument");
    4428             : 
    4429           0 :     ParseNode* arg = CallArgList(call);
    4430             : 
    4431           0 :     Type argType;
    4432           0 :     if (!CheckExpr(f, arg, &argType))
    4433           0 :         return false;
    4434             : 
    4435           0 :     if (argType.isMaybeDouble()) {
    4436           0 :         *type = Type::Double;
    4437           0 :         return f.encoder().writeOp(Op::F64Sqrt);
    4438             :     }
    4439             : 
    4440           0 :     if (argType.isMaybeFloat()) {
    4441           0 :         *type = Type::Floatish;
    4442           0 :         return f.encoder().writeOp(Op::F32Sqrt);
    4443             :     }
    4444             : 
    4445           0 :     return f.failf(call, "%s is neither a subtype of double? nor float?", argType.toChars());
    4446             : }
    4447             : 
    4448             : static bool
    4449           0 : CheckMathMinMax(FunctionValidator& f, ParseNode* callNode, bool isMax, Type* type)
    4450             : {
    4451           0 :     if (CallArgListLength(callNode) < 2)
    4452           0 :         return f.fail(callNode, "Math.min/max must be passed at least 2 arguments");
    4453             : 
    4454           0 :     ParseNode* firstArg = CallArgList(callNode);
    4455           0 :     Type firstType;
    4456           0 :     if (!CheckExpr(f, firstArg, &firstType))
    4457           0 :         return false;
    4458             : 
    4459           0 :     Op op = Op::Limit;
    4460           0 :     MozOp mozOp = MozOp::Limit;
    4461           0 :     if (firstType.isMaybeDouble()) {
    4462           0 :         *type = Type::Double;
    4463           0 :         firstType = Type::MaybeDouble;
    4464           0 :         op = isMax ? Op::F64Max : Op::F64Min;
    4465           0 :     } else if (firstType.isMaybeFloat()) {
    4466           0 :         *type = Type::Float;
    4467           0 :         firstType = Type::MaybeFloat;
    4468           0 :         op = isMax ? Op::F32Max : Op::F32Min;
    4469           0 :     } else if (firstType.isSigned()) {
    4470           0 :         *type = Type::Signed;
    4471           0 :         firstType = Type::Signed;
    4472           0 :         mozOp = isMax ? MozOp::I32Max : MozOp::I32Min;
    4473             :     } else {
    4474           0 :         return f.failf(firstArg, "%s is not a subtype of double?, float? or signed",
    4475           0 :                        firstType.toChars());
    4476             :     }
    4477             : 
    4478           0 :     unsigned numArgs = CallArgListLength(callNode);
    4479           0 :     ParseNode* nextArg = NextNode(firstArg);
    4480           0 :     for (unsigned i = 1; i < numArgs; i++, nextArg = NextNode(nextArg)) {
    4481           0 :         Type nextType;
    4482           0 :         if (!CheckExpr(f, nextArg, &nextType))
    4483           0 :             return false;
    4484           0 :         if (!(nextType <= firstType))
    4485           0 :             return f.failf(nextArg, "%s is not a subtype of %s", nextType.toChars(), firstType.toChars());
    4486             : 
    4487           0 :         if (op != Op::Limit) {
    4488           0 :             if (!f.encoder().writeOp(op))
    4489           0 :                 return false;
    4490             :         } else {
    4491           0 :             if (!f.encoder().writeOp(mozOp))
    4492           0 :                 return false;
    4493             :         }
    4494             :     }
    4495             : 
    4496           0 :     return true;
    4497             : }
    4498             : 
    4499             : static bool
    4500           0 : CheckSharedArrayAtomicAccess(FunctionValidator& f, ParseNode* viewName, ParseNode* indexExpr,
    4501             :                              Scalar::Type* viewType)
    4502             : {
    4503           0 :     if (!CheckAndPrepareArrayAccess(f, viewName, indexExpr, NoSimd, viewType))
    4504           0 :         return false;
    4505             : 
    4506             :     // The global will be sane, CheckArrayAccess checks it.
    4507           0 :     const ModuleValidator::Global* global = f.lookupGlobal(viewName->name());
    4508           0 :     if (global->which() != ModuleValidator::Global::ArrayView)
    4509           0 :         return f.fail(viewName, "base of array access must be a typed array view");
    4510             : 
    4511           0 :     MOZ_ASSERT(f.m().atomicsPresent());
    4512             : 
    4513           0 :     switch (*viewType) {
    4514             :       case Scalar::Int8:
    4515             :       case Scalar::Int16:
    4516             :       case Scalar::Int32:
    4517             :       case Scalar::Uint8:
    4518             :       case Scalar::Uint16:
    4519             :       case Scalar::Uint32:
    4520           0 :         return true;
    4521             :       default:
    4522           0 :         return f.failf(viewName, "not an integer array");
    4523             :     }
    4524             : 
    4525             :     return true;
    4526             : }
    4527             : 
    4528             : static bool
    4529           0 : WriteAtomicOperator(FunctionValidator& f, MozOp opcode, Scalar::Type viewType)
    4530             : {
    4531           0 :     return f.encoder().writeOp(opcode) &&
    4532           0 :            f.encoder().writeFixedU8(viewType);
    4533             : }
    4534             : 
    4535             : static bool
    4536           0 : CheckAtomicsLoad(FunctionValidator& f, ParseNode* call, Type* type)
    4537             : {
    4538           0 :     if (CallArgListLength(call) != 2)
    4539           0 :         return f.fail(call, "Atomics.load must be passed 2 arguments");
    4540             : 
    4541           0 :     ParseNode* arrayArg = CallArgList(call);
    4542           0 :     ParseNode* indexArg = NextNode(arrayArg);
    4543             : 
    4544             :     Scalar::Type viewType;
    4545           0 :     if (!CheckSharedArrayAtomicAccess(f, arrayArg, indexArg, &viewType))
    4546           0 :         return false;
    4547             : 
    4548           0 :     if (!WriteAtomicOperator(f, MozOp::I32AtomicsLoad, viewType))
    4549           0 :         return false;
    4550             : 
    4551           0 :     if (!WriteArrayAccessFlags(f, viewType))
    4552           0 :         return false;
    4553             : 
    4554           0 :     *type = Type::Int;
    4555           0 :     return true;
    4556             : }
    4557             : 
    4558             : static bool
    4559           0 : CheckAtomicsStore(FunctionValidator& f, ParseNode* call, Type* type)
    4560             : {
    4561           0 :     if (CallArgListLength(call) != 3)
    4562           0 :         return f.fail(call, "Atomics.store must be passed 3 arguments");
    4563             : 
    4564           0 :     ParseNode* arrayArg = CallArgList(call);
    4565           0 :     ParseNode* indexArg = NextNode(arrayArg);
    4566           0 :     ParseNode* valueArg = NextNode(indexArg);
    4567             : 
    4568           0 :     Type rhsType;
    4569           0 :     if (!CheckExpr(f, valueArg, &rhsType))
    4570           0 :         return false;
    4571             : 
    4572           0 :     if (!rhsType.isIntish())
    4573           0 :         return f.failf(arrayArg, "%s is not a subtype of intish", rhsType.toChars());
    4574             : 
    4575             :     Scalar::Type viewType;
    4576           0 :     if (!CheckSharedArrayAtomicAccess(f, arrayArg, indexArg, &viewType))
    4577           0 :         return false;
    4578             : 
    4579           0 :     if (!WriteAtomicOperator(f, MozOp::I32AtomicsStore, viewType))
    4580           0 :         return false;
    4581             : 
    4582           0 :     if (!WriteArrayAccessFlags(f, viewType))
    4583           0 :         return false;
    4584             : 
    4585           0 :     *type = rhsType;
    4586           0 :     return true;
    4587             : }
    4588             : 
    4589             : static bool
    4590           0 : CheckAtomicsBinop(FunctionValidator& f, ParseNode* call, Type* type, AtomicOp op)
    4591             : {
    4592           0 :     if (CallArgListLength(call) != 3)
    4593           0 :         return f.fail(call, "Atomics binary operator must be passed 3 arguments");
    4594             : 
    4595           0 :     ParseNode* arrayArg = CallArgList(call);
    4596           0 :     ParseNode* indexArg = NextNode(arrayArg);
    4597           0 :     ParseNode* valueArg = NextNode(indexArg);
    4598             : 
    4599           0 :     Type valueArgType;
    4600           0 :     if (!CheckExpr(f, valueArg, &valueArgType))
    4601           0 :         return false;
    4602             : 
    4603           0 :     if (!valueArgType.isIntish())
    4604           0 :         return f.failf(valueArg, "%s is not a subtype of intish", valueArgType.toChars());
    4605             : 
    4606             :     Scalar::Type viewType;
    4607           0 :     if (!CheckSharedArrayAtomicAccess(f, arrayArg, indexArg, &viewType))
    4608           0 :         return false;
    4609             : 
    4610           0 :     if (!WriteAtomicOperator(f, MozOp::I32AtomicsBinOp, viewType))
    4611           0 :         return false;
    4612           0 :     if (!f.encoder().writeFixedU8(uint8_t(op)))
    4613           0 :         return false;
    4614             : 
    4615           0 :     if (!WriteArrayAccessFlags(f, viewType))
    4616           0 :         return false;
    4617             : 
    4618           0 :     *type = Type::Int;
    4619           0 :     return true;
    4620             : }
    4621             : 
    4622             : static bool
    4623           0 : CheckAtomicsIsLockFree(FunctionValidator& f, ParseNode* call, Type* type)
    4624             : {
    4625           0 :     if (CallArgListLength(call) != 1)
    4626           0 :         return f.fail(call, "Atomics.isLockFree must be passed 1 argument");
    4627             : 
    4628           0 :     ParseNode* sizeArg = CallArgList(call);
    4629             : 
    4630             :     uint32_t size;
    4631           0 :     if (!IsLiteralInt(f.m(), sizeArg, &size))
    4632           0 :         return f.fail(sizeArg, "Atomics.isLockFree requires an integer literal argument");
    4633             : 
    4634           0 :     *type = Type::Int;
    4635           0 :     return f.writeInt32Lit(AtomicOperations::isLockfree(size));
    4636             : }
    4637             : 
    4638             : static bool
    4639           0 : CheckAtomicsCompareExchange(FunctionValidator& f, ParseNode* call, Type* type)
    4640             : {
    4641           0 :     if (CallArgListLength(call) != 4)
    4642           0 :         return f.fail(call, "Atomics.compareExchange must be passed 4 arguments");
    4643             : 
    4644           0 :     ParseNode* arrayArg = CallArgList(call);
    4645           0 :     ParseNode* indexArg = NextNode(arrayArg);
    4646           0 :     ParseNode* oldValueArg = NextNode(indexArg);
    4647           0 :     ParseNode* newValueArg = NextNode(oldValueArg);
    4648             : 
    4649           0 :     Type oldValueArgType;
    4650           0 :     if (!CheckExpr(f, oldValueArg, &oldValueArgType))
    4651           0 :         return false;
    4652             : 
    4653           0 :     Type newValueArgType;
    4654           0 :     if (!CheckExpr(f, newValueArg, &newValueArgType))
    4655           0 :         return false;
    4656             : 
    4657           0 :     if (!oldValueArgType.isIntish())
    4658           0 :         return f.failf(oldValueArg, "%s is not a subtype of intish", oldValueArgType.toChars());
    4659             : 
    4660           0 :     if (!newValueArgType.isIntish())
    4661           0 :         return f.failf(newValueArg, "%s is not a subtype of intish", newValueArgType.toChars());
    4662             : 
    4663             :     Scalar::Type viewType;
    4664           0 :     if (!CheckSharedArrayAtomicAccess(f, arrayArg, indexArg, &viewType))
    4665           0 :         return false;
    4666             : 
    4667           0 :     if (!WriteAtomicOperator(f, MozOp::I32AtomicsCompareExchange, viewType))
    4668           0 :         return false;
    4669             : 
    4670           0 :     if (!WriteArrayAccessFlags(f, viewType))
    4671           0 :         return false;
    4672             : 
    4673           0 :     *type = Type::Int;
    4674           0 :     return true;
    4675             : }
    4676             : 
    4677             : static bool
    4678           0 : CheckAtomicsExchange(FunctionValidator& f, ParseNode* call, Type* type)
    4679             : {
    4680           0 :     if (CallArgListLength(call) != 3)
    4681           0 :         return f.fail(call, "Atomics.exchange must be passed 3 arguments");
    4682             : 
    4683           0 :     ParseNode* arrayArg = CallArgList(call);
    4684           0 :     ParseNode* indexArg = NextNode(arrayArg);
    4685           0 :     ParseNode* valueArg = NextNode(indexArg);
    4686             : 
    4687           0 :     Type valueArgType;
    4688           0 :     if (!CheckExpr(f, valueArg, &valueArgType))
    4689           0 :         return false;
    4690             : 
    4691           0 :     if (!valueArgType.isIntish())
    4692           0 :         return f.failf(arrayArg, "%s is not a subtype of intish", valueArgType.toChars());
    4693             : 
    4694             :     Scalar::Type viewType;
    4695           0 :     if (!CheckSharedArrayAtomicAccess(f, arrayArg, indexArg, &viewType))
    4696           0 :         return false;
    4697             : 
    4698           0 :     if (!WriteAtomicOperator(f, MozOp::I32AtomicsExchange, viewType))
    4699           0 :         return false;
    4700             : 
    4701           0 :     if (!WriteArrayAccessFlags(f, viewType))
    4702           0 :         return false;
    4703             : 
    4704           0 :     *type = Type::Int;
    4705           0 :     return true;
    4706             : }
    4707             : 
    4708             : static bool
    4709           0 : CheckAtomicsBuiltinCall(FunctionValidator& f, ParseNode* callNode, AsmJSAtomicsBuiltinFunction func,
    4710             :                         Type* type)
    4711             : {
    4712           0 :     f.setUsesAtomics();
    4713             : 
    4714           0 :     switch (func) {
    4715             :       case AsmJSAtomicsBuiltin_compareExchange:
    4716           0 :         return CheckAtomicsCompareExchange(f, callNode, type);
    4717             :       case AsmJSAtomicsBuiltin_exchange:
    4718           0 :         return CheckAtomicsExchange(f, callNode, type);
    4719             :       case AsmJSAtomicsBuiltin_load:
    4720           0 :         return CheckAtomicsLoad(f, callNode, type);
    4721             :       case AsmJSAtomicsBuiltin_store:
    4722           0 :         return CheckAtomicsStore(f, callNode, type);
    4723             :       case AsmJSAtomicsBuiltin_add:
    4724           0 :         return CheckAtomicsBinop(f, callNode, type, AtomicFetchAddOp);
    4725             :       case AsmJSAtomicsBuiltin_sub:
    4726           0 :         return CheckAtomicsBinop(f, callNode, type, AtomicFetchSubOp);
    4727             :       case AsmJSAtomicsBuiltin_and:
    4728           0 :         return CheckAtomicsBinop(f, callNode, type, AtomicFetchAndOp);
    4729             :       case AsmJSAtomicsBuiltin_or:
    4730           0 :         return CheckAtomicsBinop(f, callNode, type, AtomicFetchOrOp);
    4731             :       case AsmJSAtomicsBuiltin_xor:
    4732           0 :         return CheckAtomicsBinop(f, callNode, type, AtomicFetchXorOp);
    4733             :       case AsmJSAtomicsBuiltin_isLockFree:
    4734           0 :         return CheckAtomicsIsLockFree(f, callNode, type);
    4735             :       default:
    4736           0 :         MOZ_CRASH("unexpected atomicsBuiltin function");
    4737             :     }
    4738             : }
    4739             : 
    4740             : typedef bool (*CheckArgType)(FunctionValidator& f, ParseNode* argNode, Type type);
    4741             : 
    4742             : template <CheckArgType checkArg>
    4743             : static bool
    4744           0 : CheckCallArgs(FunctionValidator& f, ParseNode* callNode, ValTypeVector* args)
    4745             : {
    4746           0 :     ParseNode* argNode = CallArgList(callNode);
    4747           0 :     for (unsigned i = 0; i < CallArgListLength(callNode); i++, argNode = NextNode(argNode)) {
    4748           0 :         Type type;
    4749           0 :         if (!CheckExpr(f, argNode, &type))
    4750           0 :             return false;
    4751             : 
    4752           0 :         if (!checkArg(f, argNode, type))
    4753           0 :             return false;
    4754             : 
    4755           0 :         if (!args->append(Type::canonicalize(type).canonicalToValType()))
    4756           0 :             return false;
    4757             :     }
    4758           0 :     return true;
    4759             : }
    4760             : 
    4761             : static bool
    4762           0 : CheckSignatureAgainstExisting(ModuleValidator& m, ParseNode* usepn, const Sig& sig, const Sig& existing)
    4763             : {
    4764           0 :     if (sig.args().length() != existing.args().length()) {
    4765           0 :         return m.failf(usepn, "incompatible number of arguments (%" PRIuSIZE
    4766             :                        " here vs. %" PRIuSIZE " before)",
    4767           0 :                        sig.args().length(), existing.args().length());
    4768             :     }
    4769             : 
    4770           0 :     for (unsigned i = 0; i < sig.args().length(); i++) {
    4771           0 :         if (sig.arg(i) != existing.arg(i)) {
    4772           0 :             return m.failf(usepn, "incompatible type for argument %u: (%s here vs. %s before)", i,
    4773           0 :                            ToCString(sig.arg(i)), ToCString(existing.arg(i)));
    4774             :         }
    4775             :     }
    4776             : 
    4777           0 :     if (sig.ret() != existing.ret()) {
    4778           0 :         return m.failf(usepn, "%s incompatible with previous return of type %s",
    4779           0 :                        ToCString(sig.ret()), ToCString(existing.ret()));
    4780             :     }
    4781             : 
    4782           0 :     MOZ_ASSERT(sig == existing);
    4783           0 :     return true;
    4784             : }
    4785             : 
    4786             : static bool
    4787           0 : CheckFunctionSignature(ModuleValidator& m, ParseNode* usepn, Sig&& sig, PropertyName* name,
    4788             :                        ModuleValidator::Func** func)
    4789             : {
    4790           0 :     ModuleValidator::Func* existing = m.lookupFunction(name);
    4791           0 :     if (!existing) {
    4792           0 :         if (!CheckModuleLevelName(m, usepn, name))
    4793           0 :             return false;
    4794           0 :         return m.addFunction(name, usepn->pn_pos.begin, Move(sig), func);
    4795             :     }
    4796             : 
    4797           0 :     if (!CheckSignatureAgainstExisting(m, usepn, sig, m.mg().funcSig(existing->index())))
    4798           0 :         return false;
    4799             : 
    4800           0 :     *func = existing;
    4801           0 :     return true;
    4802             : }
    4803             : 
    4804             : static bool
    4805           0 : CheckIsArgType(FunctionValidator& f, ParseNode* argNode, Type type)
    4806             : {
    4807           0 :     if (!type.isArgType())
    4808           0 :         return f.failf(argNode,
    4809             :                        "%s is not a subtype of int, float, double, or an allowed SIMD type",
    4810           0 :                        type.toChars());
    4811             : 
    4812           0 :     return true;
    4813             : }
    4814             : 
    4815             : static bool
    4816           0 : CheckInternalCall(FunctionValidator& f, ParseNode* callNode, PropertyName* calleeName,
    4817             :                   Type ret, Type* type)
    4818             : {
    4819           0 :     MOZ_ASSERT(ret.isCanonical());
    4820             : 
    4821           0 :     ValTypeVector args;
    4822           0 :     if (!CheckCallArgs<CheckIsArgType>(f, callNode, &args))
    4823           0 :         return false;
    4824             : 
    4825           0 :     Sig sig(Move(args), ret.canonicalToExprType());
    4826             : 
    4827             :     ModuleValidator::Func* callee;
    4828           0 :     if (!CheckFunctionSignature(f.m(), callNode, Move(sig), calleeName, &callee))
    4829           0 :         return false;
    4830             : 
    4831           0 :     if (!f.writeCall(callNode, Op::Call))
    4832           0 :         return false;
    4833             : 
    4834           0 :     if (!f.encoder().writeVarU32(callee->index()))
    4835           0 :         return false;
    4836             : 
    4837           0 :     *type = Type::ret(ret);
    4838           0 :     return true;
    4839             : }
    4840             : 
    4841             : static bool
    4842           0 : CheckFuncPtrTableAgainstExisting(ModuleValidator& m, ParseNode* usepn, PropertyName* name,
    4843             :                                  Sig&& sig, unsigned mask, uint32_t* funcPtrTableIndex)
    4844             : {
    4845           0 :     if (const ModuleValidator::Global* existing = m.lookupGlobal(name)) {
    4846           0 :         if (existing->which() != ModuleValidator::Global::FuncPtrTable)
    4847           0 :             return m.failName(usepn, "'%s' is not a function-pointer table", name);
    4848             : 
    4849           0 :         ModuleValidator::FuncPtrTable& table = m.funcPtrTable(existing->funcPtrTableIndex());
    4850           0 :         if (mask != table.mask())
    4851           0 :             return m.failf(usepn, "mask does not match previous value (%u)", table.mask());
    4852             : 
    4853           0 :         if (!CheckSignatureAgainstExisting(m, usepn, sig, m.mg().sig(table.sigIndex())))
    4854           0 :             return false;
    4855             : 
    4856           0 :         *funcPtrTableIndex = existing->funcPtrTableIndex();
    4857           0 :         return true;
    4858             :     }
    4859             : 
    4860           0 :     if (!CheckModuleLevelName(m, usepn, name))
    4861           0 :         return false;
    4862             : 
    4863           0 :     if (!m.declareFuncPtrTable(Move(sig), name, usepn->pn_pos.begin, mask, funcPtrTableIndex))
    4864           0 :         return false;
    4865             : 
    4866           0 :     return true;
    4867             : }
    4868             : 
    4869             : static bool
    4870           0 : CheckFuncPtrCall(FunctionValidator& f, ParseNode* callNode, Type ret, Type* type)
    4871             : {
    4872           0 :     MOZ_ASSERT(ret.isCanonical());
    4873             : 
    4874           0 :     ParseNode* callee = CallCallee(callNode);
    4875           0 :     ParseNode* tableNode = ElemBase(callee);
    4876           0 :     ParseNode* indexExpr = ElemIndex(callee);
    4877             : 
    4878           0 :     if (!tableNode->isKind(PNK_NAME))
    4879           0 :         return f.fail(tableNode, "expecting name of function-pointer array");
    4880             : 
    4881           0 :     PropertyName* name = tableNode->name();
    4882           0 :     if (const ModuleValidator::Global* existing = f.lookupGlobal(name)) {
    4883           0 :         if (existing->which() != ModuleValidator::Global::FuncPtrTable)
    4884           0 :             return f.failName(tableNode, "'%s' is not the name of a function-pointer array", name);
    4885             :     }
    4886             : 
    4887           0 :     if (!indexExpr->isKind(PNK_BITAND))
    4888           0 :         return f.fail(indexExpr, "function-pointer table index expression needs & mask");
    4889             : 
    4890           0 :     ParseNode* indexNode = BitwiseLeft(indexExpr);
    4891           0 :     ParseNode* maskNode = BitwiseRight(indexExpr);
    4892             : 
    4893             :     uint32_t mask;
    4894           0 :     if (!IsLiteralInt(f.m(), maskNode, &mask) || mask == UINT32_MAX || !IsPowerOfTwo(mask + 1))
    4895           0 :         return f.fail(maskNode, "function-pointer table index mask value must be a power of two minus 1");
    4896             : 
    4897           0 :     Type indexType;
    4898           0 :     if (!CheckExpr(f, indexNode, &indexType))
    4899           0 :         return false;
    4900             : 
    4901           0 :     if (!indexType.isIntish())
    4902           0 :         return f.failf(indexNode, "%s is not a subtype of intish", indexType.toChars());
    4903             : 
    4904           0 :     ValTypeVector args;
    4905           0 :     if (!CheckCallArgs<CheckIsArgType>(f, callNode, &args))
    4906           0 :         return false;
    4907             : 
    4908           0 :     Sig sig(Move(args), ret.canonicalToExprType());
    4909             : 
    4910             :     uint32_t tableIndex;
    4911           0 :     if (!CheckFuncPtrTableAgainstExisting(f.m(), tableNode, name, Move(sig), mask, &tableIndex))
    4912           0 :         return false;
    4913             : 
    4914           0 :     if (!f.writeCall(callNode, MozOp::OldCallIndirect))
    4915           0 :         return false;
    4916             : 
    4917             :     // Call signature
    4918           0 :     if (!f.encoder().writeVarU32(f.m().funcPtrTable(tableIndex).sigIndex()))
    4919           0 :         return false;
    4920             : 
    4921           0 :     *type = Type::ret(ret);
    4922           0 :     return true;
    4923             : }
    4924             : 
    4925             : static bool
    4926           0 : CheckIsExternType(FunctionValidator& f, ParseNode* argNode, Type type)
    4927             : {
    4928           0 :     if (!type.isExtern())
    4929           0 :         return f.failf(argNode, "%s is not a subtype of extern", type.toChars());
    4930           0 :     return true;
    4931             : }
    4932             : 
    4933             : static bool
    4934           0 : CheckFFICall(FunctionValidator& f, ParseNode* callNode, unsigned ffiIndex, Type ret, Type* type)
    4935             : {
    4936           0 :     MOZ_ASSERT(ret.isCanonical());
    4937             : 
    4938           0 :     PropertyName* calleeName = CallCallee(callNode)->name();
    4939             : 
    4940           0 :     if (ret.isFloat())
    4941           0 :         return f.fail(callNode, "FFI calls can't return float");
    4942           0 :     if (ret.isSimd())
    4943           0 :         return f.fail(callNode, "FFI calls can't return SIMD values");
    4944             : 
    4945           0 :     ValTypeVector args;
    4946           0 :     if (!CheckCallArgs<CheckIsExternType>(f, callNode, &args))
    4947           0 :         return false;
    4948             : 
    4949           0 :     Sig sig(Move(args), ret.canonicalToExprType());
    4950             : 
    4951             :     uint32_t funcIndex;
    4952           0 :     if (!f.m().declareImport(calleeName, Move(sig), ffiIndex, &funcIndex))
    4953           0 :         return false;
    4954             : 
    4955           0 :     if (!f.writeCall(callNode, Op::Call))
    4956           0 :         return false;
    4957             : 
    4958           0 :     if (!f.encoder().writeVarU32(funcIndex))
    4959           0 :         return false;
    4960             : 
    4961           0 :     *type = Type::ret(ret);
    4962           0 :     return true;
    4963             : }
    4964             : 
    4965             : static bool
    4966           0 : CheckFloatCoercionArg(FunctionValidator& f, ParseNode* inputNode, Type inputType)
    4967             : {
    4968           0 :     if (inputType.isMaybeDouble())
    4969           0 :         return f.encoder().writeOp(Op::F32DemoteF64);
    4970           0 :     if (inputType.isSigned())
    4971           0 :         return f.encoder().writeOp(Op::F32ConvertSI32);
    4972           0 :     if (inputType.isUnsigned())
    4973           0 :         return f.encoder().writeOp(Op::F32ConvertUI32);
    4974           0 :     if (inputType.isFloatish())
    4975           0 :         return true;
    4976             : 
    4977           0 :     return f.failf(inputNode, "%s is not a subtype of signed, unsigned, double? or floatish",
    4978           0 :                    inputType.toChars());
    4979             : }
    4980             : 
    4981             : static bool
    4982             : CheckCoercedCall(FunctionValidator& f, ParseNode* call, Type ret, Type* type);
    4983             : 
    4984             : static bool
    4985           0 : CheckCoercionArg(FunctionValidator& f, ParseNode* arg, Type expected, Type* type)
    4986             : {
    4987           0 :     MOZ_ASSERT(expected.isCanonicalValType());
    4988             : 
    4989           0 :     if (arg->isKind(PNK_CALL))
    4990           0 :         return CheckCoercedCall(f, arg, expected, type);
    4991             : 
    4992           0 :     Type argType;
    4993           0 :     if (!CheckExpr(f, arg, &argType))
    4994           0 :         return false;
    4995             : 
    4996           0 :     if (expected.isFloat()) {
    4997           0 :         if (!CheckFloatCoercionArg(f, arg, argType))
    4998           0 :             return false;
    4999           0 :     } else if (expected.isSimd()) {
    5000           0 :         if (!(argType <= expected))
    5001           0 :             return f.fail(arg, "argument to SIMD coercion isn't from the correct SIMD type");
    5002             :     } else {
    5003           0 :         MOZ_CRASH("not call coercions");
    5004             :     }
    5005             : 
    5006           0 :     *type = Type::ret(expected);
    5007           0 :     return true;
    5008             : }
    5009             : 
    5010             : static bool
    5011           0 : CheckMathFRound(FunctionValidator& f, ParseNode* callNode, Type* type)
    5012             : {
    5013           0 :     if (CallArgListLength(callNode) != 1)
    5014           0 :         return f.fail(callNode, "Math.fround must be passed 1 argument");
    5015             : 
    5016           0 :     ParseNode* argNode = CallArgList(callNode);
    5017           0 :     Type argType;
    5018           0 :     if (!CheckCoercionArg(f, argNode, Type::Float, &argType))
    5019           0 :         return false;
    5020             : 
    5021           0 :     MOZ_ASSERT(argType == Type::Float);
    5022           0 :     *type = Type::Float;
    5023           0 :     return true;
    5024             : }
    5025             : 
    5026             : static bool
    5027           0 : CheckMathBuiltinCall(FunctionValidator& f, ParseNode* callNode, AsmJSMathBuiltinFunction func,
    5028             :                      Type* type)
    5029             : {
    5030           0 :     unsigned arity = 0;
    5031           0 :     Op f32 = Op::Limit;
    5032           0 :     Op f64 = Op::Limit;
    5033           0 :     MozOp mozf64 = MozOp::Limit;
    5034           0 :     switch (func) {
    5035           0 :       case AsmJSMathBuiltin_imul:   return CheckMathIMul(f, callNode, type);
    5036           0 :       case AsmJSMathBuiltin_clz32:  return CheckMathClz32(f, callNode, type);
    5037           0 :       case AsmJSMathBuiltin_abs:    return CheckMathAbs(f, callNode, type);
    5038           0 :       case AsmJSMathBuiltin_sqrt:   return CheckMathSqrt(f, callNode, type);
    5039           0 :       case AsmJSMathBuiltin_fround: return CheckMathFRound(f, callNode, type);
    5040           0 :       case AsmJSMathBuiltin_min:    return CheckMathMinMax(f, callNode, /* isMax = */ false, type);
    5041           0 :       case AsmJSMathBuiltin_max:    return CheckMathMinMax(f, callNode, /* isMax = */ true, type);
    5042           0 :       case AsmJSMathBuiltin_ceil:   arity = 1; f64 = Op::F64Ceil;        f32 = Op::F32Ceil;     break;
    5043           0 :       case AsmJSMathBuiltin_floor:  arity = 1; f64 = Op::F64Floor;       f32 = Op::F32Floor;    break;
    5044           0 :       case AsmJSMathBuiltin_sin:    arity = 1; mozf64 = MozOp::F64Sin;   f32 = Op::Unreachable; break;
    5045           0 :       case AsmJSMathBuiltin_cos:    arity = 1; mozf64 = MozOp::F64Cos;   f32 = Op::Unreachable; break;
    5046           0 :       case AsmJSMathBuiltin_tan:    arity = 1; mozf64 = MozOp::F64Tan;   f32 = Op::Unreachable; break;
    5047           0 :       case AsmJSMathBuiltin_asin:   arity = 1; mozf64 = MozOp::F64Asin;  f32 = Op::Unreachable; break;
    5048           0 :       case AsmJSMathBuiltin_acos:   arity = 1; mozf64 = MozOp::F64Acos;  f32 = Op::Unreachable; break;
    5049           0 :       case AsmJSMathBuiltin_atan:   arity = 1; mozf64 = MozOp::F64Atan;  f32 = Op::Unreachable; break;
    5050           0 :       case AsmJSMathBuiltin_exp:    arity = 1; mozf64 = MozOp::F64Exp;   f32 = Op::Unreachable; break;
    5051           0 :       case AsmJSMathBuiltin_log:    arity = 1; mozf64 = MozOp::F64Log;   f32 = Op::Unreachable; break;
    5052           0 :       case AsmJSMathBuiltin_pow:    arity = 2; mozf64 = MozOp::F64Pow;   f32 = Op::Unreachable; break;
    5053           0 :       case AsmJSMathBuiltin_atan2:  arity = 2; mozf64 = MozOp::F64Atan2; f32 = Op::Unreachable; break;
    5054           0 :       default: MOZ_CRASH("unexpected mathBuiltin function");
    5055             :     }
    5056             : 
    5057           0 :     unsigned actualArity = CallArgListLength(callNode);
    5058           0 :     if (actualArity != arity)
    5059           0 :         return f.failf(callNode, "call passed %u arguments, expected %u", actualArity, arity);
    5060             : 
    5061           0 :     if (!f.prepareCall(callNode))
    5062           0 :         return false;
    5063             : 
    5064           0 :     Type firstType;
    5065           0 :     ParseNode* argNode = CallArgList(callNode);
    5066           0 :     if (!CheckExpr(f, argNode, &firstType))
    5067           0 :         return false;
    5068             : 
    5069           0 :     if (!firstType.isMaybeFloat() && !firstType.isMaybeDouble())
    5070           0 :         return f.fail(argNode, "arguments to math call should be a subtype of double? or float?");
    5071             : 
    5072           0 :     bool opIsDouble = firstType.isMaybeDouble();
    5073           0 :     if (!opIsDouble && f32 == Op::Unreachable)
    5074           0 :         return f.fail(callNode, "math builtin cannot be used as float");
    5075             : 
    5076           0 :     if (arity == 2) {
    5077           0 :         Type secondType;
    5078           0 :         argNode = NextNode(argNode);
    5079           0 :         if (!CheckExpr(f, argNode, &secondType))
    5080           0 :             return false;
    5081             : 
    5082           0 :         if (firstType.isMaybeDouble() && !secondType.isMaybeDouble())
    5083           0 :             return f.fail(argNode, "both arguments to math builtin call should be the same type");
    5084           0 :         if (firstType.isMaybeFloat() && !secondType.isMaybeFloat())
    5085           0 :             return f.fail(argNode, "both arguments to math builtin call should be the same type");
    5086             :     }
    5087             : 
    5088           0 :     if (opIsDouble) {
    5089           0 :         if (f64 != Op::Limit) {
    5090           0 :             if (!f.encoder().writeOp(f64))
    5091           0 :                 return false;
    5092             :         } else {
    5093           0 :             if (!f.encoder().writeOp(mozf64))
    5094           0 :                 return false;
    5095             :         }
    5096             :     } else {
    5097           0 :         if (!f.encoder().writeOp(f32))
    5098           0 :             return false;
    5099             :     }
    5100             : 
    5101           0 :     *type = opIsDouble ? Type::Double : Type::Floatish;
    5102           0 :     return true;
    5103             : }
    5104             : 
    5105             : namespace {
    5106             : // Include CheckSimdCallArgs in unnamed namespace to avoid MSVC name lookup bug.
    5107             : 
    5108             : template<class CheckArgOp>
    5109             : static bool
    5110           0 : CheckSimdCallArgs(FunctionValidator& f, ParseNode* call, unsigned expectedArity,
    5111             :                   const CheckArgOp& checkArg)
    5112             : {
    5113           0 :     unsigned numArgs = CallArgListLength(call);
    5114           0 :     if (numArgs != expectedArity)
    5115           0 :         return f.failf(call, "expected %u arguments to SIMD call, got %u", expectedArity, numArgs);
    5116             : 
    5117           0 :     ParseNode* arg = CallArgList(call);
    5118           0 :     for (size_t i = 0; i < numArgs; i++, arg = NextNode(arg)) {
    5119           0 :         MOZ_ASSERT(!!arg);
    5120           0 :         Type argType;
    5121           0 :         if (!CheckExpr(f, arg, &argType))
    5122           0 :             return false;
    5123           0 :         if (!checkArg(f, arg, i, argType))
    5124           0 :             return false;
    5125             :     }
    5126             : 
    5127           0 :     return true;
    5128             : }
    5129             : 
    5130             : 
    5131             : class CheckArgIsSubtypeOf
    5132             : {
    5133             :     Type formalType_;
    5134             : 
    5135             :   public:
    5136           0 :     explicit CheckArgIsSubtypeOf(SimdType t) : formalType_(t) {}
    5137             : 
    5138           0 :     bool operator()(FunctionValidator& f, ParseNode* arg, unsigned argIndex, Type actualType) const
    5139             :     {
    5140           0 :         if (!(actualType <= formalType_)) {
    5141           0 :             return f.failf(arg, "%s is not a subtype of %s", actualType.toChars(),
    5142           0 :                            formalType_.toChars());
    5143             :         }
    5144           0 :         return true;
    5145             :     }
    5146             : };
    5147             : 
    5148             : static inline Type
    5149           0 : SimdToCoercedScalarType(SimdType t)
    5150             : {
    5151           0 :     switch (t) {
    5152             :       case SimdType::Int8x16:
    5153             :       case SimdType::Int16x8:
    5154             :       case SimdType::Int32x4:
    5155             :       case SimdType::Uint8x16:
    5156             :       case SimdType::Uint16x8:
    5157             :       case SimdType::Uint32x4:
    5158             :       case SimdType::Bool8x16:
    5159             :       case SimdType::Bool16x8:
    5160             :       case SimdType::Bool32x4:
    5161           0 :         return Type::Intish;
    5162             :       case SimdType::Float32x4:
    5163           0 :         return Type::Floatish;
    5164             :       default:
    5165           0 :         break;
    5166             :     }
    5167           0 :     MOZ_MAKE_COMPILER_ASSUME_IS_UNREACHABLE("unexpected SIMD type");
    5168             : }
    5169             : 
    5170             : class CheckSimdScalarArgs
    5171             : {
    5172             :     SimdType simdType_;
    5173             :     Type formalType_;
    5174             : 
    5175             :   public:
    5176           0 :     explicit CheckSimdScalarArgs(SimdType simdType)
    5177           0 :       : simdType_(simdType), formalType_(SimdToCoercedScalarType(simdType))
    5178           0 :     {}
    5179             : 
    5180           0 :     bool operator()(FunctionValidator& f, ParseNode* arg, unsigned argIndex, Type actualType) const
    5181             :     {
    5182           0 :         if (!(actualType <= formalType_)) {
    5183             :             // As a special case, accept doublelit arguments to float32x4 ops by
    5184             :             // re-emitting them as float32 constants.
    5185           0 :             if (simdType_ != SimdType::Float32x4 || !actualType.isDoubleLit()) {
    5186           0 :                 return f.failf(arg, "%s is not a subtype of %s%s",
    5187             :                                actualType.toChars(), formalType_.toChars(),
    5188           0 :                                simdType_ == SimdType::Float32x4 ? " or doublelit" : "");
    5189             :             }
    5190             : 
    5191             :             // We emitted a double literal and actually want a float32.
    5192           0 :             return f.encoder().writeOp(Op::F32DemoteF64);
    5193             :         }
    5194             : 
    5195           0 :         return true;
    5196             :     }
    5197             : };
    5198             : 
    5199             : class CheckSimdSelectArgs
    5200             : {
    5201             :     Type formalType_;
    5202             :     Type maskType_;
    5203             : 
    5204             :   public:
    5205           0 :     explicit CheckSimdSelectArgs(SimdType t) : formalType_(t), maskType_(GetBooleanSimdType(t)) {}
    5206             : 
    5207           0 :     bool operator()(FunctionValidator& f, ParseNode* arg, unsigned argIndex, Type actualType) const
    5208             :     {
    5209             :         // The first argument is the boolean selector, the next two are the
    5210             :         // values to choose from.
    5211           0 :         Type wantedType = argIndex == 0 ? maskType_ : formalType_;
    5212             : 
    5213           0 :         if (!(actualType <= wantedType)) {
    5214           0 :             return f.failf(arg, "%s is not a subtype of %s", actualType.toChars(),
    5215           0 :                            wantedType.toChars());
    5216             :         }
    5217           0 :         return true;
    5218             :     }
    5219             : };
    5220             : 
    5221             : class CheckSimdVectorScalarArgs
    5222             : {
    5223             :     SimdType formalSimdType_;
    5224             : 
    5225             :   public:
    5226           0 :     explicit CheckSimdVectorScalarArgs(SimdType t) : formalSimdType_(t) {}
    5227             : 
    5228           0 :     bool operator()(FunctionValidator& f, ParseNode* arg, unsigned argIndex, Type actualType) const
    5229             :     {
    5230           0 :         MOZ_ASSERT(argIndex < 2);
    5231           0 :         if (argIndex == 0) {
    5232             :             // First argument is the vector
    5233           0 :             if (!(actualType <= Type(formalSimdType_))) {
    5234           0 :                 return f.failf(arg, "%s is not a subtype of %s", actualType.toChars(),
    5235           0 :                                Type(formalSimdType_).toChars());
    5236             :             }
    5237             : 
    5238           0 :             return true;
    5239             :         }
    5240             : 
    5241             :         // Second argument is the scalar
    5242           0 :         return CheckSimdScalarArgs(formalSimdType_)(f, arg, argIndex, actualType);
    5243             :     }
    5244             : };
    5245             : 
    5246             : } // namespace
    5247             : 
    5248             : static bool
    5249           0 : CheckSimdUnary(FunctionValidator& f, ParseNode* call, SimdType opType, SimdOperation op,
    5250             :                Type* type)
    5251             : {
    5252           0 :     if (!CheckSimdCallArgs(f, call, 1, CheckArgIsSubtypeOf(opType)))
    5253           0 :         return false;
    5254           0 :     if (!f.writeSimdOp(opType, op))
    5255           0 :         return false;
    5256           0 :     *type = opType;
    5257           0 :     return true;
    5258             : }
    5259             : 
    5260             : static bool
    5261           0 : CheckSimdBinaryShift(FunctionValidator& f, ParseNode* call, SimdType opType, SimdOperation op,
    5262             :                      Type *type)
    5263             : {
    5264           0 :     if (!CheckSimdCallArgs(f, call, 2, CheckSimdVectorScalarArgs(opType)))
    5265           0 :         return false;
    5266           0 :     if (!f.writeSimdOp(opType, op))
    5267           0 :         return false;
    5268           0 :     *type = opType;
    5269           0 :     return true;
    5270             : }
    5271             : 
    5272             : static bool
    5273           0 : CheckSimdBinaryComp(FunctionValidator& f, ParseNode* call, SimdType opType, SimdOperation op,
    5274             :                     Type *type)
    5275             : {
    5276           0 :     if (!CheckSimdCallArgs(f, call, 2, CheckArgIsSubtypeOf(opType)))
    5277           0 :         return false;
    5278           0 :     if (!f.writeSimdOp(opType, op))
    5279           0 :         return false;
    5280           0 :     *type = GetBooleanSimdType(opType);
    5281           0 :     return true;
    5282             : }
    5283             : 
    5284             : static bool
    5285           0 : CheckSimdBinary(FunctionValidator& f, ParseNode* call, SimdType opType, SimdOperation op,
    5286             :                 Type* type)
    5287             : {
    5288           0 :     if (!CheckSimdCallArgs(f, call, 2, CheckArgIsSubtypeOf(opType)))
    5289           0 :         return false;
    5290           0 :     if (!f.writeSimdOp(opType, op))
    5291           0 :         return false;
    5292           0 :     *type = opType;
    5293           0 :     return true;
    5294             : }
    5295             : 
    5296             : static bool
    5297           0 : CheckSimdExtractLane(FunctionValidator& f, ParseNode* call, SimdType opType, Type* type)
    5298             : {
    5299           0 :     switch (opType) {
    5300             :       case SimdType::Int8x16:
    5301             :       case SimdType::Int16x8:
    5302           0 :       case SimdType::Int32x4:   *type = Type::Signed; break;
    5303             :       case SimdType::Uint8x16:
    5304             :       case SimdType::Uint16x8:
    5305           0 :       case SimdType::Uint32x4:  *type = Type::Unsigned; break;
    5306           0 :       case SimdType::Float32x4: *type = Type::Float; break;
    5307             :       case SimdType::Bool8x16:
    5308             :       case SimdType::Bool16x8:
    5309           0 :       case SimdType::Bool32x4:  *type = Type::Int; break;
    5310           0 :       default:                  MOZ_CRASH("unhandled simd type");
    5311             :     }
    5312             : 
    5313           0 :     unsigned numArgs = CallArgListLength(call);
    5314           0 :     if (numArgs != 2)
    5315           0 :         return f.failf(call, "expected 2 arguments to SIMD extract, got %u", numArgs);
    5316             : 
    5317           0 :     ParseNode* arg = CallArgList(call);
    5318             : 
    5319             :     // First argument is the vector
    5320           0 :     Type vecType;
    5321           0 :     if (!CheckExpr(f, arg, &vecType))
    5322           0 :         return false;
    5323           0 :     if (!(vecType <= Type(opType))) {
    5324           0 :         return f.failf(arg, "%s is not a subtype of %s", vecType.toChars(),
    5325           0 :                        Type(opType).toChars());
    5326             :     }
    5327             : 
    5328           0 :     arg = NextNode(arg);
    5329             : 
    5330             :     // Second argument is the lane < vector length
    5331             :     uint32_t lane;
    5332           0 :     if (!IsLiteralOrConstInt(f, arg, &lane))
    5333           0 :         return f.failf(arg, "lane selector should be a constant integer literal");
    5334           0 :     if (lane >= GetSimdLanes(opType))
    5335           0 :         return f.failf(arg, "lane selector should be in bounds");
    5336             : 
    5337           0 :     if (!f.writeSimdOp(opType, SimdOperation::Fn_extractLane))
    5338           0 :         return false;
    5339           0 :     if (!f.encoder().writeVarU32(lane))
    5340           0 :         return false;
    5341           0 :     return true;
    5342             : }
    5343             : 
    5344             : static bool
    5345           0 : CheckSimdReplaceLane(FunctionValidator& f, ParseNode* call, SimdType opType, Type* type)
    5346             : {
    5347           0 :     unsigned numArgs = CallArgListLength(call);
    5348           0 :     if (numArgs != 3)
    5349           0 :         return f.failf(call, "expected 2 arguments to SIMD replace, got %u", numArgs);
    5350             : 
    5351           0 :     ParseNode* arg = CallArgList(call);
    5352             : 
    5353             :     // First argument is the vector
    5354           0 :     Type vecType;
    5355           0 :     if (!CheckExpr(f, arg, &vecType))
    5356           0 :         return false;
    5357           0 :     if (!(vecType <= Type(opType))) {
    5358           0 :         return f.failf(arg, "%s is not a subtype of %s", vecType.toChars(),
    5359           0 :                        Type(opType).toChars());
    5360             :     }
    5361             : 
    5362           0 :     arg = NextNode(arg);
    5363             : 
    5364             :     // Second argument is the lane < vector length
    5365             :     uint32_t lane;
    5366           0 :     if (!IsLiteralOrConstInt(f, arg, &lane))
    5367           0 :         return f.failf(arg, "lane selector should be a constant integer literal");
    5368           0 :     if (lane >= GetSimdLanes(opType))
    5369           0 :         return f.failf(arg, "lane selector should be in bounds");
    5370             : 
    5371           0 :     arg = NextNode(arg);
    5372             : 
    5373             :     // Third argument is the scalar
    5374           0 :     Type scalarType;
    5375           0 :     if (!CheckExpr(f, arg, &scalarType))
    5376           0 :         return false;
    5377           0 :     if (!(scalarType <= SimdToCoercedScalarType(opType))) {
    5378           0 :         if (opType == SimdType::Float32x4 && scalarType.isDoubleLit()) {
    5379           0 :             if (!f.encoder().writeOp(Op::F32DemoteF64))
    5380           0 :                 return false;
    5381             :         } else {
    5382           0 :             return f.failf(arg, "%s is not the correct type to replace an element of %s",
    5383           0 :                            scalarType.toChars(), vecType.toChars());
    5384             :         }
    5385             :     }
    5386             : 
    5387           0 :     if (!f.writeSimdOp(opType, SimdOperation::Fn_replaceLane))
    5388           0 :         return false;
    5389           0 :     if (!f.encoder().writeVarU32(lane))
    5390           0 :         return false;
    5391           0 :     *type = opType;
    5392           0 :     return true;
    5393             : }
    5394             : 
    5395             : typedef bool Bitcast;
    5396             : 
    5397             : namespace {
    5398             : // Include CheckSimdCast in unnamed namespace to avoid MSVC name lookup bug (due to the use of Type).
    5399             : 
    5400             : static bool
    5401           0 : CheckSimdCast(FunctionValidator& f, ParseNode* call, SimdType fromType, SimdType toType,
    5402             :               SimdOperation op, Type* type)
    5403             : {
    5404           0 :     if (!CheckSimdCallArgs(f, call, 1, CheckArgIsSubtypeOf(fromType)))
    5405           0 :         return false;
    5406           0 :     if (!f.writeSimdOp(toType, op))
    5407           0 :         return false;
    5408           0 :     *type = toType;
    5409           0 :     return true;
    5410             : }
    5411             : 
    5412             : } // namespace
    5413             : 
    5414             : static bool
    5415           0 : CheckSimdShuffleSelectors(FunctionValidator& f, ParseNode* lane,
    5416             :                           mozilla::Array<uint8_t, 16>& lanes, unsigned numLanes, unsigned maxLane)
    5417             : {
    5418           0 :     for (unsigned i = 0; i < numLanes; i++, lane = NextNode(lane)) {
    5419             :         uint32_t u32;
    5420           0 :         if (!IsLiteralInt(f.m(), lane, &u32))
    5421           0 :             return f.failf(lane, "lane selector should be a constant integer literal");
    5422           0 :         if (u32 >= maxLane)
    5423           0 :             return f.failf(lane, "lane selector should be less than %u", maxLane);
    5424           0 :         lanes[i] = uint8_t(u32);
    5425             :     }
    5426           0 :     return true;
    5427             : }
    5428             : 
    5429             : static bool
    5430           0 : CheckSimdSwizzle(FunctionValidator& f, ParseNode* call, SimdType opType, Type* type)
    5431             : {
    5432           0 :     const unsigned numLanes = GetSimdLanes(opType);
    5433           0 :     unsigned numArgs = CallArgListLength(call);
    5434           0 :     if (numArgs != 1 + numLanes)
    5435           0 :         return f.failf(call, "expected %u arguments to SIMD swizzle, got %u", 1 + numLanes,
    5436           0 :                        numArgs);
    5437             : 
    5438           0 :     Type retType = opType;
    5439           0 :     ParseNode* vec = CallArgList(call);
    5440           0 :     Type vecType;
    5441           0 :     if (!CheckExpr(f, vec, &vecType))
    5442           0 :         return false;
    5443           0 :     if (!(vecType <= retType))
    5444           0 :         return f.failf(vec, "%s is not a subtype of %s", vecType.toChars(), retType.toChars());
    5445             : 
    5446           0 :     if (!f.writeSimdOp(opType, SimdOperation::Fn_swizzle))
    5447           0 :         return false;
    5448             : 
    5449           0 :     mozilla::Array<uint8_t, 16> lanes;
    5450           0 :     if (!CheckSimdShuffleSelectors(f, NextNode(vec), lanes, numLanes, numLanes))
    5451           0 :         return false;
    5452             : 
    5453           0 :     for (unsigned i = 0; i < numLanes; i++) {
    5454           0 :         if (!f.encoder().writeFixedU8(lanes[i]))
    5455           0 :             return false;
    5456             :     }
    5457             : 
    5458           0 :     *type = retType;
    5459           0 :     return true;
    5460             : }
    5461             : 
    5462             : static bool
    5463           0 : CheckSimdShuffle(FunctionValidator& f, ParseNode* call, SimdType opType, Type* type)
    5464             : {
    5465           0 :     const unsigned numLanes = GetSimdLanes(opType);
    5466           0 :     unsigned numArgs = CallArgListLength(call);
    5467           0 :     if (numArgs != 2 + numLanes)
    5468           0 :         return f.failf(call, "expected %u arguments to SIMD shuffle, got %u", 2 + numLanes,
    5469           0 :                        numArgs);
    5470             : 
    5471           0 :     Type retType = opType;
    5472           0 :     ParseNode* arg = CallArgList(call);
    5473           0 :     for (unsigned i = 0; i < 2; i++, arg = NextNode(arg)) {
    5474           0 :         Type type;
    5475           0 :         if (!CheckExpr(f, arg, &type))
    5476           0 :             return false;
    5477           0 :         if (!(type <= retType))
    5478           0 :             return f.failf(arg, "%s is not a subtype of %s", type.toChars(), retType.toChars());
    5479             :     }
    5480             : 
    5481           0 :     if (!f.writeSimdOp(opType, SimdOperation::Fn_shuffle))
    5482           0 :         return false;
    5483             : 
    5484           0 :     mozilla::Array<uint8_t, 16> lanes;
    5485           0 :     if (!CheckSimdShuffleSelectors(f, arg, lanes, numLanes, 2 * numLanes))
    5486           0 :         return false;
    5487             : 
    5488           0 :     for (unsigned i = 0; i < numLanes; i++) {
    5489           0 :         if (!f.encoder().writeFixedU8(uint8_t(lanes[i])))
    5490           0 :             return false;
    5491             :     }
    5492             : 
    5493           0 :     *type = retType;
    5494           0 :     return true;
    5495             : }
    5496             : 
    5497             : static bool
    5498           0 : CheckSimdLoadStoreArgs(FunctionValidator& f, ParseNode* call, Scalar::Type* viewType)
    5499             : {
    5500           0 :     ParseNode* view = CallArgList(call);
    5501           0 :     if (!view->isKind(PNK_NAME))
    5502           0 :         return f.fail(view, "expected Uint8Array view as SIMD.*.load/store first argument");
    5503             : 
    5504           0 :     ParseNode* indexExpr = NextNode(view);
    5505             : 
    5506           0 :     if (!CheckAndPrepareArrayAccess(f, view, indexExpr, YesSimd, viewType))
    5507           0 :         return false;
    5508             : 
    5509           0 :     if (*viewType != Scalar::Uint8)
    5510           0 :         return f.fail(view, "expected Uint8Array view as SIMD.*.load/store first argument");
    5511             : 
    5512           0 :     return true;
    5513             : }
    5514             : 
    5515             : static bool
    5516           0 : CheckSimdLoad(FunctionValidator& f, ParseNode* call, SimdType opType, SimdOperation op,
    5517             :               Type* type)
    5518             : {
    5519           0 :     unsigned numArgs = CallArgListLength(call);
    5520           0 :     if (numArgs != 2)
    5521           0 :         return f.failf(call, "expected 2 arguments to SIMD load, got %u", numArgs);
    5522             : 
    5523             :     Scalar::Type viewType;
    5524           0 :     if (!CheckSimdLoadStoreArgs(f, call, &viewType))
    5525           0 :         return false;
    5526             : 
    5527           0 :     if (!f.writeSimdOp(opType, op))
    5528           0 :         return false;
    5529             : 
    5530           0 :     if (!WriteArrayAccessFlags(f, viewType))
    5531           0 :         return false;
    5532             : 
    5533           0 :     *type = opType;
    5534           0 :     return true;
    5535             : }
    5536             : 
    5537             : static bool
    5538           0 : CheckSimdStore(FunctionValidator& f, ParseNode* call, SimdType opType, SimdOperation op,
    5539             :                Type* type)
    5540             : {
    5541           0 :     unsigned numArgs = CallArgListLength(call);
    5542           0 :     if (numArgs != 3)
    5543           0 :         return f.failf(call, "expected 3 arguments to SIMD store, got %u", numArgs);
    5544             : 
    5545             :     Scalar::Type viewType;
    5546           0 :     if (!CheckSimdLoadStoreArgs(f, call, &viewType))
    5547           0 :         return false;
    5548             : 
    5549           0 :     Type retType = opType;
    5550           0 :     ParseNode* vecExpr = NextNode(NextNode(CallArgList(call)));
    5551           0 :     Type vecType;
    5552           0 :     if (!CheckExpr(f, vecExpr, &vecType))
    5553           0 :         return false;
    5554             : 
    5555           0 :     if (!f.writeSimdOp(opType, op))
    5556           0 :         return false;
    5557             : 
    5558           0 :     if (!WriteArrayAccessFlags(f, viewType))
    5559           0 :         return false;
    5560             : 
    5561           0 :     if (!(vecType <= retType))
    5562           0 :         return f.failf(vecExpr, "%s is not a subtype of %s", vecType.toChars(), retType.toChars());
    5563             : 
    5564           0 :     *type = vecType;
    5565           0 :     return true;
    5566             : }
    5567             : 
    5568             : static bool
    5569           0 : CheckSimdSelect(FunctionValidator& f, ParseNode* call, SimdType opType, Type* type)
    5570             : {
    5571           0 :     if (!CheckSimdCallArgs(f, call, 3, CheckSimdSelectArgs(opType)))
    5572           0 :         return false;
    5573           0 :     if (!f.writeSimdOp(opType, SimdOperation::Fn_select))
    5574           0 :         return false;
    5575           0 :     *type = opType;
    5576           0 :     return true;
    5577             : }
    5578             : 
    5579             : static bool
    5580           0 : CheckSimdAllTrue(FunctionValidator& f, ParseNode* call, SimdType opType, Type* type)
    5581             : {
    5582           0 :     if (!CheckSimdCallArgs(f, call, 1, CheckArgIsSubtypeOf(opType)))
    5583           0 :         return false;
    5584           0 :     if (!f.writeSimdOp(opType, SimdOperation::Fn_allTrue))
    5585           0 :         return false;
    5586           0 :     *type = Type::Int;
    5587           0 :     return true;
    5588             : }
    5589             : 
    5590             : static bool
    5591           0 : CheckSimdAnyTrue(FunctionValidator& f, ParseNode* call, SimdType opType, Type* type)
    5592             : {
    5593           0 :     if (!CheckSimdCallArgs(f, call, 1, CheckArgIsSubtypeOf(opType)))
    5594           0 :         return false;
    5595           0 :     if (!f.writeSimdOp(opType, SimdOperation::Fn_anyTrue))
    5596           0 :         return false;
    5597           0 :     *type = Type::Int;
    5598           0 :     return true;
    5599             : }
    5600             : 
    5601             : static bool
    5602           0 : CheckSimdCheck(FunctionValidator& f, ParseNode* call, SimdType opType, Type* type)
    5603             : {
    5604           0 :     Type coerceTo;
    5605             :     ParseNode* argNode;
    5606           0 :     if (!IsCoercionCall(f.m(), call, &coerceTo, &argNode))
    5607           0 :         return f.failf(call, "expected 1 argument in call to check");
    5608           0 :     return CheckCoercionArg(f, argNode, coerceTo, type);
    5609             : }
    5610             : 
    5611             : static bool
    5612           0 : CheckSimdSplat(FunctionValidator& f, ParseNode* call, SimdType opType, Type* type)
    5613             : {
    5614           0 :     if (!CheckSimdCallArgs(f, call, 1, CheckSimdScalarArgs(opType)))
    5615           0 :         return false;
    5616           0 :     if (!f.writeSimdOp(opType, SimdOperation::Fn_splat))
    5617           0 :         return false;
    5618           0 :     *type = opType;
    5619           0 :     return true;
    5620             : }
    5621             : 
    5622             : static bool
    5623           0 : CheckSimdOperationCall(FunctionValidator& f, ParseNode* call, const ModuleValidator::Global* global,
    5624             :                        Type* type)
    5625             : {
    5626           0 :     f.setUsesSimd();
    5627             : 
    5628           0 :     MOZ_ASSERT(global->isSimdOperation());
    5629             : 
    5630           0 :     SimdType opType = global->simdOperationType();
    5631             : 
    5632           0 :     switch (SimdOperation op = global->simdOperation()) {
    5633             :       case SimdOperation::Fn_check:
    5634           0 :         return CheckSimdCheck(f, call, opType, type);
    5635             : 
    5636             : #define _CASE(OP) case SimdOperation::Fn_##OP:
    5637             :       FOREACH_SHIFT_SIMD_OP(_CASE)
    5638           0 :         return CheckSimdBinaryShift(f, call, opType, op, type);
    5639             : 
    5640             :       FOREACH_COMP_SIMD_OP(_CASE)
    5641           0 :         return CheckSimdBinaryComp(f, call, opType, op, type);
    5642             : 
    5643             :       FOREACH_NUMERIC_SIMD_BINOP(_CASE)
    5644             :       FOREACH_FLOAT_SIMD_BINOP(_CASE)
    5645             :       FOREACH_BITWISE_SIMD_BINOP(_CASE)
    5646             :       FOREACH_SMINT_SIMD_BINOP(_CASE)
    5647           0 :         return CheckSimdBinary(f, call, opType, op, type);
    5648             : #undef _CASE
    5649             : 
    5650             :       case SimdOperation::Fn_extractLane:
    5651           0 :         return CheckSimdExtractLane(f, call, opType, type);
    5652             :       case SimdOperation::Fn_replaceLane:
    5653           0 :         return CheckSimdReplaceLane(f, call, opType, type);
    5654             : 
    5655             :       case SimdOperation::Fn_fromInt8x16Bits:
    5656           0 :         return CheckSimdCast(f, call, SimdType::Int8x16, opType, op, type);
    5657             :       case SimdOperation::Fn_fromUint8x16Bits:
    5658           0 :         return CheckSimdCast(f, call, SimdType::Uint8x16, opType, op, type);
    5659             :       case SimdOperation::Fn_fromInt16x8Bits:
    5660           0 :         return CheckSimdCast(f, call, SimdType::Int16x8, opType, op, type);
    5661             :       case SimdOperation::Fn_fromUint16x8Bits:
    5662           0 :         return CheckSimdCast(f, call, SimdType::Uint16x8, opType, op, type);
    5663             :       case SimdOperation::Fn_fromInt32x4:
    5664             :       case SimdOperation::Fn_fromInt32x4Bits:
    5665           0 :         return CheckSimdCast(f, call, SimdType::Int32x4, opType, op, type);
    5666             :       case SimdOperation::Fn_fromUint32x4:
    5667             :       case SimdOperation::Fn_fromUint32x4Bits:
    5668           0 :         return CheckSimdCast(f, call, SimdType::Uint32x4, opType, op, type);
    5669             :       case SimdOperation::Fn_fromFloat32x4:
    5670             :       case SimdOperation::Fn_fromFloat32x4Bits:
    5671           0 :         return CheckSimdCast(f, call, SimdType::Float32x4, opType, op, type);
    5672             : 
    5673             :       case SimdOperation::Fn_abs:
    5674             :       case SimdOperation::Fn_neg:
    5675             :       case SimdOperation::Fn_not:
    5676             :       case SimdOperation::Fn_sqrt:
    5677             :       case SimdOperation::Fn_reciprocalApproximation:
    5678             :       case SimdOperation::Fn_reciprocalSqrtApproximation:
    5679           0 :         return CheckSimdUnary(f, call, opType, op, type);
    5680             : 
    5681             :       case SimdOperation::Fn_swizzle:
    5682           0 :         return CheckSimdSwizzle(f, call, opType, type);
    5683             :       case SimdOperation::Fn_shuffle:
    5684           0 :         return CheckSimdShuffle(f, call, opType, type);
    5685             : 
    5686             :       case SimdOperation::Fn_load:
    5687             :       case SimdOperation::Fn_load1:
    5688             :       case SimdOperation::Fn_load2:
    5689           0 :         return CheckSimdLoad(f, call, opType, op, type);
    5690             :       case SimdOperation::Fn_store:
    5691             :       case SimdOperation::Fn_store1:
    5692             :       case SimdOperation::Fn_store2:
    5693           0 :         return CheckSimdStore(f, call, opType, op, type);
    5694             : 
    5695             :       case SimdOperation::Fn_select:
    5696           0 :         return CheckSimdSelect(f, call, opType, type);
    5697             : 
    5698             :       case SimdOperation::Fn_splat:
    5699           0 :         return CheckSimdSplat(f, call, opType, type);
    5700             : 
    5701             :       case SimdOperation::Fn_allTrue:
    5702           0 :         return CheckSimdAllTrue(f, call, opType, type);
    5703             :       case SimdOperation::Fn_anyTrue:
    5704           0 :         return CheckSimdAnyTrue(f, call, opType, type);
    5705             : 
    5706             :       case SimdOperation::Fn_load3:
    5707             :       case SimdOperation::Fn_store3:
    5708           0 :         return f.fail(call, "asm.js does not support 3-element SIMD loads or stores");
    5709             : 
    5710             :       case SimdOperation::Constructor:
    5711           0 :         MOZ_CRASH("constructors are handled in CheckSimdCtorCall");
    5712             :       case SimdOperation::Fn_fromFloat64x2Bits:
    5713           0 :         MOZ_CRASH("NYI");
    5714             :     }
    5715           0 :     MOZ_CRASH("unexpected simd operation in CheckSimdOperationCall");
    5716             : }
    5717             : 
    5718             : static bool
    5719           0 : CheckSimdCtorCall(FunctionValidator& f, ParseNode* call, const ModuleValidator::Global* global,
    5720             :                   Type* type)
    5721             : {
    5722           0 :     f.setUsesSimd();
    5723             : 
    5724           0 :     MOZ_ASSERT(call->isKind(PNK_CALL));
    5725             : 
    5726           0 :     SimdType simdType = global->simdCtorType();
    5727           0 :     unsigned length = GetSimdLanes(simdType);
    5728           0 :     if (!CheckSimdCallArgs(f, call, length, CheckSimdScalarArgs(simdType)))
    5729           0 :         return false;
    5730             : 
    5731           0 :     if (!f.writeSimdOp(simdType, SimdOperation::Constructor))
    5732           0 :         return false;
    5733             : 
    5734           0 :     *type = simdType;
    5735           0 :     return true;
    5736             : }
    5737             : 
    5738             : static bool
    5739           0 : CheckUncoercedCall(FunctionValidator& f, ParseNode* expr, Type* type)
    5740             : {
    5741           0 :     MOZ_ASSERT(expr->isKind(PNK_CALL));
    5742             : 
    5743             :     const ModuleValidator::Global* global;
    5744           0 :     if (IsCallToGlobal(f.m(), expr, &global)) {
    5745           0 :         if (global->isMathFunction())
    5746           0 :             return CheckMathBuiltinCall(f, expr, global->mathBuiltinFunction(), type);
    5747           0 :         if (global->isAtomicsFunction())
    5748           0 :             return CheckAtomicsBuiltinCall(f, expr, global->atomicsBuiltinFunction(), type);
    5749           0 :         if (global->isSimdCtor())
    5750           0 :             return CheckSimdCtorCall(f, expr, global, type);
    5751           0 :         if (global->isSimdOperation())
    5752           0 :             return CheckSimdOperationCall(f, expr, global, type);
    5753             :     }
    5754             : 
    5755             :     return f.fail(expr, "all function calls must either be calls to standard lib math functions, "
    5756             :                         "standard atomic functions, standard SIMD constructors or operations, "
    5757             :                         "ignored (via f(); or comma-expression), coerced to signed (via f()|0), "
    5758           0 :                         "coerced to float (via fround(f())) or coerced to double (via +f())");
    5759             : }
    5760             : 
    5761             : static bool
    5762           0 : CoerceResult(FunctionValidator& f, ParseNode* expr, Type expected, Type actual,
    5763             :              Type* type)
    5764             : {
    5765           0 :     MOZ_ASSERT(expected.isCanonical());
    5766             : 
    5767             :     // At this point, the bytecode resembles this:
    5768             :     //      | the thing we wanted to coerce | current position |>
    5769           0 :     switch (expected.which()) {
    5770             :       case Type::Void:
    5771           0 :         if (!actual.isVoid()) {
    5772           0 :             if (!f.encoder().writeOp(Op::Drop))
    5773           0 :                 return false;
    5774             :         }
    5775           0 :         break;
    5776             :       case Type::Int:
    5777           0 :         if (!actual.isIntish())
    5778           0 :             return f.failf(expr, "%s is not a subtype of intish", actual.toChars());
    5779           0 :         break;
    5780             :       case Type::Float:
    5781           0 :         if (!CheckFloatCoercionArg(f, expr, actual))
    5782           0 :             return false;
    5783           0 :         break;
    5784             :       case Type::Double:
    5785           0 :         if (actual.isMaybeDouble()) {
    5786             :             // No conversion necessary.
    5787           0 :         } else if (actual.isMaybeFloat()) {
    5788           0 :             if (!f.encoder().writeOp(Op::F64PromoteF32))
    5789           0 :                 return false;
    5790           0 :         } else if (actual.isSigned()) {
    5791           0 :             if (!f.encoder().writeOp(Op::F64ConvertSI32))
    5792           0 :                 return false;
    5793           0 :         } else if (actual.isUnsigned()) {
    5794           0 :             if (!f.encoder().writeOp(Op::F64ConvertUI32))
    5795           0 :                 return false;
    5796             :         } else {
    5797           0 :             return f.failf(expr, "%s is not a subtype of double?, float?, signed or unsigned", actual.toChars());
    5798             :         }
    5799           0 :         break;
    5800             :       default:
    5801           0 :         MOZ_ASSERT(expected.isSimd(), "Incomplete switch");
    5802           0 :         if (actual != expected)
    5803           0 :             return f.failf(expr, "got type %s, expected %s", actual.toChars(), expected.toChars());
    5804           0 :         break;
    5805             :     }
    5806             : 
    5807           0 :     *type = Type::ret(expected);
    5808           0 :     return true;
    5809             : }
    5810             : 
    5811             : static bool
    5812           0 : CheckCoercedMathBuiltinCall(FunctionValidator& f, ParseNode* callNode, AsmJSMathBuiltinFunction func,
    5813             :                             Type ret, Type* type)
    5814             : {
    5815           0 :     Type actual;
    5816           0 :     if (!CheckMathBuiltinCall(f, callNode, func, &actual))
    5817           0 :         return false;
    5818           0 :     return CoerceResult(f, callNode, ret, actual, type);
    5819             : }
    5820             : 
    5821             : static bool
    5822           0 : CheckCoercedSimdCall(FunctionValidator& f, ParseNode* call, const ModuleValidator::Global* global,
    5823             :                      Type ret, Type* type)
    5824             : {
    5825           0 :     MOZ_ASSERT(ret.isCanonical());
    5826             : 
    5827           0 :     Type actual;
    5828           0 :     if (global->isSimdCtor()) {
    5829           0 :         if (!CheckSimdCtorCall(f, call, global, &actual))
    5830           0 :             return false;
    5831           0 :         MOZ_ASSERT(actual.isSimd());
    5832             :     } else {
    5833           0 :         MOZ_ASSERT(global->isSimdOperation());
    5834           0 :         if (!CheckSimdOperationCall(f, call, global, &actual))
    5835           0 :             return false;
    5836             :     }
    5837             : 
    5838           0 :     return CoerceResult(f, call, ret, actual, type);
    5839             : }
    5840             : 
    5841             : static bool
    5842           0 : CheckCoercedAtomicsBuiltinCall(FunctionValidator& f, ParseNode* callNode,
    5843             :                                AsmJSAtomicsBuiltinFunction func, Type ret, Type* type)
    5844             : {
    5845           0 :     MOZ_ASSERT(ret.isCanonical());
    5846             : 
    5847           0 :     Type actual;
    5848           0 :     if (!CheckAtomicsBuiltinCall(f, callNode, func, &actual))
    5849           0 :         return false;
    5850           0 :     return CoerceResult(f, callNode, ret, actual, type);
    5851             : }
    5852             : 
    5853             : static bool
    5854           0 : CheckCoercedCall(FunctionValidator& f, ParseNode* call, Type ret, Type* type)
    5855             : {
    5856           0 :     MOZ_ASSERT(ret.isCanonical());
    5857             : 
    5858           0 :     if (!CheckRecursionLimitDontReport(f.cx()))
    5859           0 :         return f.m().failOverRecursed();
    5860             : 
    5861           0 :     bool isSimd = false;
    5862           0 :     if (IsNumericLiteral(f.m(), call, &isSimd)) {
    5863           0 :         if (isSimd)
    5864           0 :             f.setUsesSimd();
    5865           0 :         NumLit lit = ExtractNumericLiteral(f.m(), call);
    5866           0 :         if (!f.writeConstExpr(lit))
    5867           0 :             return false;
    5868           0 :         return CoerceResult(f, call, ret, Type::lit(lit), type);
    5869             :     }
    5870             : 
    5871           0 :     ParseNode* callee = CallCallee(call);
    5872             : 
    5873           0 :     if (callee->isKind(PNK_ELEM))
    5874           0 :         return CheckFuncPtrCall(f, call, ret, type);
    5875             : 
    5876           0 :     if (!callee->isKind(PNK_NAME))
    5877           0 :         return f.fail(callee, "unexpected callee expression type");
    5878             : 
    5879           0 :     PropertyName* calleeName = callee->name();
    5880             : 
    5881           0 :     if (const ModuleValidator::Global* global = f.lookupGlobal(calleeName)) {
    5882           0 :         switch (global->which()) {
    5883             :           case ModuleValidator::Global::FFI:
    5884           0 :             return CheckFFICall(f, call, global->ffiIndex(), ret, type);
    5885             :           case ModuleValidator::Global::MathBuiltinFunction:
    5886           0 :             return CheckCoercedMathBuiltinCall(f, call, global->mathBuiltinFunction(), ret, type);
    5887             :           case ModuleValidator::Global::AtomicsBuiltinFunction:
    5888           0 :             return CheckCoercedAtomicsBuiltinCall(f, call, global->atomicsBuiltinFunction(), ret, type);
    5889             :           case ModuleValidator::Global::ConstantLiteral:
    5890             :           case ModuleValidator::Global::ConstantImport:
    5891             :           case ModuleValidator::Global::Variable:
    5892             :           case ModuleValidator::Global::FuncPtrTable:
    5893             :           case ModuleValidator::Global::ArrayView:
    5894             :           case ModuleValidator::Global::ArrayViewCtor:
    5895           0 :             return f.failName(callee, "'%s' is not callable function", callee->name());
    5896             :           case ModuleValidator::Global::SimdCtor:
    5897             :           case ModuleValidator::Global::SimdOp:
    5898           0 :             return CheckCoercedSimdCall(f, call, global, ret, type);
    5899             :           case ModuleValidator::Global::Function:
    5900           0 :             break;
    5901             :         }
    5902             :     }
    5903             : 
    5904           0 :     return CheckInternalCall(f, call, calleeName, ret, type);
    5905             : }
    5906             : 
    5907             : static bool
    5908           0 : CheckPos(FunctionValidator& f, ParseNode* pos, Type* type)
    5909             : {
    5910           0 :     MOZ_ASSERT(pos->isKind(PNK_POS));
    5911           0 :     ParseNode* operand = UnaryKid(pos);
    5912             : 
    5913           0 :     if (operand->isKind(PNK_CALL))
    5914           0 :         return CheckCoercedCall(f, operand, Type::Double, type);
    5915             : 
    5916           0 :     Type actual;
    5917           0 :     if (!CheckExpr(f, operand, &actual))
    5918           0 :         return false;
    5919             : 
    5920           0 :     return CoerceResult(f, operand, Type::Double, actual, type);
    5921             : }
    5922             : 
    5923             : static bool
    5924           0 : CheckNot(FunctionValidator& f, ParseNode* expr, Type* type)
    5925             : {
    5926           0 :     MOZ_ASSERT(expr->isKind(PNK_NOT));
    5927           0 :     ParseNode* operand = UnaryKid(expr);
    5928             : 
    5929           0 :     Type operandType;
    5930           0 :     if (!CheckExpr(f, operand, &operandType))
    5931           0 :         return false;
    5932             : 
    5933           0 :     if (!operandType.isInt())
    5934           0 :         return f.failf(operand, "%s is not a subtype of int", operandType.toChars());
    5935             : 
    5936           0 :     *type = Type::Int;
    5937           0 :     return f.encoder().writeOp(Op::I32Eqz);
    5938             : }
    5939             : 
    5940             : static bool
    5941           0 : CheckNeg(FunctionValidator& f, ParseNode* expr, Type* type)
    5942             : {
    5943           0 :     MOZ_ASSERT(expr->isKind(PNK_NEG));
    5944           0 :     ParseNode* operand = UnaryKid(expr);
    5945             : 
    5946           0 :     Type operandType;
    5947           0 :     if (!CheckExpr(f, operand, &operandType))
    5948           0 :         return false;
    5949             : 
    5950           0 :     if (operandType.isInt()) {
    5951           0 :         *type = Type::Intish;
    5952           0 :         return f.encoder().writeOp(MozOp::I32Neg);
    5953             :     }
    5954             : 
    5955           0 :     if (operandType.isMaybeDouble()) {
    5956           0 :         *type = Type::Double;
    5957           0 :         return f.encoder().writeOp(Op::F64Neg);
    5958             :     }
    5959             : 
    5960           0 :     if (operandType.isMaybeFloat()) {
    5961           0 :         *type = Type::Floatish;
    5962           0 :         return f.encoder().writeOp(Op::F32Neg);
    5963             :     }
    5964             : 
    5965           0 :     return f.failf(operand, "%s is not a subtype of int, float? or double?", operandType.toChars());
    5966             : }
    5967             : 
    5968             : static bool
    5969           0 : CheckCoerceToInt(FunctionValidator& f, ParseNode* expr, Type* type)
    5970             : {
    5971           0 :     MOZ_ASSERT(expr->isKind(PNK_BITNOT));
    5972           0 :     ParseNode* operand = UnaryKid(expr);
    5973             : 
    5974           0 :     Type operandType;
    5975           0 :     if (!CheckExpr(f, operand, &operandType))
    5976           0 :         return false;
    5977             : 
    5978           0 :     if (operandType.isMaybeDouble() || operandType.isMaybeFloat()) {
    5979           0 :         *type = Type::Signed;
    5980           0 :         Op opcode = operandType.isMaybeDouble() ? Op::I32TruncSF64 : Op::I32TruncSF32;
    5981           0 :         return f.encoder().writeOp(opcode);
    5982             :     }
    5983             : 
    5984           0 :     if (!operandType.isIntish())
    5985           0 :         return f.failf(operand, "%s is not a subtype of double?, float? or intish", operandType.toChars());
    5986             : 
    5987           0 :     *type = Type::Signed;
    5988           0 :     return true;
    5989             : }
    5990             : 
    5991             : static bool
    5992           0 : CheckBitNot(FunctionValidator& f, ParseNode* neg, Type* type)
    5993             : {
    5994           0 :     MOZ_ASSERT(neg->isKind(PNK_BITNOT));
    5995           0 :     ParseNode* operand = UnaryKid(neg);
    5996             : 
    5997           0 :     if (operand->isKind(PNK_BITNOT))
    5998           0 :         return CheckCoerceToInt(f, operand, type);
    5999             : 
    6000           0 :     Type operandType;
    6001           0 :     if (!CheckExpr(f, operand, &operandType))
    6002           0 :         return false;
    6003             : 
    6004           0 :     if (!operandType.isIntish())
    6005           0 :         return f.failf(operand, "%s is not a subtype of intish", operandType.toChars());
    6006             : 
    6007           0 :     if (!f.encoder().writeOp(MozOp::I32BitNot))
    6008           0 :         return false;
    6009             : 
    6010           0 :     *type = Type::Signed;
    6011           0 :     return true;
    6012             : }
    6013             : 
    6014             : static bool
    6015             : CheckAsExprStatement(FunctionValidator& f, ParseNode* exprStmt);
    6016             : 
    6017             : static bool
    6018           0 : CheckComma(FunctionValidator& f, ParseNode* comma, Type* type)
    6019             : {
    6020           0 :     MOZ_ASSERT(comma->isKind(PNK_COMMA));
    6021           0 :     ParseNode* operands = ListHead(comma);
    6022             : 
    6023             :     // The block depth isn't taken into account here, because a comma list can't
    6024             :     // contain breaks and continues and nested control flow structures.
    6025           0 :     if (!f.encoder().writeOp(Op::Block))
    6026           0 :         return false;
    6027             : 
    6028             :     size_t typeAt;
    6029           0 :     if (!f.encoder().writePatchableFixedU7(&typeAt))
    6030           0 :         return false;
    6031             : 
    6032           0 :     ParseNode* pn = operands;
    6033           0 :     for (; NextNode(pn); pn = NextNode(pn)) {
    6034           0 :         if (!CheckAsExprStatement(f, pn))
    6035           0 :             return false;
    6036             :     }
    6037             : 
    6038           0 :     if (!CheckExpr(f, pn, type))
    6039           0 :         return false;
    6040             : 
    6041           0 :     f.encoder().patchFixedU7(typeAt, uint8_t(type->toWasmBlockSignatureType()));
    6042             : 
    6043           0 :     return f.encoder().writeOp(Op::End);
    6044             : }
    6045             : 
    6046             : static bool
    6047           0 : CheckConditional(FunctionValidator& f, ParseNode* ternary, Type* type)
    6048             : {
    6049           0 :     MOZ_ASSERT(ternary->isKind(PNK_CONDITIONAL));
    6050             : 
    6051           0 :     ParseNode* cond = TernaryKid1(ternary);
    6052           0 :     ParseNode* thenExpr = TernaryKid2(ternary);
    6053           0 :     ParseNode* elseExpr = TernaryKid3(ternary);
    6054             : 
    6055           0 :     Type condType;
    6056           0 :     if (!CheckExpr(f, cond, &condType))
    6057           0 :         return false;
    6058             : 
    6059           0 :     if (!condType.isInt())
    6060           0 :         return f.failf(cond, "%s is not a subtype of int", condType.toChars());
    6061             : 
    6062             :     size_t typeAt;
    6063           0 :     if (!f.pushIf(&typeAt))
    6064           0 :         return false;
    6065             : 
    6066           0 :     Type thenType;
    6067           0 :     if (!CheckExpr(f, thenExpr, &thenType))
    6068           0 :         return false;
    6069             : 
    6070           0 :     if (!f.switchToElse())
    6071           0 :         return false;
    6072             : 
    6073           0 :     Type elseType;
    6074           0 :     if (!CheckExpr(f, elseExpr, &elseType))
    6075           0 :         return false;
    6076             : 
    6077           0 :     if (thenType.isInt() && elseType.isInt()) {
    6078           0 :         *type = Type::Int;
    6079           0 :     } else if (thenType.isDouble() && elseType.isDouble()) {
    6080           0 :         *type = Type::Double;
    6081           0 :     } else if (thenType.isFloat() && elseType.isFloat()) {
    6082           0 :         *type = Type::Float;
    6083           0 :     } else if (thenType.isSimd() && elseType == thenType) {
    6084           0 :         *type = thenType;
    6085             :     } else {
    6086           0 :         return f.failf(ternary, "then/else branches of conditional must both produce int, float, "
    6087             :                        "double or SIMD types, current types are %s and %s",
    6088           0 :                        thenType.toChars(), elseType.toChars());
    6089             :     }
    6090             : 
    6091           0 :     if (!f.popIf(typeAt, type->toWasmBlockSignatureType()))
    6092           0 :         return false;
    6093             : 
    6094           0 :     return true;
    6095             : }
    6096             : 
    6097             : static bool
    6098           0 : IsValidIntMultiplyConstant(ModuleValidator& m, ParseNode* expr)
    6099             : {
    6100           0 :     if (!IsNumericLiteral(m, expr))
    6101           0 :         return false;
    6102             : 
    6103           0 :     NumLit lit = ExtractNumericLiteral(m, expr);
    6104           0 :     switch (lit.which()) {
    6105             :       case NumLit::Fixnum:
    6106             :       case NumLit::NegativeInt:
    6107           0 :         if (abs(lit.toInt32()) < (1<<20))
    6108           0 :             return true;
    6109           0 :         return false;
    6110             :       case NumLit::BigUnsigned:
    6111             :       case NumLit::Double:
    6112             :       case NumLit::Float:
    6113             :       case NumLit::OutOfRangeInt:
    6114             :       case NumLit::Int8x16:
    6115             :       case NumLit::Uint8x16:
    6116             :       case NumLit::Int16x8:
    6117             :       case NumLit::Uint16x8:
    6118             :       case NumLit::Int32x4:
    6119             :       case NumLit::Uint32x4:
    6120             :       case NumLit::Float32x4:
    6121             :       case NumLit::Bool8x16:
    6122             :       case NumLit::Bool16x8:
    6123             :       case NumLit::Bool32x4:
    6124           0 :         return false;
    6125             :     }
    6126             : 
    6127           0 :     MOZ_MAKE_COMPILER_ASSUME_IS_UNREACHABLE("Bad literal");
    6128             : }
    6129             : 
    6130             : static bool
    6131           0 : CheckMultiply(FunctionValidator& f, ParseNode* star, Type* type)
    6132             : {
    6133           0 :     MOZ_ASSERT(star->isKind(PNK_STAR));
    6134           0 :     ParseNode* lhs = MultiplyLeft(star);
    6135           0 :     ParseNode* rhs = MultiplyRight(star);
    6136             : 
    6137           0 :     Type lhsType;
    6138           0 :     if (!CheckExpr(f, lhs, &lhsType))
    6139           0 :         return false;
    6140             : 
    6141           0 :     Type rhsType;
    6142           0 :     if (!CheckExpr(f, rhs, &rhsType))
    6143           0 :         return false;
    6144             : 
    6145           0 :     if (lhsType.isInt() && rhsType.isInt()) {
    6146           0 :         if (!IsValidIntMultiplyConstant(f.m(), lhs) && !IsValidIntMultiplyConstant(f.m(), rhs))
    6147           0 :             return f.fail(star, "one arg to int multiply must be a small (-2^20, 2^20) int literal");
    6148           0 :         *type = Type::Intish;
    6149           0 :         return f.encoder().writeOp(Op::I32Mul);
    6150             :     }
    6151             : 
    6152           0 :     if (lhsType.isMaybeDouble() && rhsType.isMaybeDouble()) {
    6153           0 :         *type = Type::Double;
    6154           0 :         return f.encoder().writeOp(Op::F64Mul);
    6155             :     }
    6156             : 
    6157           0 :     if (lhsType.isMaybeFloat() && rhsType.isMaybeFloat()) {
    6158           0 :         *type = Type::Floatish;
    6159           0 :         return f.encoder().writeOp(Op::F32Mul);
    6160             :     }
    6161             : 
    6162           0 :     return f.fail(star, "multiply operands must be both int, both double? or both float?");
    6163             : }
    6164             : 
    6165             : static bool
    6166           0 : CheckAddOrSub(FunctionValidator& f, ParseNode* expr, Type* type, unsigned* numAddOrSubOut = nullptr)
    6167             : {
    6168           0 :     if (!CheckRecursionLimitDontReport(f.cx()))
    6169           0 :         return f.m().failOverRecursed();
    6170             : 
    6171           0 :     MOZ_ASSERT(expr->isKind(PNK_ADD) || expr->isKind(PNK_SUB));
    6172           0 :     ParseNode* lhs = AddSubLeft(expr);
    6173           0 :     ParseNode* rhs = AddSubRight(expr);
    6174             : 
    6175           0 :     Type lhsType, rhsType;
    6176             :     unsigned lhsNumAddOrSub, rhsNumAddOrSub;
    6177             : 
    6178           0 :     if (lhs->isKind(PNK_ADD) || lhs->isKind(PNK_SUB)) {
    6179           0 :         if (!CheckAddOrSub(f, lhs, &lhsType, &lhsNumAddOrSub))
    6180           0 :             return false;
    6181           0 :         if (lhsType == Type::Intish)
    6182           0 :             lhsType = Type::Int;
    6183             :     } else {
    6184           0 :         if (!CheckExpr(f, lhs, &lhsType))
    6185           0 :             return false;
    6186           0 :         lhsNumAddOrSub = 0;
    6187             :     }
    6188             : 
    6189           0 :     if (rhs->isKind(PNK_ADD) || rhs->isKind(PNK_SUB)) {
    6190           0 :         if (!CheckAddOrSub(f, rhs, &rhsType, &rhsNumAddOrSub))
    6191           0 :             return false;
    6192           0 :         if (rhsType == Type::Intish)
    6193           0 :             rhsType = Type::Int;
    6194             :     } else {
    6195           0 :         if (!CheckExpr(f, rhs, &rhsType))
    6196           0 :             return false;
    6197           0 :         rhsNumAddOrSub = 0;
    6198             :     }
    6199             : 
    6200           0 :     unsigned numAddOrSub = lhsNumAddOrSub + rhsNumAddOrSub + 1;
    6201           0 :     if (numAddOrSub > (1<<20))
    6202           0 :         return f.fail(expr, "too many + or - without intervening coercion");
    6203             : 
    6204           0 :     if (lhsType.isInt() && rhsType.isInt()) {
    6205           0 :         if (!f.encoder().writeOp(expr->isKind(PNK_ADD) ? Op::I32Add : Op::I32Sub))
    6206           0 :             return false;
    6207           0 :         *type = Type::Intish;
    6208           0 :     } else if (lhsType.isMaybeDouble() && rhsType.isMaybeDouble()) {
    6209           0 :         if (!f.encoder().writeOp(expr->isKind(PNK_ADD) ? Op::F64Add : Op::F64Sub))
    6210           0 :             return false;
    6211           0 :         *type = Type::Double;
    6212           0 :     } else if (lhsType.isMaybeFloat() && rhsType.isMaybeFloat()) {
    6213           0 :         if (!f.encoder().writeOp(expr->isKind(PNK_ADD) ? Op::F32Add : Op::F32Sub))
    6214           0 :             return false;
    6215           0 :         *type = Type::Floatish;
    6216             :     } else {
    6217           0 :         return f.failf(expr, "operands to + or - must both be int, float? or double?, got %s and %s",
    6218           0 :                        lhsType.toChars(), rhsType.toChars());
    6219             :     }
    6220             : 
    6221           0 :     if (numAddOrSubOut)
    6222           0 :         *numAddOrSubOut = numAddOrSub;
    6223           0 :     return true;
    6224             : }
    6225             : 
    6226             : static bool
    6227           0 : CheckDivOrMod(FunctionValidator& f, ParseNode* expr, Type* type)
    6228             : {
    6229           0 :     MOZ_ASSERT(expr->isKind(PNK_DIV) || expr->isKind(PNK_MOD));
    6230             : 
    6231           0 :     ParseNode* lhs = DivOrModLeft(expr);
    6232           0 :     ParseNode* rhs = DivOrModRight(expr);
    6233             : 
    6234           0 :     Type lhsType, rhsType;
    6235           0 :     if (!CheckExpr(f, lhs, &lhsType))
    6236           0 :         return false;
    6237           0 :     if (!CheckExpr(f, rhs, &rhsType))
    6238           0 :         return false;
    6239             : 
    6240           0 :     if (lhsType.isMaybeDouble() && rhsType.isMaybeDouble()) {
    6241           0 :         *type = Type::Double;
    6242           0 :         if (expr->isKind(PNK_DIV))
    6243           0 :             return f.encoder().writeOp(Op::F64Div);
    6244           0 :         return f.encoder().writeOp(MozOp::F64Mod);
    6245             :     }
    6246             : 
    6247           0 :     if (lhsType.isMaybeFloat() && rhsType.isMaybeFloat()) {
    6248           0 :         *type = Type::Floatish;
    6249           0 :         if (expr->isKind(PNK_DIV))
    6250           0 :             return f.encoder().writeOp(Op::F32Div);
    6251             :         else
    6252           0 :             return f.fail(expr, "modulo cannot receive float arguments");
    6253             :     }
    6254             : 
    6255           0 :     if (lhsType.isSigned() && rhsType.isSigned()) {
    6256           0 :         *type = Type::Intish;
    6257           0 :         return f.encoder().writeOp(expr->isKind(PNK_DIV) ? Op::I32DivS : Op::I32RemS);
    6258             :     }
    6259             : 
    6260           0 :     if (lhsType.isUnsigned() && rhsType.isUnsigned()) {
    6261           0 :         *type = Type::Intish;
    6262           0 :         return f.encoder().writeOp(expr->isKind(PNK_DIV) ? Op::I32DivU : Op::I32RemU);
    6263             :     }
    6264             : 
    6265           0 :     return f.failf(expr, "arguments to / or %% must both be double?, float?, signed, or unsigned; "
    6266           0 :                    "%s and %s are given", lhsType.toChars(), rhsType.toChars());
    6267             : }
    6268             : 
    6269             : static bool
    6270           0 : CheckComparison(FunctionValidator& f, ParseNode* comp, Type* type)
    6271             : {
    6272           0 :     MOZ_ASSERT(comp->isKind(PNK_LT) || comp->isKind(PNK_LE) || comp->isKind(PNK_GT) ||
    6273             :                comp->isKind(PNK_GE) || comp->isKind(PNK_EQ) || comp->isKind(PNK_NE));
    6274             : 
    6275           0 :     ParseNode* lhs = ComparisonLeft(comp);
    6276           0 :     ParseNode* rhs = ComparisonRight(comp);
    6277             : 
    6278           0 :     Type lhsType, rhsType;
    6279           0 :     if (!CheckExpr(f, lhs, &lhsType))
    6280           0 :         return false;
    6281           0 :     if (!CheckExpr(f, rhs, &rhsType))
    6282           0 :         return false;
    6283             : 
    6284           0 :     if (!(lhsType.isSigned() && rhsType.isSigned()) &&
    6285           0 :         !(lhsType.isUnsigned() && rhsType.isUnsigned()) &&
    6286           0 :         !(lhsType.isDouble() && rhsType.isDouble()) &&
    6287           0 :         !(lhsType.isFloat() && rhsType.isFloat()))
    6288             :     {
    6289           0 :         return f.failf(comp, "arguments to a comparison must both be signed, unsigned, floats or doubles; "
    6290           0 :                        "%s and %s are given", lhsType.toChars(), rhsType.toChars());
    6291             :     }
    6292             : 
    6293             :     Op stmt;
    6294           0 :     if (lhsType.isSigned() && rhsType.isSigned()) {
    6295           0 :         switch (comp->getOp()) {
    6296           0 :           case JSOP_EQ: stmt = Op::I32Eq;  break;
    6297           0 :           case JSOP_NE: stmt = Op::I32Ne;  break;
    6298           0 :           case JSOP_LT: stmt = Op::I32LtS; break;
    6299           0 :           case JSOP_LE: stmt = Op::I32LeS; break;
    6300           0 :           case JSOP_GT: stmt = Op::I32GtS; break;
    6301           0 :           case JSOP_GE: stmt = Op::I32GeS; break;
    6302           0 :           default: MOZ_CRASH("unexpected comparison op");
    6303             :         }
    6304           0 :     } else if (lhsType.isUnsigned() && rhsType.isUnsigned()) {
    6305           0 :         switch (comp->getOp()) {
    6306           0 :           case JSOP_EQ: stmt = Op::I32Eq;  break;
    6307           0 :           case JSOP_NE: stmt = Op::I32Ne;  break;
    6308           0 :           case JSOP_LT: stmt = Op::I32LtU; break;
    6309           0 :           case JSOP_LE: stmt = Op::I32LeU; break;
    6310           0 :           case JSOP_GT: stmt = Op::I32GtU; break;
    6311           0 :           case JSOP_GE: stmt = Op::I32GeU; break;
    6312           0 :           default: MOZ_CRASH("unexpected comparison op");
    6313             :         }
    6314           0 :     } else if (lhsType.isDouble()) {
    6315           0 :         switch (comp->getOp()) {
    6316           0 :           case JSOP_EQ: stmt = Op::F64Eq; break;
    6317           0 :           case JSOP_NE: stmt = Op::F64Ne; break;
    6318           0 :           case JSOP_LT: stmt = Op::F64Lt; break;
    6319           0 :           case JSOP_LE: stmt = Op::F64Le; break;
    6320           0 :           case JSOP_GT: stmt = Op::F64Gt; break;
    6321           0 :           case JSOP_GE: stmt = Op::F64Ge; break;
    6322           0 :           default: MOZ_CRASH("unexpected comparison op");
    6323             :         }
    6324           0 :     } else if (lhsType.isFloat()) {
    6325           0 :         switch (comp->getOp()) {
    6326           0 :           case JSOP_EQ: stmt = Op::F32Eq; break;
    6327           0 :           case JSOP_NE: stmt = Op::F32Ne; break;
    6328           0 :           case JSOP_LT: stmt = Op::F32Lt; break;
    6329           0 :           case JSOP_LE: stmt = Op::F32Le; break;
    6330           0 :           case JSOP_GT: stmt = Op::F32Gt; break;
    6331           0 :           case JSOP_GE: stmt = Op::F32Ge; break;
    6332           0 :           default: MOZ_CRASH("unexpected comparison op");
    6333             :         }
    6334             :     } else {
    6335           0 :         MOZ_CRASH("unexpected type");
    6336             :     }
    6337             : 
    6338           0 :     *type = Type::Int;
    6339           0 :     return f.encoder().writeOp(stmt);
    6340             : }
    6341             : 
    6342             : static bool
    6343           0 : CheckBitwise(FunctionValidator& f, ParseNode* bitwise, Type* type)
    6344             : {
    6345           0 :     ParseNode* lhs = BitwiseLeft(bitwise);
    6346           0 :     ParseNode* rhs = BitwiseRight(bitwise);
    6347             : 
    6348             :     int32_t identityElement;
    6349             :     bool onlyOnRight;
    6350           0 :     switch (bitwise->getKind()) {
    6351           0 :       case PNK_BITOR:  identityElement = 0;  onlyOnRight = false; *type = Type::Signed;   break;
    6352           0 :       case PNK_BITAND: identityElement = -1; onlyOnRight = false; *type = Type::Signed;   break;
    6353           0 :       case PNK_BITXOR: identityElement = 0;  onlyOnRight = false; *type = Type::Signed;   break;
    6354           0 :       case PNK_LSH:    identityElement = 0;  onlyOnRight = true;  *type = Type::Signed;   break;
    6355           0 :       case PNK_RSH:    identityElement = 0;  onlyOnRight = true;  *type = Type::Signed;   break;
    6356           0 :       case PNK_URSH:   identityElement = 0;  onlyOnRight = true;  *type = Type::Unsigned; break;
    6357           0 :       default: MOZ_CRASH("not a bitwise op");
    6358             :     }
    6359             : 
    6360             :     uint32_t i;
    6361           0 :     if (!onlyOnRight && IsLiteralInt(f.m(), lhs, &i) && i == uint32_t(identityElement)) {
    6362           0 :         Type rhsType;
    6363           0 :         if (!CheckExpr(f, rhs, &rhsType))
    6364           0 :             return false;
    6365           0 :         if (!rhsType.isIntish())
    6366           0 :             return f.failf(bitwise, "%s is not a subtype of intish", rhsType.toChars());
    6367           0 :         return true;
    6368             :     }
    6369             : 
    6370           0 :     if (IsLiteralInt(f.m(), rhs, &i) && i == uint32_t(identityElement)) {
    6371           0 :         if (bitwise->isKind(PNK_BITOR) && lhs->isKind(PNK_CALL))
    6372           0 :             return CheckCoercedCall(f, lhs, Type::Int, type);
    6373             : 
    6374           0 :         Type lhsType;
    6375           0 :         if (!CheckExpr(f, lhs, &lhsType))
    6376           0 :             return false;
    6377           0 :         if (!lhsType.isIntish())
    6378           0 :             return f.failf(bitwise, "%s is not a subtype of intish", lhsType.toChars());
    6379           0 :         return true;
    6380             :     }
    6381             : 
    6382           0 :     Type lhsType;
    6383           0 :     if (!CheckExpr(f, lhs, &lhsType))
    6384           0 :         return false;
    6385             : 
    6386           0 :     Type rhsType;
    6387           0 :     if (!CheckExpr(f, rhs, &rhsType))
    6388           0 :         return false;
    6389             : 
    6390           0 :     if (!lhsType.isIntish())
    6391           0 :         return f.failf(lhs, "%s is not a subtype of intish", lhsType.toChars());
    6392           0 :     if (!rhsType.isIntish())
    6393           0 :         return f.failf(rhs, "%s is not a subtype of intish", rhsType.toChars());
    6394             : 
    6395           0 :     switch (bitwise->getKind()) {
    6396           0 :       case PNK_BITOR:  if (!f.encoder().writeOp(Op::I32Or))   return false; break;
    6397           0 :       case PNK_BITAND: if (!f.encoder().writeOp(Op::I32And))  return false; break;
    6398           0 :       case PNK_BITXOR: if (!f.encoder().writeOp(Op::I32Xor))  return false; break;
    6399           0 :       case PNK_LSH:    if (!f.encoder().writeOp(Op::I32Shl))  return false; break;
    6400           0 :       case PNK_RSH:    if (!f.encoder().writeOp(Op::I32ShrS)) return false; break;
    6401           0 :       case PNK_URSH:   if (!f.encoder().writeOp(Op::I32ShrU)) return false; break;
    6402           0 :       default: MOZ_CRASH("not a bitwise op");
    6403             :     }
    6404             : 
    6405           0 :     return true;
    6406             : }
    6407             : 
    6408             : static bool
    6409           0 : CheckExpr(FunctionValidator& f, ParseNode* expr, Type* type)
    6410             : {
    6411           0 :     if (!CheckRecursionLimitDontReport(f.cx()))
    6412           0 :         return f.m().failOverRecursed();
    6413             : 
    6414           0 :     bool isSimd = false;
    6415           0 :     if (IsNumericLiteral(f.m(), expr, &isSimd)) {
    6416           0 :         if (isSimd)
    6417           0 :             f.setUsesSimd();
    6418           0 :         return CheckNumericLiteral(f, expr, type);
    6419             :     }
    6420             : 
    6421           0 :     switch (expr->getKind()) {
    6422           0 :       case PNK_NAME:        return CheckVarRef(f, expr, type);
    6423           0 :       case PNK_ELEM:        return CheckLoadArray(f, expr, type);
    6424           0 :       case PNK_ASSIGN:      return CheckAssign(f, expr, type);
    6425           0 :       case PNK_POS:         return CheckPos(f, expr, type);
    6426           0 :       case PNK_NOT:         return CheckNot(f, expr, type);
    6427           0 :       case PNK_NEG:         return CheckNeg(f, expr, type);
    6428           0 :       case PNK_BITNOT:      return CheckBitNot(f, expr, type);
    6429           0 :       case PNK_COMMA:       return CheckComma(f, expr, type);
    6430           0 :       case PNK_CONDITIONAL: return CheckConditional(f, expr, type);
    6431           0 :       case PNK_STAR:        return CheckMultiply(f, expr, type);
    6432           0 :       case PNK_CALL:        return CheckUncoercedCall(f, expr, type);
    6433             : 
    6434             :       case PNK_ADD:
    6435           0 :       case PNK_SUB:         return CheckAddOrSub(f, expr, type);
    6436             : 
    6437             :       case PNK_DIV:
    6438           0 :       case PNK_MOD:         return CheckDivOrMod(f, expr, type);
    6439             : 
    6440             :       case PNK_LT:
    6441             :       case PNK_LE:
    6442             :       case PNK_GT:
    6443             :       case PNK_GE:
    6444             :       case PNK_EQ:
    6445           0 :       case PNK_NE:          return CheckComparison(f, expr, type);
    6446             : 
    6447             :       case PNK_BITOR:
    6448             :       case PNK_BITAND:
    6449             :       case PNK_BITXOR:
    6450             :       case PNK_LSH:
    6451             :       case PNK_RSH:
    6452           0 :       case PNK_URSH:        return CheckBitwise(f, expr, type);
    6453             : 
    6454             :       default:;
    6455             :     }
    6456             : 
    6457           0 :     return f.fail(expr, "unsupported expression");
    6458             : }
    6459             : 
    6460             : static bool
    6461             : CheckStatement(FunctionValidator& f, ParseNode* stmt);
    6462             : 
    6463             : static bool
    6464           0 : CheckAsExprStatement(FunctionValidator& f, ParseNode* expr)
    6465             : {
    6466           0 :     if (expr->isKind(PNK_CALL)) {
    6467           0 :         Type ignored;
    6468           0 :         return CheckCoercedCall(f, expr, Type::Void, &ignored);
    6469             :     }
    6470             : 
    6471           0 :     Type resultType;
    6472           0 :     if (!CheckExpr(f, expr, &resultType))
    6473           0 :         return false;
    6474             : 
    6475           0 :     if (!resultType.isVoid()) {
    6476           0 :         if (!f.encoder().writeOp(Op::Drop))
    6477           0 :             return false;
    6478             :     }
    6479             : 
    6480           0 :     return true;
    6481             : }
    6482             : 
    6483             : static bool
    6484           0 : CheckExprStatement(FunctionValidator& f, ParseNode* exprStmt)
    6485             : {
    6486           0 :     MOZ_ASSERT(exprStmt->isKind(PNK_SEMI));
    6487           0 :     ParseNode* expr = UnaryKid(exprStmt);
    6488           0 :     if (!expr)
    6489           0 :         return true;
    6490           0 :     return CheckAsExprStatement(f, expr);
    6491             : }
    6492             : 
    6493             : static bool
    6494           0 : CheckLoopConditionOnEntry(FunctionValidator& f, ParseNode* cond)
    6495             : {
    6496             :     uint32_t maybeLit;
    6497           0 :     if (IsLiteralInt(f.m(), cond, &maybeLit) && maybeLit)
    6498           0 :         return true;
    6499             : 
    6500           0 :     Type condType;
    6501           0 :     if (!CheckExpr(f, cond, &condType))
    6502           0 :         return false;
    6503           0 :     if (!condType.isInt())
    6504           0 :         return f.failf(cond, "%s is not a subtype of int", condType.toChars());
    6505             : 
    6506             :     // TODO change this to i32.eqz
    6507             :     // i32.eq 0 $f
    6508           0 :     if (!f.writeInt32Lit(0))
    6509           0 :         return false;
    6510           0 :     if (!f.encoder().writeOp(Op::I32Eq))
    6511           0 :         return false;
    6512             : 
    6513             :     // brIf (i32.eq 0 $f) $out
    6514           0 :     if (!f.writeBreakIf())
    6515           0 :         return false;
    6516             : 
    6517           0 :     return true;
    6518             : }
    6519             : 
    6520             : static bool
    6521           0 : CheckWhile(FunctionValidator& f, ParseNode* whileStmt, const NameVector* labels = nullptr)
    6522             : {
    6523           0 :     MOZ_ASSERT(whileStmt->isKind(PNK_WHILE));
    6524           0 :     ParseNode* cond = BinaryLeft(whileStmt);
    6525           0 :     ParseNode* body = BinaryRight(whileStmt);
    6526             : 
    6527             :     // A while loop `while(#cond) #body` is equivalent to:
    6528             :     // (block $after_loop
    6529             :     //    (loop $top
    6530             :     //       (brIf $after_loop (i32.eq 0 #cond))
    6531             :     //       #body
    6532             :     //       (br $top)
    6533             :     //    )
    6534             :     // )
    6535           0 :     if (labels && !f.addLabels(*labels, 0, 1))
    6536           0 :         return false;
    6537             : 
    6538           0 :     if (!f.pushLoop())
    6539           0 :         return false;
    6540             : 
    6541           0 :     if (!CheckLoopConditionOnEntry(f, cond))
    6542           0 :         return false;
    6543           0 :     if (!CheckStatement(f, body))
    6544           0 :         return false;
    6545           0 :     if (!f.writeContinue())
    6546           0 :         return false;
    6547             : 
    6548           0 :     if (!f.popLoop())
    6549           0 :         return false;
    6550           0 :     if (labels)
    6551           0 :         f.removeLabels(*labels);
    6552           0 :     return true;
    6553             : }
    6554             : 
    6555             : static bool
    6556           0 : CheckFor(FunctionValidator& f, ParseNode* forStmt, const NameVector* labels = nullptr)
    6557             : {
    6558           0 :     MOZ_ASSERT(forStmt->isKind(PNK_FOR));
    6559           0 :     ParseNode* forHead = BinaryLeft(forStmt);
    6560           0 :     ParseNode* body = BinaryRight(forStmt);
    6561             : 
    6562           0 :     if (!forHead->isKind(PNK_FORHEAD))
    6563           0 :         return f.fail(forHead, "unsupported for-loop statement");
    6564             : 
    6565           0 :     ParseNode* maybeInit = TernaryKid1(forHead);
    6566           0 :     ParseNode* maybeCond = TernaryKid2(forHead);
    6567           0 :     ParseNode* maybeInc = TernaryKid3(forHead);
    6568             : 
    6569             :     // A for-loop `for (#init; #cond; #inc) #body` is equivalent to:
    6570             :     // (block                                               // depth X
    6571             :     //   (#init)
    6572             :     //   (block $after_loop                                 // depth X+1 (block)
    6573             :     //     (loop $loop_top                                  // depth X+2 (loop)
    6574             :     //       (brIf $after (eq 0 #cond))
    6575             :     //       (block $after_body #body)                      // depth X+3
    6576             :     //       #inc
    6577             :     //       (br $loop_top)
    6578             :     //     )
    6579             :     //   )
    6580             :     // )
    6581             :     // A break in the body should break out to $after_loop, i.e. depth + 1.
    6582             :     // A continue in the body should break out to $after_body, i.e. depth + 3.
    6583           0 :     if (labels && !f.addLabels(*labels, 1, 3))
    6584           0 :         return false;
    6585             : 
    6586           0 :     if (!f.pushUnbreakableBlock())
    6587           0 :         return false;
    6588             : 
    6589           0 :     if (maybeInit && !CheckAsExprStatement(f, maybeInit))
    6590           0 :         return false;
    6591             : 
    6592             :     {
    6593           0 :         if (!f.pushLoop())
    6594           0 :             return false;
    6595             : 
    6596           0 :         if (maybeCond && !CheckLoopConditionOnEntry(f, maybeCond))
    6597           0 :             return false;
    6598             : 
    6599             :         {
    6600             :             // Continuing in the body should just break out to the increment.
    6601           0 :             if (!f.pushContinuableBlock())
    6602           0 :                 return false;
    6603           0 :             if (!CheckStatement(f, body))
    6604           0 :                 return false;
    6605           0 :             if (!f.popContinuableBlock())
    6606           0 :                 return false;
    6607             :         }
    6608             : 
    6609           0 :         if (maybeInc && !CheckAsExprStatement(f, maybeInc))
    6610           0 :             return false;
    6611             : 
    6612           0 :         if (!f.writeContinue())
    6613           0 :             return false;
    6614           0 :         if (!f.popLoop())
    6615           0 :             return false;
    6616             :     }
    6617             : 
    6618           0 :     if (!f.popUnbreakableBlock())
    6619           0 :         return false;
    6620             : 
    6621           0 :     if (labels)
    6622           0 :         f.removeLabels(*labels);
    6623             : 
    6624           0 :     return true;
    6625             : }
    6626             : 
    6627             : static bool
    6628           0 : CheckDoWhile(FunctionValidator& f, ParseNode* whileStmt, const NameVector* labels = nullptr)
    6629             : {
    6630           0 :     MOZ_ASSERT(whileStmt->isKind(PNK_DOWHILE));
    6631           0 :     ParseNode* body = BinaryLeft(whileStmt);
    6632           0 :     ParseNode* cond = BinaryRight(whileStmt);
    6633             : 
    6634             :     // A do-while loop `do { #body } while (#cond)` is equivalent to:
    6635             :     // (block $after_loop           // depth X
    6636             :     //   (loop $top                 // depth X+1
    6637             :     //     (block #body)            // depth X+2
    6638             :     //     (brIf #cond $top)
    6639             :     //   )
    6640             :     // )
    6641             :     // A break should break out of the entire loop, i.e. at depth 0.
    6642             :     // A continue should break out to the condition, i.e. at depth 2.
    6643           0 :     if (labels && !f.addLabels(*labels, 0, 2))
    6644           0 :         return false;
    6645             : 
    6646           0 :     if (!f.pushLoop())
    6647           0 :         return false;
    6648             : 
    6649             :     {
    6650             :         // An unlabeled continue in the body should break out to the condition.
    6651           0 :         if (!f.pushContinuableBlock())
    6652           0 :             return false;
    6653           0 :         if (!CheckStatement(f, body))
    6654           0 :             return false;
    6655           0 :         if (!f.popContinuableBlock())
    6656           0 :             return false;
    6657             :     }
    6658             : 
    6659           0 :     Type condType;
    6660           0 :     if (!CheckExpr(f, cond, &condType))
    6661           0 :         return false;
    6662           0 :     if (!condType.isInt())
    6663           0 :         return f.failf(cond, "%s is not a subtype of int", condType.toChars());
    6664             : 
    6665           0 :     if (!f.writeContinueIf())
    6666           0 :         return false;
    6667             : 
    6668           0 :     if (!f.popLoop())
    6669           0 :         return false;
    6670           0 :     if (labels)
    6671           0 :         f.removeLabels(*labels);
    6672           0 :     return true;
    6673             : }
    6674             : 
    6675             : static bool CheckStatementList(FunctionValidator& f, ParseNode*, const NameVector* = nullptr);
    6676             : 
    6677             : static bool
    6678           0 : CheckLabel(FunctionValidator& f, ParseNode* labeledStmt)
    6679             : {
    6680           0 :     MOZ_ASSERT(labeledStmt->isKind(PNK_LABEL));
    6681             : 
    6682           0 :     NameVector labels;
    6683           0 :     ParseNode* innermost = labeledStmt;
    6684           0 :     do {
    6685           0 :         if (!labels.append(LabeledStatementLabel(innermost)))
    6686           0 :             return false;
    6687           0 :         innermost = LabeledStatementStatement(innermost);
    6688           0 :     } while (innermost->getKind() == PNK_LABEL);
    6689             : 
    6690           0 :     switch (innermost->getKind()) {
    6691             :       case PNK_FOR:
    6692           0 :         return CheckFor(f, innermost, &labels);
    6693             :       case PNK_DOWHILE:
    6694           0 :         return CheckDoWhile(f, innermost, &labels);
    6695             :       case PNK_WHILE:
    6696           0 :         return CheckWhile(f, innermost, &labels);
    6697             :       case PNK_STATEMENTLIST:
    6698           0 :         return CheckStatementList(f, innermost, &labels);
    6699             :       default:
    6700           0 :         break;
    6701             :     }
    6702             : 
    6703           0 :     if (!f.pushUnbreakableBlock(&labels))
    6704           0 :         return false;
    6705             : 
    6706           0 :     if (!CheckStatement(f, innermost))
    6707           0 :         return false;
    6708             : 
    6709           0 :     if (!f.popUnbreakableBlock(&labels))
    6710           0 :         return false;
    6711           0 :     return true;
    6712             : }
    6713             : 
    6714             : static bool
    6715           0 : CheckIf(FunctionValidator& f, ParseNode* ifStmt)
    6716             : {
    6717           0 :     uint32_t numIfEnd = 1;
    6718             : 
    6719             :   recurse:
    6720           0 :     MOZ_ASSERT(ifStmt->isKind(PNK_IF));
    6721           0 :     ParseNode* cond = TernaryKid1(ifStmt);
    6722           0 :     ParseNode* thenStmt = TernaryKid2(ifStmt);
    6723           0 :     ParseNode* elseStmt = TernaryKid3(ifStmt);
    6724             : 
    6725           0 :     Type condType;
    6726           0 :     if (!CheckExpr(f, cond, &condType))
    6727           0 :         return false;
    6728           0 :     if (!condType.isInt())
    6729           0 :         return f.failf(cond, "%s is not a subtype of int", condType.toChars());
    6730             : 
    6731             :     size_t typeAt;
    6732           0 :     if (!f.pushIf(&typeAt))
    6733           0 :         return false;
    6734             : 
    6735           0 :     f.setIfType(typeAt, ExprType::Void);
    6736             : 
    6737           0 :     if (!CheckStatement(f, thenStmt))
    6738           0 :         return false;
    6739             : 
    6740           0 :     if (elseStmt) {
    6741           0 :         if (!f.switchToElse())
    6742           0 :             return false;
    6743             : 
    6744           0 :         if (elseStmt->isKind(PNK_IF)) {
    6745           0 :             ifStmt = elseStmt;
    6746           0 :             if (numIfEnd++ == UINT32_MAX)
    6747           0 :                 return false;
    6748           0 :             goto recurse;
    6749             :         }
    6750             : 
    6751           0 :         if (!CheckStatement(f, elseStmt))
    6752           0 :             return false;
    6753             :     }
    6754             : 
    6755           0 :     for (uint32_t i = 0; i != numIfEnd; ++i) {
    6756           0 :         if (!f.popIf())
    6757           0 :             return false;
    6758             :     }
    6759             : 
    6760           0 :     return true;
    6761             : }
    6762             : 
    6763             : static bool
    6764           0 : CheckCaseExpr(FunctionValidator& f, ParseNode* caseExpr, int32_t* value)
    6765             : {
    6766           0 :     if (!IsNumericLiteral(f.m(), caseExpr))
    6767           0 :         return f.fail(caseExpr, "switch case expression must be an integer literal");
    6768             : 
    6769           0 :     NumLit lit = ExtractNumericLiteral(f.m(), caseExpr);
    6770           0 :     switch (lit.which()) {
    6771             :       case NumLit::Fixnum:
    6772             :       case NumLit::NegativeInt:
    6773           0 :         *value = lit.toInt32();
    6774           0 :         break;
    6775             :       case NumLit::OutOfRangeInt:
    6776             :       case NumLit::BigUnsigned:
    6777           0 :         return f.fail(caseExpr, "switch case expression out of integer range");
    6778             :       case NumLit::Double:
    6779             :       case NumLit::Float:
    6780             :       case NumLit::Int8x16:
    6781             :       case NumLit::Uint8x16:
    6782             :       case NumLit::Int16x8:
    6783             :       case NumLit::Uint16x8:
    6784             :       case NumLit::Int32x4:
    6785             :       case NumLit::Uint32x4:
    6786             :       case NumLit::Float32x4:
    6787             :       case NumLit::Bool8x16:
    6788             :       case NumLit::Bool16x8:
    6789             :       case NumLit::Bool32x4:
    6790           0 :         return f.fail(caseExpr, "switch case expression must be an integer literal");
    6791             :     }
    6792             : 
    6793           0 :     return true;
    6794             : }
    6795             : 
    6796             : static bool
    6797           0 : CheckDefaultAtEnd(FunctionValidator& f, ParseNode* stmt)
    6798             : {
    6799           0 :     for (; stmt; stmt = NextNode(stmt)) {
    6800           0 :         if (IsDefaultCase(stmt) && NextNode(stmt) != nullptr)
    6801           0 :             return f.fail(stmt, "default label must be at the end");
    6802             :     }
    6803             : 
    6804           0 :     return true;
    6805             : }
    6806             : 
    6807             : static bool
    6808           0 : CheckSwitchRange(FunctionValidator& f, ParseNode* stmt, int32_t* low, int32_t* high,
    6809             :                  uint32_t* tableLength)
    6810             : {
    6811           0 :     if (IsDefaultCase(stmt)) {
    6812           0 :         *low = 0;
    6813           0 :         *high = -1;
    6814           0 :         *tableLength = 0;
    6815           0 :         return true;
    6816             :     }
    6817             : 
    6818           0 :     int32_t i = 0;
    6819           0 :     if (!CheckCaseExpr(f, CaseExpr(stmt), &i))
    6820           0 :         return false;
    6821             : 
    6822           0 :     *low = *high = i;
    6823             : 
    6824           0 :     ParseNode* initialStmt = stmt;
    6825           0 :     for (stmt = NextNode(stmt); stmt && !IsDefaultCase(stmt); stmt = NextNode(stmt)) {
    6826           0 :         int32_t i = 0;
    6827           0 :         if (!CheckCaseExpr(f, CaseExpr(stmt), &i))
    6828           0 :             return false;
    6829             : 
    6830           0 :         *low = Min(*low, i);
    6831           0 :         *high = Max(*high, i);
    6832             :     }
    6833             : 
    6834           0 :     int64_t i64 = (int64_t(*high) - int64_t(*low)) + 1;
    6835           0 :     if (i64 > MaxBrTableElems)
    6836           0 :         return f.fail(initialStmt, "all switch statements generate tables; this table would be too big");
    6837             : 
    6838           0 :     *tableLength = uint32_t(i64);
    6839           0 :     return true;
    6840             : }
    6841             : 
    6842             : static bool
    6843           0 : CheckSwitchExpr(FunctionValidator& f, ParseNode* switchExpr)
    6844             : {
    6845           0 :     Type exprType;
    6846           0 :     if (!CheckExpr(f, switchExpr, &exprType))
    6847           0 :         return false;
    6848           0 :     if (!exprType.isSigned())
    6849           0 :         return f.failf(switchExpr, "%s is not a subtype of signed", exprType.toChars());
    6850           0 :     return true;
    6851             : }
    6852             : 
    6853             : // A switch will be constructed as:
    6854             : // - the default block wrapping all the other blocks, to be able to break
    6855             : // out of the switch with an unlabeled break statement. It has two statements
    6856             : // (an inner block and the default expr). asm.js rules require default to be at
    6857             : // the end, so the default block always encloses all the cases blocks.
    6858             : // - one block per case between low and high; undefined cases just jump to the
    6859             : // default case. Each of these blocks contain two statements: the next case's
    6860             : // block and the possibly empty statement list comprising the case body. The
    6861             : // last block pushed is the first case so the (relative) branch target therefore
    6862             : // matches the sequential order of cases.
    6863             : // - one block for the br_table, so that the first break goes to the first
    6864             : // case's block.
    6865             : static bool
    6866           0 : CheckSwitch(FunctionValidator& f, ParseNode* switchStmt)
    6867             : {
    6868           0 :     MOZ_ASSERT(switchStmt->isKind(PNK_SWITCH));
    6869             : 
    6870           0 :     ParseNode* switchExpr = BinaryLeft(switchStmt);
    6871           0 :     ParseNode* switchBody = BinaryRight(switchStmt);
    6872             : 
    6873           0 :     if (switchBody->isKind(PNK_LEXICALSCOPE)) {
    6874           0 :         if (!switchBody->isEmptyScope())
    6875           0 :             return f.fail(switchBody, "switch body may not contain lexical declarations");
    6876           0 :         switchBody = switchBody->scopeBody();
    6877             :     }
    6878             : 
    6879           0 :     ParseNode* stmt = ListHead(switchBody);
    6880           0 :     if (!stmt) {
    6881           0 :         if (!CheckSwitchExpr(f, switchExpr))
    6882           0 :             return false;
    6883           0 :         if (!f.encoder().writeOp(Op::Drop))
    6884           0 :             return false;
    6885           0 :         return true;
    6886             :     }
    6887             : 
    6888           0 :     if (!CheckDefaultAtEnd(f, stmt))
    6889           0 :         return false;
    6890             : 
    6891           0 :     int32_t low = 0, high = 0;
    6892           0 :     uint32_t tableLength = 0;
    6893           0 :     if (!CheckSwitchRange(f, stmt, &low, &high, &tableLength))
    6894           0 :         return false;
    6895             : 
    6896             :     static const uint32_t CASE_NOT_DEFINED = UINT32_MAX;
    6897             : 
    6898           0 :     Uint32Vector caseDepths;
    6899           0 :     if (!caseDepths.appendN(CASE_NOT_DEFINED, tableLength))
    6900           0 :         return false;
    6901             : 
    6902           0 :     uint32_t numCases = 0;
    6903           0 :     for (ParseNode* s = stmt; s && !IsDefaultCase(s); s = NextNode(s)) {
    6904           0 :         int32_t caseValue = ExtractNumericLiteral(f.m(), CaseExpr(s)).toInt32();
    6905             : 
    6906           0 :         MOZ_ASSERT(caseValue >= low);
    6907           0 :         unsigned i = caseValue - low;
    6908           0 :         if (caseDepths[i] != CASE_NOT_DEFINED)
    6909           0 :             return f.fail(s, "no duplicate case labels");
    6910             : 
    6911           0 :         MOZ_ASSERT(numCases != CASE_NOT_DEFINED);
    6912           0 :         caseDepths[i] = numCases++;
    6913             :     }
    6914             : 
    6915             :     // Open the wrapping breakable default block.
    6916           0 :     if (!f.pushBreakableBlock())
    6917           0 :         return false;
    6918             : 
    6919             :     // Open all the case blocks.
    6920           0 :     for (uint32_t i = 0; i < numCases; i++) {
    6921           0 :         if (!f.pushUnbreakableBlock())
    6922           0 :             return false;
    6923             :     }
    6924             : 
    6925             :     // Open the br_table block.
    6926           0 :     if (!f.pushUnbreakableBlock())
    6927           0 :         return false;
    6928             : 
    6929             :     // The default block is the last one.
    6930           0 :     uint32_t defaultDepth = numCases;
    6931             : 
    6932             :     // Subtract lowest case value, so that all the cases start from 0.
    6933           0 :     if (low) {
    6934           0 :         if (!CheckSwitchExpr(f, switchExpr))
    6935           0 :             return false;
    6936           0 :         if (!f.writeInt32Lit(low))
    6937           0 :             return false;
    6938           0 :         if (!f.encoder().writeOp(Op::I32Sub))
    6939           0 :             return false;
    6940             :     } else {
    6941           0 :         if (!CheckSwitchExpr(f, switchExpr))
    6942           0 :             return false;
    6943             :     }
    6944             : 
    6945             :     // Start the br_table block.
    6946           0 :     if (!f.encoder().writeOp(Op::BrTable))
    6947           0 :         return false;
    6948             : 
    6949             :     // Write the number of cases (tableLength - 1 + 1 (default)).
    6950             :     // Write the number of cases (tableLength - 1 + 1 (default)).
    6951           0 :     if (!f.encoder().writeVarU32(tableLength))
    6952           0 :         return false;
    6953             : 
    6954             :     // Each case value describes the relative depth to the actual block. When
    6955             :     // a case is not explicitly defined, it goes to the default.
    6956           0 :     for (size_t i = 0; i < tableLength; i++) {
    6957           0 :         uint32_t target = caseDepths[i] == CASE_NOT_DEFINED ? defaultDepth : caseDepths[i];
    6958           0 :         if (!f.encoder().writeVarU32(target))
    6959           0 :             return false;
    6960             :     }
    6961             : 
    6962             :     // Write the default depth.
    6963           0 :     if (!f.encoder().writeVarU32(defaultDepth))
    6964           0 :         return false;
    6965             : 
    6966             :     // Our br_table is done. Close its block, write the cases down in order.
    6967           0 :     if (!f.popUnbreakableBlock())
    6968           0 :         return false;
    6969             : 
    6970           0 :     for (; stmt && !IsDefaultCase(stmt); stmt = NextNode(stmt)) {
    6971           0 :         if (!CheckStatement(f, CaseBody(stmt)))
    6972           0 :             return false;
    6973           0 :         if (!f.popUnbreakableBlock())
    6974           0 :             return false;
    6975             :     }
    6976             : 
    6977             :     // Write the default block.
    6978           0 :     if (stmt && IsDefaultCase(stmt)) {
    6979           0 :         if (!CheckStatement(f, CaseBody(stmt)))
    6980           0 :             return false;
    6981             :     }
    6982             : 
    6983             :     // Close the wrapping block.
    6984           0 :     if (!f.popBreakableBlock())
    6985           0 :         return false;
    6986           0 :     return true;
    6987             : }
    6988             : 
    6989             : static bool
    6990           0 : CheckReturnType(FunctionValidator& f, ParseNode* usepn, Type ret)
    6991             : {
    6992           0 :     if (!f.hasAlreadyReturned()) {
    6993           0 :         f.setReturnedType(ret.canonicalToExprType());
    6994           0 :         return true;
    6995             :     }
    6996             : 
    6997           0 :     if (f.returnedType() != ret.canonicalToExprType()) {
    6998           0 :         return f.failf(usepn, "%s incompatible with previous return of type %s",
    6999           0 :                        Type::ret(ret).toChars(), ToCString(f.returnedType()));
    7000             :     }
    7001             : 
    7002           0 :     return true;
    7003             : }
    7004             : 
    7005             : static bool
    7006           0 : CheckReturn(FunctionValidator& f, ParseNode* returnStmt)
    7007             : {
    7008           0 :     ParseNode* expr = ReturnExpr(returnStmt);
    7009             : 
    7010           0 :     if (!expr) {
    7011           0 :         if (!CheckReturnType(f, returnStmt, Type::Void))
    7012           0 :             return false;
    7013             :     } else {
    7014           0 :         Type type;
    7015           0 :         if (!CheckExpr(f, expr, &type))
    7016           0 :             return false;
    7017             : 
    7018           0 :         if (!type.isReturnType())
    7019           0 :             return f.failf(expr, "%s is not a valid return type", type.toChars());
    7020             : 
    7021           0 :         if (!CheckReturnType(f, expr, Type::canonicalize(type)))
    7022           0 :             return false;
    7023             :     }
    7024             : 
    7025           0 :     if (!f.encoder().writeOp(Op::Return))
    7026           0 :         return false;
    7027             : 
    7028           0 :     return true;
    7029             : }
    7030             : 
    7031             : static bool
    7032           0 : CheckStatementList(FunctionValidator& f, ParseNode* stmtList, const NameVector* labels /*= nullptr */)
    7033             : {
    7034           0 :     MOZ_ASSERT(stmtList->isKind(PNK_STATEMENTLIST));
    7035             : 
    7036           0 :     if (!f.pushUnbreakableBlock(labels))
    7037           0 :         return false;
    7038             : 
    7039           0 :     for (ParseNode* stmt = ListHead(stmtList); stmt; stmt = NextNode(stmt)) {
    7040           0 :         if (!CheckStatement(f, stmt))
    7041           0 :             return false;
    7042             :     }
    7043             : 
    7044           0 :     if (!f.popUnbreakableBlock(labels))
    7045           0 :         return false;
    7046           0 :     return true;
    7047             : }
    7048             : 
    7049             : static bool
    7050           0 : CheckLexicalScope(FunctionValidator& f, ParseNode* lexicalScope)
    7051             : {
    7052           0 :     MOZ_ASSERT(lexicalScope->isKind(PNK_LEXICALSCOPE));
    7053             : 
    7054           0 :     if (!lexicalScope->isEmptyScope())
    7055           0 :         return f.fail(lexicalScope, "cannot have 'let' or 'const' declarations");
    7056             : 
    7057           0 :     return CheckStatement(f, lexicalScope->scopeBody());
    7058             : }
    7059             : 
    7060             : static bool
    7061           0 : CheckBreakOrContinue(FunctionValidator& f, bool isBreak, ParseNode* stmt)
    7062             : {
    7063           0 :     if (PropertyName* maybeLabel = LoopControlMaybeLabel(stmt))
    7064           0 :         return f.writeLabeledBreakOrContinue(maybeLabel, isBreak);
    7065           0 :     return f.writeUnlabeledBreakOrContinue(isBreak);
    7066             : }
    7067             : 
    7068             : static bool
    7069           0 : CheckStatement(FunctionValidator& f, ParseNode* stmt)
    7070             : {
    7071           0 :     if (!CheckRecursionLimitDontReport(f.cx()))
    7072           0 :         return f.m().failOverRecursed();
    7073             : 
    7074           0 :     switch (stmt->getKind()) {
    7075           0 :       case PNK_SEMI:          return CheckExprStatement(f, stmt);
    7076           0 :       case PNK_WHILE:         return CheckWhile(f, stmt);
    7077           0 :       case PNK_FOR:           return CheckFor(f, stmt);
    7078           0 :       case PNK_DOWHILE:       return CheckDoWhile(f, stmt);
    7079           0 :       case PNK_LABEL:         return CheckLabel(f, stmt);
    7080           0 :       case PNK_IF:            return CheckIf(f, stmt);
    7081           0 :       case PNK_SWITCH:        return CheckSwitch(f, stmt);
    7082           0 :       case PNK_RETURN:        return CheckReturn(f, stmt);
    7083           0 :       case PNK_STATEMENTLIST: return CheckStatementList(f, stmt);
    7084           0 :       case PNK_BREAK:         return CheckBreakOrContinue(f, true, stmt);
    7085           0 :       case PNK_CONTINUE:      return CheckBreakOrContinue(f, false, stmt);
    7086           0 :       case PNK_LEXICALSCOPE:  return CheckLexicalScope(f, stmt);
    7087             :       default:;
    7088             :     }
    7089             : 
    7090           0 :     return f.fail(stmt, "unexpected statement kind");
    7091             : }
    7092             : 
    7093             : static bool
    7094           0 : ParseFunction(ModuleValidator& m, ParseNode** fnOut, unsigned* line)
    7095             : {
    7096           0 :     TokenStream& tokenStream = m.tokenStream();
    7097             : 
    7098           0 :     tokenStream.consumeKnownToken(TOK_FUNCTION, TokenStream::Operand);
    7099           0 :     uint32_t toStringStart = tokenStream.currentToken().pos.begin;
    7100           0 :     *line = tokenStream.srcCoords.lineNum(tokenStream.currentToken().pos.end);
    7101             : 
    7102             :     TokenKind tk;
    7103           0 :     if (!tokenStream.getToken(&tk, TokenStream::Operand))
    7104           0 :         return false;
    7105           0 :     if (!TokenKindIsPossibleIdentifier(tk))
    7106           0 :         return false;  // The regular parser will throw a SyntaxError, no need to m.fail.
    7107             : 
    7108           0 :     RootedPropertyName name(m.cx(), m.parser().bindingIdentifier(YieldIsName));
    7109           0 :     if (!name)
    7110           0 :         return false;
    7111             : 
    7112           0 :     ParseNode* fn = m.parser().handler.newFunctionStatement(m.parser().pos());
    7113           0 :     if (!fn)
    7114           0 :         return false;
    7115             : 
    7116           0 :     RootedFunction& fun = m.dummyFunction();
    7117           0 :     fun->setAtom(name);
    7118           0 :     fun->setArgCount(0);
    7119             : 
    7120           0 :     ParseContext* outerpc = m.parser().pc;
    7121           0 :     Directives directives(outerpc);
    7122           0 :     FunctionBox* funbox = m.parser().newFunctionBox(fn, fun, toStringStart, directives,
    7123           0 :                                                     NotGenerator, SyncFunction);
    7124           0 :     if (!funbox)
    7125           0 :         return false;
    7126           0 :     funbox->initWithEnclosingParseContext(outerpc, frontend::Statement);
    7127             : 
    7128           0 :     Directives newDirectives = directives;
    7129           0 :     ParseContext funpc(&m.parser(), funbox, &newDirectives);
    7130           0 :     if (!funpc.init())
    7131           0 :         return false;
    7132             : 
    7133           0 :     if (!m.parser().functionFormalParametersAndBody(InAllowed, YieldIsName, fn, Statement)) {
    7134           0 :         if (tokenStream.hadError() || directives == newDirectives)
    7135           0 :             return false;
    7136             : 
    7137           0 :         return m.fail(fn, "encountered new directive in function");
    7138             :     }
    7139             : 
    7140           0 :     MOZ_ASSERT(!tokenStream.hadError());
    7141           0 :     MOZ_ASSERT(directives == newDirectives);
    7142             : 
    7143           0 :     *fnOut = fn;
    7144           0 :     return true;
    7145             : }
    7146             : 
    7147             : static bool
    7148           0 : CheckFunction(ModuleValidator& m)
    7149             : {
    7150             :     // asm.js modules can be quite large when represented as parse trees so pop
    7151             :     // the backing LifoAlloc after parsing/compiling each function.
    7152           0 :     AsmJSParser::Mark mark = m.parser().mark();
    7153             : 
    7154           0 :     ParseNode* fn = nullptr;
    7155           0 :     unsigned line = 0;
    7156           0 :     if (!ParseFunction(m, &fn, &line))
    7157           0 :         return false;
    7158             : 
    7159           0 :     if (!CheckFunctionHead(m, fn))
    7160           0 :         return false;
    7161             : 
    7162           0 :     FunctionValidator f(m, fn);
    7163           0 :     if (!f.init(FunctionName(fn), line))
    7164           0 :         return m.fail(fn, "internal compiler failure (probably out of memory)");
    7165             : 
    7166           0 :     ParseNode* stmtIter = ListHead(FunctionStatementList(fn));
    7167             : 
    7168           0 :     if (!CheckProcessingDirectives(m, &stmtIter))
    7169           0 :         return false;
    7170             : 
    7171           0 :     ValTypeVector args;
    7172           0 :     if (!CheckArguments(f, &stmtIter, &args))
    7173           0 :         return false;
    7174             : 
    7175           0 :     if (!CheckVariables(f, &stmtIter))
    7176           0 :         return false;
    7177             : 
    7178           0 :     ParseNode* lastNonEmptyStmt = nullptr;
    7179           0 :     for (; stmtIter; stmtIter = NextNonEmptyStatement(stmtIter)) {
    7180           0 :         lastNonEmptyStmt = stmtIter;
    7181           0 :         if (!CheckStatement(f, stmtIter))
    7182           0 :             return false;
    7183             :     }
    7184             : 
    7185           0 :     if (!CheckFinalReturn(f, lastNonEmptyStmt))
    7186           0 :         return false;
    7187             : 
    7188           0 :     ModuleValidator::Func* func = nullptr;
    7189           0 :     if (!CheckFunctionSignature(m, fn, Sig(Move(args), f.returnedType()), FunctionName(fn), &func))
    7190           0 :         return false;
    7191             : 
    7192           0 :     if (func->defined())
    7193           0 :         return m.failName(fn, "function '%s' already defined", FunctionName(fn));
    7194             : 
    7195           0 :     func->define(fn);
    7196             : 
    7197           0 :     if (!f.finish(func->index()))
    7198           0 :         return m.fail(fn, "internal compiler failure (probably out of memory)");
    7199             : 
    7200             :     // Release the parser's lifo memory only after the last use of a parse node.
    7201           0 :     m.parser().release(mark);
    7202           0 :     return true;
    7203             : }
    7204             : 
    7205             : static bool
    7206           0 : CheckAllFunctionsDefined(ModuleValidator& m)
    7207             : {
    7208           0 :     for (unsigned i = 0; i < m.numFunctions(); i++) {
    7209           0 :         ModuleValidator::Func& f = m.function(i);
    7210           0 :         if (!f.defined())
    7211           0 :             return m.failNameOffset(f.firstUse(), "missing definition of function %s", f.name());
    7212             :     }
    7213             : 
    7214           0 :     return true;
    7215             : }
    7216             : 
    7217             : static bool
    7218           0 : CheckFunctions(ModuleValidator& m)
    7219             : {
    7220             :     while (true) {
    7221             :         TokenKind tk;
    7222           0 :         if (!PeekToken(m.parser(), &tk))
    7223           0 :             return false;
    7224             : 
    7225           0 :         if (tk != TOK_FUNCTION)
    7226           0 :             break;
    7227             : 
    7228           0 :         if (!CheckFunction(m))
    7229           0 :             return false;
    7230           0 :     }
    7231             : 
    7232           0 :     return CheckAllFunctionsDefined(m);
    7233             : }
    7234             : 
    7235             : static bool
    7236           0 : CheckFuncPtrTable(ModuleValidator& m, ParseNode* var)
    7237             : {
    7238           0 :     if (!var->isKind(PNK_NAME))
    7239           0 :         return m.fail(var, "function-pointer table name is not a plain name");
    7240             : 
    7241           0 :     ParseNode* arrayLiteral = MaybeInitializer(var);
    7242           0 :     if (!arrayLiteral || !arrayLiteral->isKind(PNK_ARRAY))
    7243           0 :         return m.fail(var, "function-pointer table's initializer must be an array literal");
    7244             : 
    7245           0 :     unsigned length = ListLength(arrayLiteral);
    7246             : 
    7247           0 :     if (!IsPowerOfTwo(length))
    7248           0 :         return m.failf(arrayLiteral, "function-pointer table length must be a power of 2 (is %u)", length);
    7249             : 
    7250           0 :     unsigned mask = length - 1;
    7251             : 
    7252           0 :     Uint32Vector elemFuncIndices;
    7253           0 :     const Sig* sig = nullptr;
    7254           0 :     for (ParseNode* elem = ListHead(arrayLiteral); elem; elem = NextNode(elem)) {
    7255           0 :         if (!elem->isKind(PNK_NAME))
    7256           0 :             return m.fail(elem, "function-pointer table's elements must be names of functions");
    7257             : 
    7258           0 :         PropertyName* funcName = elem->name();
    7259           0 :         const ModuleValidator::Func* func = m.lookupFunction(funcName);
    7260           0 :         if (!func)
    7261           0 :             return m.fail(elem, "function-pointer table's elements must be names of functions");
    7262             : 
    7263           0 :         const Sig& funcSig = m.mg().funcSig(func->index());
    7264           0 :         if (sig) {
    7265           0 :             if (*sig != funcSig)
    7266           0 :                 return m.fail(elem, "all functions in table must have same signature");
    7267             :         } else {
    7268           0 :             sig = &funcSig;
    7269             :         }
    7270             : 
    7271           0 :         if (!elemFuncIndices.append(func->index()))
    7272           0 :             return false;
    7273             :     }
    7274             : 
    7275           0 :     Sig copy;
    7276           0 :     if (!copy.clone(*sig))
    7277           0 :         return false;
    7278             : 
    7279             :     uint32_t tableIndex;
    7280           0 :     if (!CheckFuncPtrTableAgainstExisting(m, var, var->name(), Move(copy), mask, &tableIndex))
    7281           0 :         return false;
    7282             : 
    7283           0 :     if (!m.defineFuncPtrTable(tableIndex, Move(elemFuncIndices)))
    7284           0 :         return m.fail(var, "duplicate function-pointer definition");
    7285             : 
    7286           0 :     return true;
    7287             : }
    7288             : 
    7289             : static bool
    7290           0 : CheckFuncPtrTables(ModuleValidator& m)
    7291             : {
    7292             :     while (true) {
    7293             :         ParseNode* varStmt;
    7294           0 :         if (!ParseVarOrConstStatement(m.parser(), &varStmt))
    7295           0 :             return false;
    7296           0 :         if (!varStmt)
    7297           0 :             break;
    7298           0 :         for (ParseNode* var = VarListHead(varStmt); var; var = NextNode(var)) {
    7299           0 :             if (!CheckFuncPtrTable(m, var))
    7300           0 :                 return false;
    7301             :         }
    7302           0 :     }
    7303             : 
    7304           0 :     for (unsigned i = 0; i < m.numFuncPtrTables(); i++) {
    7305           0 :         ModuleValidator::FuncPtrTable& funcPtrTable = m.funcPtrTable(i);
    7306           0 :         if (!funcPtrTable.defined()) {
    7307           0 :             return m.failNameOffset(funcPtrTable.firstUse(),
    7308             :                                     "function-pointer table %s wasn't defined",
    7309           0 :                                     funcPtrTable.name());
    7310             :         }
    7311             :     }
    7312             : 
    7313           0 :     return true;
    7314             : }
    7315             : 
    7316             : static bool
    7317           0 : CheckModuleExportFunction(ModuleValidator& m, ParseNode* pn, PropertyName* maybeFieldName = nullptr)
    7318             : {
    7319           0 :     if (!pn->isKind(PNK_NAME))
    7320           0 :         return m.fail(pn, "expected name of exported function");
    7321             : 
    7322           0 :     PropertyName* funcName = pn->name();
    7323           0 :     const ModuleValidator::Func* func = m.lookupFunction(funcName);
    7324           0 :     if (!func)
    7325           0 :         return m.failName(pn, "function '%s' not found", funcName);
    7326             : 
    7327           0 :     return m.addExportField(pn, *func, maybeFieldName);
    7328             : }
    7329             : 
    7330             : static bool
    7331           0 : CheckModuleExportObject(ModuleValidator& m, ParseNode* object)
    7332             : {
    7333           0 :     MOZ_ASSERT(object->isKind(PNK_OBJECT));
    7334             : 
    7335           0 :     for (ParseNode* pn = ListHead(object); pn; pn = NextNode(pn)) {
    7336           0 :         if (!IsNormalObjectField(m.cx(), pn))
    7337           0 :             return m.fail(pn, "only normal object properties may be used in the export object literal");
    7338             : 
    7339           0 :         PropertyName* fieldName = ObjectNormalFieldName(m.cx(), pn);
    7340             : 
    7341           0 :         ParseNode* initNode = ObjectNormalFieldInitializer(m.cx(), pn);
    7342           0 :         if (!initNode->isKind(PNK_NAME))
    7343           0 :             return m.fail(initNode, "initializer of exported object literal must be name of function");
    7344             : 
    7345           0 :         if (!CheckModuleExportFunction(m, initNode, fieldName))
    7346           0 :             return false;
    7347             :     }
    7348             : 
    7349           0 :     return true;
    7350             : }
    7351             : 
    7352             : static bool
    7353           0 : CheckModuleReturn(ModuleValidator& m)
    7354             : {
    7355             :     TokenKind tk;
    7356           0 :     if (!GetToken(m.parser(), &tk))
    7357           0 :         return false;
    7358           0 :     TokenStream& ts = m.parser().tokenStream;
    7359           0 :     if (tk != TOK_RETURN) {
    7360           0 :         return m.failCurrentOffset((tk == TOK_RC || tk == TOK_EOF)
    7361             :                                    ? "expecting return statement"
    7362           0 :                                    : "invalid asm.js. statement");
    7363             :     }
    7364           0 :     ts.ungetToken();
    7365             : 
    7366           0 :     ParseNode* returnStmt = m.parser().statementListItem(YieldIsName);
    7367           0 :     if (!returnStmt)
    7368           0 :         return false;
    7369             : 
    7370           0 :     ParseNode* returnExpr = ReturnExpr(returnStmt);
    7371           0 :     if (!returnExpr)
    7372           0 :         return m.fail(returnStmt, "export statement must return something");
    7373             : 
    7374           0 :     if (returnExpr->isKind(PNK_OBJECT)) {
    7375           0 :         if (!CheckModuleExportObject(m, returnExpr))
    7376           0 :             return false;
    7377             :     } else {
    7378           0 :         if (!CheckModuleExportFunction(m, returnExpr))
    7379           0 :             return false;
    7380             :     }
    7381             : 
    7382           0 :     return true;
    7383             : }
    7384             : 
    7385             : static bool
    7386           0 : CheckModuleEnd(ModuleValidator &m)
    7387             : {
    7388             :     TokenKind tk;
    7389           0 :     if (!GetToken(m.parser(), &tk))
    7390           0 :         return false;
    7391             : 
    7392           0 :     if (tk != TOK_EOF && tk != TOK_RC)
    7393           0 :         return m.failCurrentOffset("top-level export (return) must be the last statement");
    7394             : 
    7395           0 :     m.parser().tokenStream.ungetToken();
    7396           0 :     return true;
    7397             : }
    7398             : 
    7399             : static SharedModule
    7400           0 : CheckModule(JSContext* cx, AsmJSParser& parser, ParseNode* stmtList, unsigned* time)
    7401             : {
    7402           0 :     int64_t before = PRMJ_Now();
    7403             : 
    7404           0 :     ParseNode* moduleFunctionNode = parser.pc->functionBox()->functionNode;
    7405           0 :     MOZ_ASSERT(moduleFunctionNode);
    7406             : 
    7407           0 :     ModuleValidator m(cx, parser, moduleFunctionNode);
    7408           0 :     if (!m.init())
    7409           0 :         return nullptr;
    7410             : 
    7411           0 :     if (!CheckFunctionHead(m, moduleFunctionNode))
    7412           0 :         return nullptr;
    7413             : 
    7414           0 :     if (!CheckModuleArguments(m, moduleFunctionNode))
    7415           0 :         return nullptr;
    7416             : 
    7417           0 :     if (!CheckPrecedingStatements(m, stmtList))
    7418           0 :         return nullptr;
    7419             : 
    7420           0 :     if (!CheckModuleProcessingDirectives(m))
    7421           0 :         return nullptr;
    7422             : 
    7423           0 :     if (!CheckModuleGlobals(m))
    7424           0 :         return nullptr;
    7425             : 
    7426           0 :     if (!m.startFunctionBodies())
    7427           0 :         return nullptr;
    7428             : 
    7429           0 :     if (!CheckFunctions(m))
    7430           0 :         return nullptr;
    7431             : 
    7432           0 :     if (!m.finishFunctionBodies())
    7433           0 :         return nullptr;
    7434             : 
    7435           0 :     if (!CheckFuncPtrTables(m))
    7436           0 :         return nullptr;
    7437             : 
    7438           0 :     if (!CheckModuleReturn(m))
    7439           0 :         return nullptr;
    7440             : 
    7441           0 :     if (!CheckModuleEnd(m))
    7442           0 :         return nullptr;
    7443             : 
    7444           0 :     SharedModule module = m.finish();
    7445           0 :     if (!module)
    7446           0 :         return nullptr;
    7447             : 
    7448           0 :     *time = (PRMJ_Now() - before) / PRMJ_USEC_PER_MSEC;
    7449           0 :     return module;
    7450             : }
    7451             : 
    7452             : /*****************************************************************************/
    7453             : // Link-time validation
    7454             : 
    7455             : static bool
    7456           0 : LinkFail(JSContext* cx, const char* str)
    7457             : {
    7458             :     JS_ReportErrorFlagsAndNumberASCII(cx, JSREPORT_WARNING, GetErrorMessage, nullptr,
    7459           0 :                                       JSMSG_USE_ASM_LINK_FAIL, str);
    7460           0 :     return false;
    7461             : }
    7462             : 
    7463             : static bool
    7464           0 : IsMaybeWrappedScriptedProxy(JSObject* obj)
    7465             : {
    7466           0 :     JSObject* unwrapped = UncheckedUnwrap(obj);
    7467           0 :     return unwrapped && IsScriptedProxy(unwrapped);
    7468             : }
    7469             : 
    7470             : static bool
    7471           0 : GetDataProperty(JSContext* cx, HandleValue objVal, HandleAtom field, MutableHandleValue v)
    7472             : {
    7473           0 :     if (!objVal.isObject())
    7474           0 :         return LinkFail(cx, "accessing property of non-object");
    7475             : 
    7476           0 :     RootedObject obj(cx, &objVal.toObject());
    7477           0 :     if (IsMaybeWrappedScriptedProxy(obj))
    7478           0 :         return LinkFail(cx, "accessing property of a Proxy");
    7479             : 
    7480           0 :     Rooted<PropertyDescriptor> desc(cx);
    7481           0 :     RootedId id(cx, AtomToId(field));
    7482           0 :     if (!GetPropertyDescriptor(cx, obj, id, &desc))
    7483           0 :         return false;
    7484             : 
    7485           0 :     if (!desc.object())
    7486           0 :         return LinkFail(cx, "property not present on object");
    7487             : 
    7488           0 :     if (!desc.isDataDescriptor())
    7489           0 :         return LinkFail(cx, "property is not a data property");
    7490             : 
    7491           0 :     v.set(desc.value());
    7492           0 :     return true;
    7493             : }
    7494             : 
    7495             : static bool
    7496           0 : GetDataProperty(JSContext* cx, HandleValue objVal, const char* fieldChars, MutableHandleValue v)
    7497             : {
    7498           0 :     RootedAtom field(cx, AtomizeUTF8Chars(cx, fieldChars, strlen(fieldChars)));
    7499           0 :     if (!field)
    7500           0 :         return false;
    7501             : 
    7502           0 :     return GetDataProperty(cx, objVal, field, v);
    7503             : }
    7504             : 
    7505             : static bool
    7506           0 : GetDataProperty(JSContext* cx, HandleValue objVal, ImmutablePropertyNamePtr field, MutableHandleValue v)
    7507             : {
    7508             :     // Help the conversion along for all the cx->names().* users.
    7509           0 :     HandlePropertyName fieldHandle = field;
    7510           0 :     return GetDataProperty(cx, objVal, fieldHandle, v);
    7511             : }
    7512             : 
    7513             : static bool
    7514           0 : HasObjectValueOfMethodPure(JSObject* obj, JSContext* cx)
    7515             : {
    7516           0 :     Value v;
    7517           0 :     if (!GetPropertyPure(cx, obj, NameToId(cx->names().valueOf), &v))
    7518           0 :         return false;
    7519             : 
    7520             :     JSFunction* fun;
    7521           0 :     if (!IsFunctionObject(v, &fun))
    7522           0 :         return false;
    7523             : 
    7524           0 :     return IsSelfHostedFunctionWithName(fun, cx->names().Object_valueOf);
    7525             : }
    7526             : 
    7527             : static bool
    7528           0 : HasPureCoercion(JSContext* cx, HandleValue v)
    7529             : {
    7530             :     // Unsigned SIMD types are not allowed in function signatures.
    7531           0 :     if (IsVectorObject<Int32x4>(v) || IsVectorObject<Int16x8>(v) ||  IsVectorObject<Int8x16>(v) ||
    7532           0 :         IsVectorObject<Bool32x4>(v) || IsVectorObject<Bool16x8>(v) ||
    7533           0 :         IsVectorObject<Bool8x16>(v) || IsVectorObject<Float32x4>(v)) {
    7534           0 :         return true;
    7535             :     }
    7536             : 
    7537             :     // Ideally, we'd reject all non-SIMD non-primitives, but Emscripten has a
    7538             :     // bug that generates code that passes functions for some imports. To avoid
    7539             :     // breaking all the code that contains this bug, we make an exception for
    7540             :     // functions that don't have user-defined valueOf or toString, for their
    7541             :     // coercions are not observable and coercion via ToNumber/ToInt32
    7542             :     // definitely produces NaN/0. We should remove this special case later once
    7543             :     // most apps have been built with newer Emscripten.
    7544           0 :     if (v.toObject().is<JSFunction>() &&
    7545           0 :         HasNoToPrimitiveMethodPure(&v.toObject(), cx) &&
    7546           0 :         HasObjectValueOfMethodPure(&v.toObject(), cx) &&
    7547           0 :         HasNativeMethodPure(&v.toObject(), cx->names().toString, fun_toString, cx))
    7548             :     {
    7549           0 :         return true;
    7550             :     }
    7551             : 
    7552           0 :     return false;
    7553             : }
    7554             : 
    7555             : static bool
    7556           0 : ValidateGlobalVariable(JSContext* cx, const AsmJSGlobal& global, HandleValue importVal, Val* val)
    7557             : {
    7558           0 :     switch (global.varInitKind()) {
    7559             :       case AsmJSGlobal::InitConstant:
    7560           0 :         *val = global.varInitVal();
    7561           0 :         return true;
    7562             : 
    7563             :       case AsmJSGlobal::InitImport: {
    7564           0 :         RootedValue v(cx);
    7565           0 :         if (!GetDataProperty(cx, importVal, global.field(), &v))
    7566           0 :             return false;
    7567             : 
    7568           0 :         if (!v.isPrimitive() && !HasPureCoercion(cx, v))
    7569           0 :             return LinkFail(cx, "Imported values must be primitives");
    7570             : 
    7571           0 :         switch (global.varInitImportType()) {
    7572             :           case ValType::I32: {
    7573             :             int32_t i32;
    7574           0 :             if (!ToInt32(cx, v, &i32))
    7575           0 :                 return false;
    7576           0 :             *val = Val(uint32_t(i32));
    7577           0 :             return true;
    7578             :           }
    7579             :           case ValType::I64:
    7580           0 :             MOZ_CRASH("int64");
    7581             :           case ValType::F32: {
    7582             :             float f;
    7583           0 :             if (!RoundFloat32(cx, v, &f))
    7584           0 :                 return false;
    7585           0 :             *val = Val(f);
    7586           0 :             return true;
    7587             :           }
    7588             :           case ValType::F64: {
    7589             :             double d;
    7590           0 :             if (!ToNumber(cx, v, &d))
    7591           0 :                 return false;
    7592           0 :             *val = Val(d);
    7593           0 :             return true;
    7594             :           }
    7595             :           case ValType::I8x16: {
    7596             :             SimdConstant simdConstant;
    7597           0 :             if (!ToSimdConstant<Int8x16>(cx, v, &simdConstant))
    7598           0 :                 return false;
    7599           0 :             *val = Val(simdConstant.asInt8x16());
    7600           0 :             return true;
    7601             :           }
    7602             :           case ValType::I16x8: {
    7603             :             SimdConstant simdConstant;
    7604           0 :             if (!ToSimdConstant<Int16x8>(cx, v, &simdConstant))
    7605           0 :                 return false;
    7606           0 :             *val = Val(simdConstant.asInt16x8());
    7607           0 :             return true;
    7608             :           }
    7609             :           case ValType::I32x4: {
    7610             :             SimdConstant simdConstant;
    7611           0 :             if (!ToSimdConstant<Int32x4>(cx, v, &simdConstant))
    7612           0 :                 return false;
    7613           0 :             *val = Val(simdConstant.asInt32x4());
    7614           0 :             return true;
    7615             :           }
    7616             :           case ValType::F32x4: {
    7617             :             SimdConstant simdConstant;
    7618           0 :             if (!ToSimdConstant<Float32x4>(cx, v, &simdConstant))
    7619           0 :                 return false;
    7620           0 :             *val = Val(simdConstant.asFloat32x4());
    7621           0 :             return true;
    7622             :           }
    7623             :           case ValType::B8x16: {
    7624             :             SimdConstant simdConstant;
    7625           0 :             if (!ToSimdConstant<Bool8x16>(cx, v, &simdConstant))
    7626           0 :                 return false;
    7627             :             // Bool8x16 uses the same data layout as Int8x16.
    7628           0 :             *val = Val(simdConstant.asInt8x16());
    7629           0 :             return true;
    7630             :           }
    7631             :           case ValType::B16x8: {
    7632             :             SimdConstant simdConstant;
    7633           0 :             if (!ToSimdConstant<Bool16x8>(cx, v, &simdConstant))
    7634           0 :                 return false;
    7635             :             // Bool16x8 uses the same data layout as Int16x8.
    7636           0 :             *val = Val(simdConstant.asInt16x8());
    7637           0 :             return true;
    7638             :           }
    7639             :           case ValType::B32x4: {
    7640             :             SimdConstant simdConstant;
    7641           0 :             if (!ToSimdConstant<Bool32x4>(cx, v, &simdConstant))
    7642           0 :                 return false;
    7643             :             // Bool32x4 uses the same data layout as Int32x4.
    7644           0 :             *val = Val(simdConstant.asInt32x4());
    7645           0 :             return true;
    7646             :           }
    7647             :         }
    7648             :       }
    7649             :     }
    7650             : 
    7651           0 :     MOZ_CRASH("unreachable");
    7652             : }
    7653             : 
    7654             : static bool
    7655           0 : ValidateFFI(JSContext* cx, const AsmJSGlobal& global, HandleValue importVal,
    7656             :             MutableHandle<FunctionVector> ffis)
    7657             : {
    7658           0 :     RootedValue v(cx);
    7659           0 :     if (!GetDataProperty(cx, importVal, global.field(), &v))
    7660           0 :         return false;
    7661             : 
    7662           0 :     if (!IsFunctionObject(v))
    7663           0 :         return LinkFail(cx, "FFI imports must be functions");
    7664             : 
    7665           0 :     ffis[global.ffiIndex()].set(&v.toObject().as<JSFunction>());
    7666           0 :     return true;
    7667             : }
    7668             : 
    7669             : static bool
    7670           0 : ValidateArrayView(JSContext* cx, const AsmJSGlobal& global, HandleValue globalVal)
    7671             : {
    7672           0 :     if (!global.field())
    7673           0 :         return true;
    7674             : 
    7675           0 :     RootedValue v(cx);
    7676           0 :     if (!GetDataProperty(cx, globalVal, global.field(), &v))
    7677           0 :         return false;
    7678             : 
    7679           0 :     bool tac = IsTypedArrayConstructor(v, global.viewType());
    7680           0 :     if (!tac)
    7681           0 :         return LinkFail(cx, "bad typed array constructor");
    7682             : 
    7683           0 :     return true;
    7684             : }
    7685             : 
    7686             : static bool
    7687           0 : ValidateMathBuiltinFunction(JSContext* cx, const AsmJSGlobal& global, HandleValue globalVal)
    7688             : {
    7689           0 :     RootedValue v(cx);
    7690           0 :     if (!GetDataProperty(cx, globalVal, cx->names().Math, &v))
    7691           0 :         return false;
    7692             : 
    7693           0 :     if (!GetDataProperty(cx, v, global.field(), &v))
    7694           0 :         return false;
    7695             : 
    7696           0 :     Native native = nullptr;
    7697           0 :     switch (global.mathBuiltinFunction()) {
    7698           0 :       case AsmJSMathBuiltin_sin: native = math_sin; break;
    7699           0 :       case AsmJSMathBuiltin_cos: native = math_cos; break;
    7700           0 :       case AsmJSMathBuiltin_tan: native = math_tan; break;
    7701           0 :       case AsmJSMathBuiltin_asin: native = math_asin; break;
    7702           0 :       case AsmJSMathBuiltin_acos: native = math_acos; break;
    7703           0 :       case AsmJSMathBuiltin_atan: native = math_atan; break;
    7704           0 :       case AsmJSMathBuiltin_ceil: native = math_ceil; break;
    7705           0 :       case AsmJSMathBuiltin_floor: native = math_floor; break;
    7706           0 :       case AsmJSMathBuiltin_exp: native = math_exp; break;
    7707           0 :       case AsmJSMathBuiltin_log: native = math_log; break;
    7708           0 :       case AsmJSMathBuiltin_pow: native = math_pow; break;
    7709           0 :       case AsmJSMathBuiltin_sqrt: native = math_sqrt; break;
    7710           0 :       case AsmJSMathBuiltin_min: native = math_min; break;
    7711           0 :       case AsmJSMathBuiltin_max: native = math_max; break;
    7712           0 :       case AsmJSMathBuiltin_abs: native = math_abs; break;
    7713           0 :       case AsmJSMathBuiltin_atan2: native = math_atan2; break;
    7714           0 :       case AsmJSMathBuiltin_imul: native = math_imul; break;
    7715           0 :       case AsmJSMathBuiltin_clz32: native = math_clz32; break;
    7716           0 :       case AsmJSMathBuiltin_fround: native = math_fround; break;
    7717             :     }
    7718             : 
    7719           0 :     if (!IsNativeFunction(v, native))
    7720           0 :         return LinkFail(cx, "bad Math.* builtin function");
    7721             : 
    7722           0 :     return true;
    7723             : }
    7724             : 
    7725             : static bool
    7726           0 : ValidateSimdType(JSContext* cx, const AsmJSGlobal& global, HandleValue globalVal,
    7727             :                  MutableHandleValue out)
    7728             : {
    7729           0 :     RootedValue v(cx);
    7730           0 :     if (!GetDataProperty(cx, globalVal, cx->names().SIMD, &v))
    7731           0 :         return false;
    7732             : 
    7733             :     SimdType type;
    7734           0 :     if (global.which() == AsmJSGlobal::SimdCtor)
    7735           0 :         type = global.simdCtorType();
    7736             :     else
    7737           0 :         type = global.simdOperationType();
    7738             : 
    7739           0 :     RootedPropertyName simdTypeName(cx, SimdTypeToName(cx->names(), type));
    7740           0 :     if (!GetDataProperty(cx, v, simdTypeName, &v))
    7741           0 :         return false;
    7742             : 
    7743           0 :     if (!v.isObject())
    7744           0 :         return LinkFail(cx, "bad SIMD type");
    7745             : 
    7746           0 :     RootedObject simdDesc(cx, &v.toObject());
    7747           0 :     if (!simdDesc->is<SimdTypeDescr>())
    7748           0 :         return LinkFail(cx, "bad SIMD type");
    7749             : 
    7750           0 :     if (type != simdDesc->as<SimdTypeDescr>().type())
    7751           0 :         return LinkFail(cx, "bad SIMD type");
    7752             : 
    7753           0 :     out.set(v);
    7754           0 :     return true;
    7755             : }
    7756             : 
    7757             : static bool
    7758           0 : ValidateSimdType(JSContext* cx, const AsmJSGlobal& global, HandleValue globalVal)
    7759             : {
    7760           0 :     RootedValue _(cx);
    7761           0 :     return ValidateSimdType(cx, global, globalVal, &_);
    7762             : }
    7763             : 
    7764             : static bool
    7765           0 : ValidateSimdOperation(JSContext* cx, const AsmJSGlobal& global, HandleValue globalVal)
    7766             : {
    7767           0 :     RootedValue v(cx);
    7768           0 :     JS_ALWAYS_TRUE(ValidateSimdType(cx, global, globalVal, &v));
    7769             : 
    7770           0 :     if (!GetDataProperty(cx, v, global.field(), &v))
    7771           0 :         return false;
    7772             : 
    7773           0 :     Native native = nullptr;
    7774           0 :     switch (global.simdOperationType()) {
    7775             : #define SET_NATIVE_INT8X16(op) case SimdOperation::Fn_##op: native = simd_int8x16_##op; break;
    7776             : #define SET_NATIVE_INT16X8(op) case SimdOperation::Fn_##op: native = simd_int16x8_##op; break;
    7777             : #define SET_NATIVE_INT32X4(op) case SimdOperation::Fn_##op: native = simd_int32x4_##op; break;
    7778             : #define SET_NATIVE_UINT8X16(op) case SimdOperation::Fn_##op: native = simd_uint8x16_##op; break;
    7779             : #define SET_NATIVE_UINT16X8(op) case SimdOperation::Fn_##op: native = simd_uint16x8_##op; break;
    7780             : #define SET_NATIVE_UINT32X4(op) case SimdOperation::Fn_##op: native = simd_uint32x4_##op; break;
    7781             : #define SET_NATIVE_FLOAT32X4(op) case SimdOperation::Fn_##op: native = simd_float32x4_##op; break;
    7782             : #define SET_NATIVE_BOOL8X16(op) case SimdOperation::Fn_##op: native = simd_bool8x16_##op; break;
    7783             : #define SET_NATIVE_BOOL16X8(op) case SimdOperation::Fn_##op: native = simd_bool16x8_##op; break;
    7784             : #define SET_NATIVE_BOOL32X4(op) case SimdOperation::Fn_##op: native = simd_bool32x4_##op; break;
    7785             : #define FALLTHROUGH(op) case SimdOperation::Fn_##op:
    7786             :       case SimdType::Int8x16:
    7787           0 :         switch (global.simdOperation()) {
    7788           0 :           FORALL_INT8X16_ASMJS_OP(SET_NATIVE_INT8X16)
    7789           0 :           SET_NATIVE_INT8X16(fromUint8x16Bits)
    7790           0 :           SET_NATIVE_INT8X16(fromUint16x8Bits)
    7791           0 :           SET_NATIVE_INT8X16(fromUint32x4Bits)
    7792           0 :           default: MOZ_CRASH("shouldn't have been validated in the first place");
    7793             :         }
    7794           0 :         break;
    7795             :       case SimdType::Int16x8:
    7796           0 :         switch (global.simdOperation()) {
    7797           0 :           FORALL_INT16X8_ASMJS_OP(SET_NATIVE_INT16X8)
    7798           0 :           SET_NATIVE_INT16X8(fromUint8x16Bits)
    7799           0 :           SET_NATIVE_INT16X8(fromUint16x8Bits)
    7800           0 :           SET_NATIVE_INT16X8(fromUint32x4Bits)
    7801           0 :           default: MOZ_CRASH("shouldn't have been validated in the first place");
    7802             :         }
    7803           0 :         break;
    7804             :       case SimdType::Int32x4:
    7805           0 :         switch (global.simdOperation()) {
    7806           0 :           FORALL_INT32X4_ASMJS_OP(SET_NATIVE_INT32X4)
    7807           0 :           SET_NATIVE_INT32X4(fromUint8x16Bits)
    7808           0 :           SET_NATIVE_INT32X4(fromUint16x8Bits)
    7809           0 :           SET_NATIVE_INT32X4(fromUint32x4Bits)
    7810           0 :           default: MOZ_CRASH("shouldn't have been validated in the first place");
    7811             :         }
    7812           0 :         break;
    7813             :       case SimdType::Uint8x16:
    7814           0 :         switch (global.simdOperation()) {
    7815           0 :           FORALL_INT8X16_ASMJS_OP(SET_NATIVE_UINT8X16)
    7816           0 :           SET_NATIVE_UINT8X16(fromInt8x16Bits)
    7817           0 :           SET_NATIVE_UINT8X16(fromUint16x8Bits)
    7818           0 :           SET_NATIVE_UINT8X16(fromUint32x4Bits)
    7819           0 :           default: MOZ_CRASH("shouldn't have been validated in the first place");
    7820             :         }
    7821           0 :         break;
    7822             :       case SimdType::Uint16x8:
    7823           0 :         switch (global.simdOperation()) {
    7824           0 :           FORALL_INT16X8_ASMJS_OP(SET_NATIVE_UINT16X8)
    7825           0 :           SET_NATIVE_UINT16X8(fromUint8x16Bits)
    7826           0 :           SET_NATIVE_UINT16X8(fromInt16x8Bits)
    7827           0 :           SET_NATIVE_UINT16X8(fromUint32x4Bits)
    7828           0 :           default: MOZ_CRASH("shouldn't have been validated in the first place");
    7829             :         }
    7830           0 :         break;
    7831             :       case SimdType::Uint32x4:
    7832           0 :         switch (global.simdOperation()) {
    7833           0 :           FORALL_INT32X4_ASMJS_OP(SET_NATIVE_UINT32X4)
    7834           0 :           SET_NATIVE_UINT32X4(fromUint8x16Bits)
    7835           0 :           SET_NATIVE_UINT32X4(fromUint16x8Bits)
    7836           0 :           SET_NATIVE_UINT32X4(fromInt32x4Bits)
    7837           0 :           default: MOZ_CRASH("shouldn't have been validated in the first place");
    7838             :         }
    7839           0 :         break;
    7840             :       case SimdType::Float32x4:
    7841           0 :         switch (global.simdOperation()) {
    7842           0 :           FORALL_FLOAT32X4_ASMJS_OP(SET_NATIVE_FLOAT32X4)
    7843           0 :           SET_NATIVE_FLOAT32X4(fromUint8x16Bits)
    7844           0 :           SET_NATIVE_FLOAT32X4(fromUint16x8Bits)
    7845           0 :           SET_NATIVE_FLOAT32X4(fromUint32x4Bits)
    7846           0 :           default: MOZ_CRASH("shouldn't have been validated in the first place");
    7847             :         }
    7848           0 :         break;
    7849             :       case SimdType::Bool8x16:
    7850           0 :         switch (global.simdOperation()) {
    7851           0 :           FORALL_BOOL_SIMD_OP(SET_NATIVE_BOOL8X16)
    7852           0 :           default: MOZ_CRASH("shouldn't have been validated in the first place");
    7853             :         }
    7854           0 :         break;
    7855             :       case SimdType::Bool16x8:
    7856           0 :         switch (global.simdOperation()) {
    7857           0 :           FORALL_BOOL_SIMD_OP(SET_NATIVE_BOOL16X8)
    7858           0 :           default: MOZ_CRASH("shouldn't have been validated in the first place");
    7859             :         }
    7860           0 :         break;
    7861             :       case SimdType::Bool32x4:
    7862           0 :         switch (global.simdOperation()) {
    7863           0 :           FORALL_BOOL_SIMD_OP(SET_NATIVE_BOOL32X4)
    7864           0 :           default: MOZ_CRASH("shouldn't have been validated in the first place");
    7865             :         }
    7866           0 :         break;
    7867           0 :       default: MOZ_CRASH("unhandled simd type");
    7868             : #undef FALLTHROUGH
    7869             : #undef SET_NATIVE_INT8X16
    7870             : #undef SET_NATIVE_INT16X8
    7871             : #undef SET_NATIVE_INT32X4
    7872             : #undef SET_NATIVE_UINT8X16
    7873             : #undef SET_NATIVE_UINT16X8
    7874             : #undef SET_NATIVE_UINT32X4
    7875             : #undef SET_NATIVE_FLOAT32X4
    7876             : #undef SET_NATIVE_BOOL8X16
    7877             : #undef SET_NATIVE_BOOL16X8
    7878             : #undef SET_NATIVE_BOOL32X4
    7879             : #undef SET_NATIVE
    7880             :     }
    7881           0 :     if (!native || !IsNativeFunction(v, native))
    7882           0 :         return LinkFail(cx, "bad SIMD.type.* operation");
    7883           0 :     return true;
    7884             : }
    7885             : 
    7886             : static bool
    7887           0 : ValidateAtomicsBuiltinFunction(JSContext* cx, const AsmJSGlobal& global, HandleValue globalVal)
    7888             : {
    7889           0 :     RootedValue v(cx);
    7890           0 :     if (!GetDataProperty(cx, globalVal, cx->names().Atomics, &v))
    7891           0 :         return false;
    7892             : 
    7893           0 :     if (!GetDataProperty(cx, v, global.field(), &v))
    7894           0 :         return false;
    7895             : 
    7896           0 :     Native native = nullptr;
    7897           0 :     switch (global.atomicsBuiltinFunction()) {
    7898           0 :       case AsmJSAtomicsBuiltin_compareExchange: native = atomics_compareExchange; break;
    7899           0 :       case AsmJSAtomicsBuiltin_exchange: native = atomics_exchange; break;
    7900           0 :       case AsmJSAtomicsBuiltin_load: native = atomics_load; break;
    7901           0 :       case AsmJSAtomicsBuiltin_store: native = atomics_store; break;
    7902           0 :       case AsmJSAtomicsBuiltin_add: native = atomics_add; break;
    7903           0 :       case AsmJSAtomicsBuiltin_sub: native = atomics_sub; break;
    7904           0 :       case AsmJSAtomicsBuiltin_and: native = atomics_and; break;
    7905           0 :       case AsmJSAtomicsBuiltin_or: native = atomics_or; break;
    7906           0 :       case AsmJSAtomicsBuiltin_xor: native = atomics_xor; break;
    7907           0 :       case AsmJSAtomicsBuiltin_isLockFree: native = atomics_isLockFree; break;
    7908             :     }
    7909             : 
    7910           0 :     if (!IsNativeFunction(v, native))
    7911           0 :         return LinkFail(cx, "bad Atomics.* builtin function");
    7912             : 
    7913           0 :     return true;
    7914             : }
    7915             : 
    7916             : static bool
    7917           0 : ValidateConstant(JSContext* cx, const AsmJSGlobal& global, HandleValue globalVal)
    7918             : {
    7919           0 :     RootedValue v(cx, globalVal);
    7920             : 
    7921           0 :     if (global.constantKind() == AsmJSGlobal::MathConstant) {
    7922           0 :         if (!GetDataProperty(cx, v, cx->names().Math, &v))
    7923           0 :             return false;
    7924             :     }
    7925             : 
    7926           0 :     if (!GetDataProperty(cx, v, global.field(), &v))
    7927           0 :         return false;
    7928             : 
    7929           0 :     if (!v.isNumber())
    7930           0 :         return LinkFail(cx, "math / global constant value needs to be a number");
    7931             : 
    7932             :     // NaN != NaN
    7933           0 :     if (IsNaN(global.constantValue())) {
    7934           0 :         if (!IsNaN(v.toNumber()))
    7935           0 :             return LinkFail(cx, "global constant value needs to be NaN");
    7936             :     } else {
    7937           0 :         if (v.toNumber() != global.constantValue())
    7938           0 :             return LinkFail(cx, "global constant value mismatch");
    7939             :     }
    7940             : 
    7941           0 :     return true;
    7942             : }
    7943             : 
    7944             : static bool
    7945           0 : CheckBuffer(JSContext* cx, const AsmJSMetadata& metadata, HandleValue bufferVal,
    7946             :             MutableHandle<ArrayBufferObjectMaybeShared*> buffer)
    7947             : {
    7948           0 :     if (metadata.memoryUsage == MemoryUsage::Shared) {
    7949           0 :         if (!IsSharedArrayBuffer(bufferVal))
    7950           0 :             return LinkFail(cx, "shared views can only be constructed onto SharedArrayBuffer");
    7951             :     } else {
    7952           0 :         if (!IsArrayBuffer(bufferVal))
    7953           0 :             return LinkFail(cx, "unshared views can only be constructed onto ArrayBuffer");
    7954             :     }
    7955             : 
    7956           0 :     buffer.set(&AsAnyArrayBuffer(bufferVal));
    7957           0 :     uint32_t memoryLength = buffer->byteLength();
    7958             : 
    7959           0 :     if (!IsValidAsmJSHeapLength(memoryLength)) {
    7960             :         UniqueChars msg(
    7961             :             JS_smprintf("ArrayBuffer byteLength 0x%x is not a valid heap length. The next "
    7962             :                         "valid length is 0x%x",
    7963             :                         memoryLength,
    7964           0 :                         RoundUpToNextValidAsmJSHeapLength(memoryLength)));
    7965           0 :         if (!msg)
    7966           0 :             return false;
    7967           0 :         return LinkFail(cx, msg.get());
    7968             :     }
    7969             : 
    7970             :     // This check is sufficient without considering the size of the loaded datum because heap
    7971             :     // loads and stores start on an aligned boundary and the heap byteLength has larger alignment.
    7972           0 :     MOZ_ASSERT((metadata.minMemoryLength - 1) <= INT32_MAX);
    7973           0 :     if (memoryLength < metadata.minMemoryLength) {
    7974             :         UniqueChars msg(
    7975             :             JS_smprintf("ArrayBuffer byteLength of 0x%x is less than 0x%x (the size implied "
    7976             :                         "by const heap accesses).",
    7977             :                         memoryLength,
    7978           0 :                         metadata.minMemoryLength));
    7979           0 :         if (!msg)
    7980           0 :             return false;
    7981           0 :         return LinkFail(cx, msg.get());
    7982             :     }
    7983             : 
    7984           0 :     if (buffer->is<ArrayBufferObject>()) {
    7985             :         // On 64-bit, bounds checks are statically removed so the huge guard
    7986             :         // region is always necessary. On 32-bit, allocating a guard page
    7987             :         // requires reallocating the incoming ArrayBuffer which could trigger
    7988             :         // OOM. Thus, only ask for a guard page when SIMD is used since SIMD
    7989             :         // allows unaligned memory access (see MaxMemoryAccessSize comment);
    7990             : #ifdef WASM_HUGE_MEMORY
    7991           0 :         bool needGuard = true;
    7992             : #else
    7993             :         bool needGuard = metadata.usesSimd;
    7994             : #endif
    7995           0 :         Rooted<ArrayBufferObject*> arrayBuffer(cx, &buffer->as<ArrayBufferObject>());
    7996           0 :         if (!ArrayBufferObject::prepareForAsmJS(cx, arrayBuffer, needGuard))
    7997           0 :             return LinkFail(cx, "Unable to prepare ArrayBuffer for asm.js use");
    7998             :     } else {
    7999           0 :         if (!buffer->as<SharedArrayBufferObject>().isPreparedForAsmJS())
    8000           0 :             return LinkFail(cx, "SharedArrayBuffer must be created with wasm test mode enabled");
    8001             :     }
    8002             : 
    8003           0 :     MOZ_ASSERT(buffer->isPreparedForAsmJS());
    8004           0 :     return true;
    8005             : }
    8006             : 
    8007             : static bool
    8008           0 : GetImports(JSContext* cx, const AsmJSMetadata& metadata, HandleValue globalVal,
    8009             :            HandleValue importVal, MutableHandle<FunctionVector> funcImports, ValVector* valImports)
    8010             : {
    8011           0 :     Rooted<FunctionVector> ffis(cx, FunctionVector(cx));
    8012           0 :     if (!ffis.resize(metadata.numFFIs))
    8013           0 :         return false;
    8014             : 
    8015           0 :     for (const AsmJSGlobal& global : metadata.asmJSGlobals) {
    8016           0 :         switch (global.which()) {
    8017             :           case AsmJSGlobal::Variable: {
    8018           0 :             Val val;
    8019           0 :             if (!ValidateGlobalVariable(cx, global, importVal, &val))
    8020           0 :                 return false;
    8021           0 :             if (!valImports->append(val))
    8022           0 :                 return false;
    8023           0 :             break;
    8024             :           }
    8025             :           case AsmJSGlobal::FFI:
    8026           0 :             if (!ValidateFFI(cx, global, importVal, &ffis))
    8027           0 :                 return false;
    8028           0 :             break;
    8029             :           case AsmJSGlobal::ArrayView:
    8030             :           case AsmJSGlobal::ArrayViewCtor:
    8031           0 :             if (!ValidateArrayView(cx, global, globalVal))
    8032           0 :                 return false;
    8033           0 :             break;
    8034             :           case AsmJSGlobal::MathBuiltinFunction:
    8035           0 :             if (!ValidateMathBuiltinFunction(cx, global, globalVal))
    8036           0 :                 return false;
    8037           0 :             break;
    8038             :           case AsmJSGlobal::AtomicsBuiltinFunction:
    8039           0 :             if (!ValidateAtomicsBuiltinFunction(cx, global, globalVal))
    8040           0 :                 return false;
    8041           0 :             break;
    8042             :           case AsmJSGlobal::Constant:
    8043           0 :             if (!ValidateConstant(cx, global, globalVal))
    8044           0 :                 return false;
    8045           0 :             break;
    8046             :           case AsmJSGlobal::SimdCtor:
    8047           0 :             if (!ValidateSimdType(cx, global, globalVal))
    8048           0 :                 return false;
    8049           0 :             break;
    8050             :           case AsmJSGlobal::SimdOp:
    8051           0 :             if (!ValidateSimdOperation(cx, global, globalVal))
    8052           0 :                 return false;
    8053           0 :             break;
    8054             :         }
    8055             :     }
    8056             : 
    8057           0 :     for (const AsmJSImport& import : metadata.asmJSImports) {
    8058           0 :         if (!funcImports.append(ffis[import.ffiIndex()]))
    8059           0 :             return false;
    8060             :     }
    8061             : 
    8062           0 :     return true;
    8063             : }
    8064             : 
    8065             : static bool
    8066           0 : TryInstantiate(JSContext* cx, CallArgs args, Module& module, const AsmJSMetadata& metadata,
    8067             :                MutableHandleWasmInstanceObject instanceObj, MutableHandleObject exportObj)
    8068             : {
    8069           0 :     HandleValue globalVal = args.get(0);
    8070           0 :     HandleValue importVal = args.get(1);
    8071           0 :     HandleValue bufferVal = args.get(2);
    8072             : 
    8073           0 :     RootedArrayBufferObjectMaybeShared buffer(cx);
    8074           0 :     RootedWasmMemoryObject memory(cx);
    8075           0 :     if (module.metadata().usesMemory()) {
    8076           0 :         if (!CheckBuffer(cx, metadata, bufferVal, &buffer))
    8077           0 :             return false;
    8078             : 
    8079           0 :         memory = WasmMemoryObject::create(cx, buffer, nullptr);
    8080           0 :         if (!memory)
    8081           0 :             return false;
    8082             :     }
    8083             : 
    8084           0 :     ValVector valImports;
    8085           0 :     Rooted<FunctionVector> funcs(cx, FunctionVector(cx));
    8086           0 :     if (!GetImports(cx, metadata, globalVal, importVal, &funcs, &valImports))
    8087           0 :         return false;
    8088             : 
    8089           0 :     RootedWasmTableObject table(cx);
    8090           0 :     if (!module.instantiate(cx, funcs, table, memory, valImports, nullptr, instanceObj))
    8091           0 :         return false;
    8092             : 
    8093           0 :     exportObj.set(&instanceObj->exportsObj());
    8094           0 :     return true;
    8095             : }
    8096             : 
    8097             : static bool
    8098           0 : HandleInstantiationFailure(JSContext* cx, CallArgs args, const AsmJSMetadata& metadata)
    8099             : {
    8100           0 :     RootedAtom name(cx, args.callee().as<JSFunction>().explicitName());
    8101             : 
    8102           0 :     if (cx->isExceptionPending())
    8103           0 :         return false;
    8104             : 
    8105           0 :     ScriptSource* source = metadata.scriptSource.get();
    8106             : 
    8107             :     // Source discarding is allowed to affect JS semantics because it is never
    8108             :     // enabled for normal JS content.
    8109           0 :     bool haveSource = source->hasSourceData();
    8110           0 :     if (!haveSource && !JSScript::loadSource(cx, source, &haveSource))
    8111           0 :         return false;
    8112           0 :     if (!haveSource) {
    8113           0 :         JS_ReportErrorASCII(cx, "asm.js link failure with source discarding enabled");
    8114           0 :         return false;
    8115             :     }
    8116             : 
    8117           0 :     uint32_t begin = metadata.toStringStart;
    8118           0 :     uint32_t end = metadata.srcEndAfterCurly();
    8119           0 :     Rooted<JSFlatString*> src(cx, source->substringDontDeflate(cx, begin, end));
    8120           0 :     if (!src)
    8121           0 :         return false;
    8122             : 
    8123           0 :     RootedFunction fun(cx, NewScriptedFunction(cx, 0, JSFunction::INTERPRETED_NORMAL,
    8124             :                                                name, /* proto = */ nullptr, gc::AllocKind::FUNCTION,
    8125           0 :                                                TenuredObject));
    8126           0 :     if (!fun)
    8127           0 :         return false;
    8128             : 
    8129           0 :     CompileOptions options(cx);
    8130           0 :     options.setMutedErrors(source->mutedErrors())
    8131           0 :            .setFile(source->filename())
    8132           0 :            .setNoScriptRval(false);
    8133           0 :     options.asmJSOption = AsmJSOption::Disabled;
    8134             : 
    8135             :     // The exported function inherits an implicit strict context if the module
    8136             :     // also inherited it somehow.
    8137           0 :     if (metadata.strict)
    8138           0 :         options.strictOption = true;
    8139             : 
    8140           0 :     AutoStableStringChars stableChars(cx);
    8141           0 :     if (!stableChars.initTwoByte(cx, src))
    8142           0 :         return false;
    8143             : 
    8144           0 :     const char16_t* chars = stableChars.twoByteRange().begin().get();
    8145           0 :     SourceBufferHolder::Ownership ownership = stableChars.maybeGiveOwnershipToCaller()
    8146           0 :                                               ? SourceBufferHolder::GiveOwnership
    8147           0 :                                               : SourceBufferHolder::NoOwnership;
    8148           0 :     SourceBufferHolder srcBuf(chars, end - begin, ownership);
    8149           0 :     if (!frontend::CompileStandaloneFunction(cx, &fun, options, srcBuf, Nothing()))
    8150           0 :         return false;
    8151             : 
    8152             :     // Call the function we just recompiled.
    8153           0 :     args.setCallee(ObjectValue(*fun));
    8154           0 :     return InternalCallOrConstruct(cx, args, args.isConstructing() ? CONSTRUCT : NO_CONSTRUCT);
    8155             : }
    8156             : 
    8157             : static Module&
    8158           0 : AsmJSModuleFunctionToModule(JSFunction* fun)
    8159             : {
    8160           0 :     MOZ_ASSERT(IsAsmJSModule(fun));
    8161           0 :     const Value& v = fun->getExtendedSlot(FunctionExtended::ASMJS_MODULE_SLOT);
    8162           0 :     return v.toObject().as<WasmModuleObject>().module();
    8163             : }
    8164             : 
    8165             : // Implements the semantics of an asm.js module function that has been successfully validated.
    8166             : static bool
    8167           0 : InstantiateAsmJS(JSContext* cx, unsigned argc, JS::Value* vp)
    8168             : {
    8169           0 :     CallArgs args = CallArgsFromVp(argc, vp);
    8170             : 
    8171           0 :     JSFunction* callee = &args.callee().as<JSFunction>();
    8172           0 :     Module& module = AsmJSModuleFunctionToModule(callee);
    8173           0 :     const AsmJSMetadata& metadata = module.metadata().asAsmJS();
    8174             : 
    8175           0 :     RootedWasmInstanceObject instanceObj(cx);
    8176           0 :     RootedObject exportObj(cx);
    8177           0 :     if (!TryInstantiate(cx, args, module, metadata, &instanceObj, &exportObj)) {
    8178             :         // Link-time validation checks failed, so reparse the entire asm.js
    8179             :         // module from scratch to get normal interpreted bytecode which we can
    8180             :         // simply Invoke. Very slow.
    8181           0 :         return HandleInstantiationFailure(cx, args, metadata);
    8182             :     }
    8183             : 
    8184           0 :     args.rval().set(ObjectValue(*exportObj));
    8185           0 :     return true;
    8186             : }
    8187             : 
    8188             : static JSFunction*
    8189           0 : NewAsmJSModuleFunction(JSContext* cx, JSFunction* origFun, HandleObject moduleObj)
    8190             : {
    8191           0 :     RootedAtom name(cx, origFun->explicitName());
    8192             : 
    8193           0 :     JSFunction::Flags flags = origFun->isLambda() ? JSFunction::ASMJS_LAMBDA_CTOR
    8194           0 :                                                   : JSFunction::ASMJS_CTOR;
    8195             :     JSFunction* moduleFun =
    8196           0 :         NewNativeConstructor(cx, InstantiateAsmJS, origFun->nargs(), name,
    8197             :                              gc::AllocKind::FUNCTION_EXTENDED, TenuredObject,
    8198           0 :                              flags);
    8199           0 :     if (!moduleFun)
    8200           0 :         return nullptr;
    8201             : 
    8202           0 :     moduleFun->setExtendedSlot(FunctionExtended::ASMJS_MODULE_SLOT, ObjectValue(*moduleObj));
    8203             : 
    8204           0 :     MOZ_ASSERT(IsAsmJSModule(moduleFun));
    8205           0 :     return moduleFun;
    8206             : }
    8207             : 
    8208             : /*****************************************************************************/
    8209             : // Caching and cloning
    8210             : 
    8211             : size_t
    8212           0 : AsmJSGlobal::serializedSize() const
    8213             : {
    8214             :     return sizeof(pod) +
    8215           0 :            field_.serializedSize();
    8216             : }
    8217             : 
    8218             : uint8_t*
    8219           0 : AsmJSGlobal::serialize(uint8_t* cursor) const
    8220             : {
    8221           0 :     cursor = WriteBytes(cursor, &pod, sizeof(pod));
    8222           0 :     cursor = field_.serialize(cursor);
    8223           0 :     return cursor;
    8224             : }
    8225             : 
    8226             : const uint8_t*
    8227           0 : AsmJSGlobal::deserialize(const uint8_t* cursor)
    8228             : {
    8229           0 :     (cursor = ReadBytes(cursor, &pod, sizeof(pod))) &&
    8230           0 :     (cursor = field_.deserialize(cursor));
    8231           0 :     return cursor;
    8232             : }
    8233             : 
    8234             : size_t
    8235           0 : AsmJSGlobal::sizeOfExcludingThis(MallocSizeOf mallocSizeOf) const
    8236             : {
    8237           0 :     return field_.sizeOfExcludingThis(mallocSizeOf);
    8238             : }
    8239             : 
    8240             : size_t
    8241           0 : AsmJSMetadata::serializedSize() const
    8242             : {
    8243           0 :     return Metadata::serializedSize() +
    8244           0 :            sizeof(pod()) +
    8245           0 :            SerializedVectorSize(asmJSGlobals) +
    8246           0 :            SerializedPodVectorSize(asmJSImports) +
    8247           0 :            SerializedPodVectorSize(asmJSExports) +
    8248           0 :            SerializedVectorSize(asmJSFuncNames) +
    8249           0 :            globalArgumentName.serializedSize() +
    8250           0 :            importArgumentName.serializedSize() +
    8251           0 :            bufferArgumentName.serializedSize();
    8252             : }
    8253             : 
    8254             : uint8_t*
    8255           0 : AsmJSMetadata::serialize(uint8_t* cursor) const
    8256             : {
    8257           0 :     cursor = Metadata::serialize(cursor);
    8258           0 :     cursor = WriteBytes(cursor, &pod(), sizeof(pod()));
    8259           0 :     cursor = SerializeVector(cursor, asmJSGlobals);
    8260           0 :     cursor = SerializePodVector(cursor, asmJSImports);
    8261           0 :     cursor = SerializePodVector(cursor, asmJSExports);
    8262           0 :     cursor = SerializeVector(cursor, asmJSFuncNames);
    8263           0 :     cursor = globalArgumentName.serialize(cursor);
    8264           0 :     cursor = importArgumentName.serialize(cursor);
    8265           0 :     cursor = bufferArgumentName.serialize(cursor);
    8266           0 :     return cursor;
    8267             : }
    8268             : 
    8269             : const uint8_t*
    8270           0 : AsmJSMetadata::deserialize(const uint8_t* cursor)
    8271             : {
    8272           0 :     (cursor = Metadata::deserialize(cursor)) &&
    8273           0 :     (cursor = ReadBytes(cursor, &pod(), sizeof(pod()))) &&
    8274           0 :     (cursor = DeserializeVector(cursor, &asmJSGlobals)) &&
    8275           0 :     (cursor = DeserializePodVector(cursor, &asmJSImports)) &&
    8276           0 :     (cursor = DeserializePodVector(cursor, &asmJSExports)) &&
    8277           0 :     (cursor = DeserializeVector(cursor, &asmJSFuncNames)) &&
    8278           0 :     (cursor = globalArgumentName.deserialize(cursor)) &&
    8279           0 :     (cursor = importArgumentName.deserialize(cursor)) &&
    8280           0 :     (cursor = bufferArgumentName.deserialize(cursor));
    8281           0 :     cacheResult = CacheResult::Hit;
    8282           0 :     return cursor;
    8283             : }
    8284             : 
    8285             : size_t
    8286           0 : AsmJSMetadata::sizeOfExcludingThis(MallocSizeOf mallocSizeOf) const
    8287             : {
    8288           0 :     return Metadata::sizeOfExcludingThis(mallocSizeOf) +
    8289           0 :            SizeOfVectorExcludingThis(asmJSGlobals, mallocSizeOf) +
    8290           0 :            asmJSImports.sizeOfExcludingThis(mallocSizeOf) +
    8291           0 :            asmJSExports.sizeOfExcludingThis(mallocSizeOf) +
    8292           0 :            SizeOfVectorExcludingThis(asmJSFuncNames, mallocSizeOf) +
    8293           0 :            globalArgumentName.sizeOfExcludingThis(mallocSizeOf) +
    8294           0 :            importArgumentName.sizeOfExcludingThis(mallocSizeOf) +
    8295           0 :            bufferArgumentName.sizeOfExcludingThis(mallocSizeOf);
    8296             : }
    8297             : 
    8298             : namespace {
    8299             : 
    8300           0 : class ModuleChars
    8301             : {
    8302             :   protected:
    8303             :     uint32_t isFunCtor_;
    8304             :     Vector<CacheableChars, 0, SystemAllocPolicy> funCtorArgs_;
    8305             : 
    8306             :   public:
    8307           0 :     static uint32_t beginOffset(AsmJSParser& parser) {
    8308           0 :         return parser.pc->functionBox()->functionNode->pn_pos.begin;
    8309             :     }
    8310             : 
    8311           0 :     static uint32_t endOffset(AsmJSParser& parser) {
    8312           0 :         TokenPos pos(0, 0);  // initialize to silence GCC warning
    8313           0 :         MOZ_ALWAYS_TRUE(parser.tokenStream.peekTokenPos(&pos, TokenStream::Operand));
    8314           0 :         return pos.end;
    8315             :     }
    8316             : };
    8317             : 
    8318           0 : class ModuleCharsForStore : ModuleChars
    8319             : {
    8320             :     uint32_t uncompressedSize_;
    8321             :     uint32_t compressedSize_;
    8322             :     Vector<char, 0, SystemAllocPolicy> compressedBuffer_;
    8323             : 
    8324             :   public:
    8325           0 :     bool init(AsmJSParser& parser) {
    8326           0 :         MOZ_ASSERT(beginOffset(parser) < endOffset(parser));
    8327             : 
    8328           0 :         uncompressedSize_ = (endOffset(parser) - beginOffset(parser)) * sizeof(char16_t);
    8329           0 :         size_t maxCompressedSize = LZ4::maxCompressedSize(uncompressedSize_);
    8330           0 :         if (maxCompressedSize < uncompressedSize_)
    8331           0 :             return false;
    8332             : 
    8333           0 :         if (!compressedBuffer_.resize(maxCompressedSize))
    8334           0 :             return false;
    8335             : 
    8336           0 :         const char16_t* chars = parser.tokenStream.rawCharPtrAt(beginOffset(parser));
    8337           0 :         const char* source = reinterpret_cast<const char*>(chars);
    8338           0 :         size_t compressedSize = LZ4::compress(source, uncompressedSize_, compressedBuffer_.begin());
    8339           0 :         if (!compressedSize || compressedSize > UINT32_MAX)
    8340           0 :             return false;
    8341             : 
    8342           0 :         compressedSize_ = compressedSize;
    8343             : 
    8344             :         // For a function statement or named function expression:
    8345             :         //   function f(x,y,z) { abc }
    8346             :         // the range [beginOffset, endOffset) captures the source:
    8347             :         //   f(x,y,z) { abc }
    8348             :         // An unnamed function expression captures the same thing, sans 'f'.
    8349             :         // Since asm.js modules do not contain any free variables, equality of
    8350             :         // [beginOffset, endOffset) is sufficient to guarantee identical code
    8351             :         // generation, modulo Assumptions.
    8352             :         //
    8353             :         // For functions created with 'new Function', function arguments are
    8354             :         // not present in the source so we must manually explicitly serialize
    8355             :         // and match the formals as a Vector of PropertyName.
    8356           0 :         isFunCtor_ = parser.pc->isStandaloneFunctionBody();
    8357           0 :         if (isFunCtor_) {
    8358             :             unsigned numArgs;
    8359           0 :             ParseNode* functionNode = parser.pc->functionBox()->functionNode;
    8360           0 :             ParseNode* arg = FunctionFormalParametersList(functionNode, &numArgs);
    8361           0 :             for (unsigned i = 0; i < numArgs; i++, arg = arg->pn_next) {
    8362           0 :                 UniqueChars name = StringToNewUTF8CharsZ(nullptr, *arg->name());
    8363           0 :                 if (!name || !funCtorArgs_.append(Move(name)))
    8364           0 :                     return false;
    8365             :             }
    8366             :         }
    8367             : 
    8368           0 :         return true;
    8369             :     }
    8370             : 
    8371           0 :     size_t serializedSize() const {
    8372             :         return sizeof(uint32_t) +
    8373             :                sizeof(uint32_t) +
    8374           0 :                compressedSize_ +
    8375           0 :                sizeof(uint32_t) +
    8376           0 :                (isFunCtor_ ? SerializedVectorSize(funCtorArgs_) : 0);
    8377             :     }
    8378             : 
    8379           0 :     uint8_t* serialize(uint8_t* cursor) const {
    8380           0 :         cursor = WriteScalar<uint32_t>(cursor, uncompressedSize_);
    8381           0 :         cursor = WriteScalar<uint32_t>(cursor, compressedSize_);
    8382           0 :         cursor = WriteBytes(cursor, compressedBuffer_.begin(), compressedSize_);
    8383           0 :         cursor = WriteScalar<uint32_t>(cursor, isFunCtor_);
    8384           0 :         if (isFunCtor_)
    8385           0 :             cursor = SerializeVector(cursor, funCtorArgs_);
    8386           0 :         return cursor;
    8387             :     }
    8388             : };
    8389             : 
    8390           0 : class ModuleCharsForLookup : ModuleChars
    8391             : {
    8392             :     Vector<char16_t, 0, SystemAllocPolicy> chars_;
    8393             : 
    8394             :   public:
    8395           0 :     const uint8_t* deserialize(const uint8_t* cursor) {
    8396             :         uint32_t uncompressedSize;
    8397           0 :         cursor = ReadScalar<uint32_t>(cursor, &uncompressedSize);
    8398             : 
    8399             :         uint32_t compressedSize;
    8400           0 :         cursor = ReadScalar<uint32_t>(cursor, &compressedSize);
    8401             : 
    8402           0 :         if (!chars_.resize(uncompressedSize / sizeof(char16_t)))
    8403           0 :             return nullptr;
    8404             : 
    8405           0 :         const char* source = reinterpret_cast<const char*>(cursor);
    8406           0 :         char* dest = reinterpret_cast<char*>(chars_.begin());
    8407           0 :         if (!LZ4::decompress(source, dest, uncompressedSize))
    8408           0 :             return nullptr;
    8409             : 
    8410           0 :         cursor += compressedSize;
    8411             : 
    8412           0 :         cursor = ReadScalar<uint32_t>(cursor, &isFunCtor_);
    8413           0 :         if (isFunCtor_)
    8414           0 :             cursor = DeserializeVector(cursor, &funCtorArgs_);
    8415             : 
    8416           0 :         return cursor;
    8417             :     }
    8418             : 
    8419           0 :     bool match(AsmJSParser& parser) const {
    8420           0 :         const char16_t* parseBegin = parser.tokenStream.rawCharPtrAt(beginOffset(parser));
    8421           0 :         const char16_t* parseLimit = parser.tokenStream.rawLimit();
    8422           0 :         MOZ_ASSERT(parseLimit >= parseBegin);
    8423           0 :         if (uint32_t(parseLimit - parseBegin) < chars_.length())
    8424           0 :             return false;
    8425           0 :         if (!PodEqual(chars_.begin(), parseBegin, chars_.length()))
    8426           0 :             return false;
    8427           0 :         if (isFunCtor_ != parser.pc->isStandaloneFunctionBody())
    8428           0 :             return false;
    8429           0 :         if (isFunCtor_) {
    8430             :             // For function statements, the closing } is included as the last
    8431             :             // character of the matched source. For Function constructor,
    8432             :             // parsing terminates with EOF which we must explicitly check. This
    8433             :             // prevents
    8434             :             //   new Function('"use asm"; function f() {} return f')
    8435             :             // from incorrectly matching
    8436             :             //   new Function('"use asm"; function f() {} return ff')
    8437           0 :             if (parseBegin + chars_.length() != parseLimit)
    8438           0 :                 return false;
    8439             :             unsigned numArgs;
    8440           0 :             ParseNode* functionNode = parser.pc->functionBox()->functionNode;
    8441           0 :             ParseNode* arg = FunctionFormalParametersList(functionNode, &numArgs);
    8442           0 :             if (funCtorArgs_.length() != numArgs)
    8443           0 :                 return false;
    8444           0 :             for (unsigned i = 0; i < funCtorArgs_.length(); i++, arg = arg->pn_next) {
    8445           0 :                 UniqueChars name = StringToNewUTF8CharsZ(nullptr, *arg->name());
    8446           0 :                 if (!name || strcmp(funCtorArgs_[i].get(), name.get()))
    8447           0 :                     return false;
    8448             :             }
    8449             :         }
    8450           0 :         return true;
    8451             :     }
    8452             : };
    8453             : 
    8454             : struct ScopedCacheEntryOpenedForWrite
    8455             : {
    8456             :     JSContext* cx;
    8457             :     const size_t serializedSize;
    8458             :     uint8_t* memory;
    8459             :     intptr_t handle;
    8460             : 
    8461           0 :     ScopedCacheEntryOpenedForWrite(JSContext* cx, size_t serializedSize)
    8462           0 :       : cx(cx), serializedSize(serializedSize), memory(nullptr), handle(-1)
    8463           0 :     {}
    8464             : 
    8465           0 :     ~ScopedCacheEntryOpenedForWrite() {
    8466           0 :         if (memory)
    8467           0 :             cx->asmJSCacheOps().closeEntryForWrite(serializedSize, memory, handle);
    8468           0 :     }
    8469             : };
    8470             : 
    8471             : struct ScopedCacheEntryOpenedForRead
    8472             : {
    8473             :     JSContext* cx;
    8474             :     size_t serializedSize;
    8475             :     const uint8_t* memory;
    8476             :     intptr_t handle;
    8477             : 
    8478           0 :     explicit ScopedCacheEntryOpenedForRead(JSContext* cx)
    8479           0 :       : cx(cx), serializedSize(0), memory(nullptr), handle(0)
    8480           0 :     {}
    8481             : 
    8482           0 :     ~ScopedCacheEntryOpenedForRead() {
    8483           0 :         if (memory)
    8484           0 :             cx->asmJSCacheOps().closeEntryForRead(serializedSize, memory, handle);
    8485           0 :     }
    8486             : };
    8487             : 
    8488             : } // unnamed namespace
    8489             : 
    8490             : static JS::AsmJSCacheResult
    8491           0 : StoreAsmJSModuleInCache(AsmJSParser& parser, Module& module, JSContext* cx)
    8492             : {
    8493           0 :     ModuleCharsForStore moduleChars;
    8494           0 :     if (!moduleChars.init(parser))
    8495           0 :         return JS::AsmJSCache_InternalError;
    8496             : 
    8497             :     size_t bytecodeSize, compiledSize;
    8498           0 :     module.serializedSize(&bytecodeSize, &compiledSize);
    8499           0 :     MOZ_RELEASE_ASSERT(bytecodeSize == 0);
    8500           0 :     MOZ_RELEASE_ASSERT(compiledSize <= UINT32_MAX);
    8501             : 
    8502             :     size_t serializedSize = sizeof(uint32_t) +
    8503           0 :                             compiledSize +
    8504           0 :                             moduleChars.serializedSize();
    8505             : 
    8506           0 :     JS::OpenAsmJSCacheEntryForWriteOp open = cx->asmJSCacheOps().openEntryForWrite;
    8507           0 :     if (!open)
    8508           0 :         return JS::AsmJSCache_Disabled_Internal;
    8509             : 
    8510           0 :     const char16_t* begin = parser.tokenStream.rawCharPtrAt(ModuleChars::beginOffset(parser));
    8511           0 :     const char16_t* end = parser.tokenStream.rawCharPtrAt(ModuleChars::endOffset(parser));
    8512             : 
    8513           0 :     ScopedCacheEntryOpenedForWrite entry(cx, serializedSize);
    8514             :     JS::AsmJSCacheResult openResult =
    8515           0 :         open(cx->global(), begin, end, serializedSize, &entry.memory, &entry.handle);
    8516           0 :     if (openResult != JS::AsmJSCache_Success)
    8517           0 :         return openResult;
    8518             : 
    8519           0 :     uint8_t* cursor = entry.memory;
    8520             : 
    8521             :     // Everything serialized before the Module must not change incompatibly
    8522             :     // between any two builds (regardless of platform, architecture, ...).
    8523             :     // (The Module::assumptionsMatch() guard everything in the Module and
    8524             :     // afterwards.)
    8525           0 :     cursor = WriteScalar<uint32_t>(cursor, compiledSize);
    8526             : 
    8527           0 :     module.serialize(/* bytecodeBegin = */ nullptr, /* bytecodeSize = */ 0, cursor, compiledSize);
    8528           0 :     cursor += compiledSize;
    8529             : 
    8530           0 :     cursor = moduleChars.serialize(cursor);
    8531             : 
    8532           0 :     MOZ_RELEASE_ASSERT(cursor == entry.memory + serializedSize);
    8533             : 
    8534           0 :     return JS::AsmJSCache_Success;
    8535             : }
    8536             : 
    8537             : static bool
    8538           0 : LookupAsmJSModuleInCache(JSContext* cx, AsmJSParser& parser, bool* loadedFromCache,
    8539             :                          SharedModule* module, UniqueChars* compilationTimeReport)
    8540             : {
    8541           0 :     int64_t before = PRMJ_Now();
    8542             : 
    8543           0 :     *loadedFromCache = false;
    8544             : 
    8545           0 :     JS::OpenAsmJSCacheEntryForReadOp open = cx->asmJSCacheOps().openEntryForRead;
    8546           0 :     if (!open)
    8547           0 :         return true;
    8548             : 
    8549           0 :     const char16_t* begin = parser.tokenStream.rawCharPtrAt(ModuleChars::beginOffset(parser));
    8550           0 :     const char16_t* limit = parser.tokenStream.rawLimit();
    8551             : 
    8552           0 :     ScopedCacheEntryOpenedForRead entry(cx);
    8553           0 :     if (!open(cx->global(), begin, limit, &entry.serializedSize, &entry.memory, &entry.handle))
    8554           0 :         return true;
    8555             : 
    8556           0 :     size_t remain = entry.serializedSize;
    8557           0 :     const uint8_t* cursor = entry.memory;
    8558             : 
    8559             :     uint32_t compiledSize;
    8560           0 :     cursor = ReadScalarChecked<uint32_t>(cursor, &remain, &compiledSize);
    8561           0 :     if (!cursor)
    8562           0 :         return true;
    8563             : 
    8564           0 :     Assumptions assumptions;
    8565           0 :     if (!assumptions.initBuildIdFromContext(cx))
    8566           0 :         return false;
    8567             : 
    8568           0 :     if (!Module::assumptionsMatch(assumptions, cursor, remain))
    8569           0 :         return true;
    8570             : 
    8571           0 :     auto tierMetadata = js::MakeUnique<MetadataTier>(Tier::Ion);
    8572           0 :     if (!tierMetadata)
    8573           0 :         return false;
    8574             : 
    8575           0 :     MutableAsmJSMetadata asmJSMetadata = cx->new_<AsmJSMetadata>(Move(tierMetadata));
    8576           0 :     if (!asmJSMetadata)
    8577           0 :         return false;
    8578             : 
    8579           0 :     *module = Module::deserialize(/* bytecodeBegin = */ nullptr, /* bytecodeSize = */ 0,
    8580           0 :                                   cursor, compiledSize, asmJSMetadata.get());
    8581           0 :     if (!*module) {
    8582           0 :         ReportOutOfMemory(cx);
    8583           0 :         return false;
    8584             :     }
    8585           0 :     cursor += compiledSize;
    8586             : 
    8587             :     // Due to the hash comparison made by openEntryForRead, this should succeed
    8588             :     // with high probability.
    8589           0 :     ModuleCharsForLookup moduleChars;
    8590           0 :     cursor = moduleChars.deserialize(cursor);
    8591           0 :     if (!moduleChars.match(parser))
    8592           0 :         return true;
    8593             : 
    8594             :     // Don't punish release users by crashing if there is a programmer error
    8595             :     // here, just gracefully return with a cache miss.
    8596             : #ifdef NIGHTLY_BUILD
    8597           0 :     MOZ_RELEASE_ASSERT(cursor == entry.memory + entry.serializedSize);
    8598             : #endif
    8599           0 :     if (cursor != entry.memory + entry.serializedSize)
    8600           0 :         return true;
    8601             : 
    8602             :     // See AsmJSMetadata comment as well as ModuleValidator::init().
    8603           0 :     asmJSMetadata->toStringStart = parser.pc->functionBox()->toStringStart;
    8604           0 :     asmJSMetadata->srcStart = parser.pc->functionBox()->functionNode->pn_body->pn_pos.begin;
    8605           0 :     asmJSMetadata->srcBodyStart = parser.tokenStream.currentToken().pos.end;
    8606           0 :     asmJSMetadata->strict = parser.pc->sc()->strict() && !parser.pc->sc()->hasExplicitUseStrict();
    8607           0 :     asmJSMetadata->scriptSource.reset(parser.ss);
    8608             : 
    8609           0 :     if (!parser.tokenStream.advance(asmJSMetadata->srcEndBeforeCurly()))
    8610           0 :         return false;
    8611             : 
    8612           0 :     int64_t after = PRMJ_Now();
    8613           0 :     int ms = (after - before) / PRMJ_USEC_PER_MSEC;
    8614           0 :     *compilationTimeReport = JS_smprintf("loaded from cache in %dms", ms);
    8615           0 :     if (!*compilationTimeReport)
    8616           0 :         return false;
    8617             : 
    8618           0 :     *loadedFromCache = true;
    8619           0 :     return true;
    8620             : }
    8621             : 
    8622             : /*****************************************************************************/
    8623             : // Top-level js::CompileAsmJS
    8624             : 
    8625             : static bool
    8626           0 : NoExceptionPending(JSContext* cx)
    8627             : {
    8628           0 :     return cx->helperThread() || !cx->isExceptionPending();
    8629             : }
    8630             : 
    8631             : static bool
    8632           0 : Warn(AsmJSParser& parser, int errorNumber, const char* str)
    8633             : {
    8634           0 :     ParseReportKind reportKind = parser.options().throwOnAsmJSValidationFailureOption &&
    8635             :                                  errorNumber == JSMSG_USE_ASM_TYPE_FAIL
    8636           0 :                                  ? ParseError
    8637           0 :                                  : ParseWarning;
    8638           0 :     parser.reportNoOffset(reportKind, /* strict = */ false, errorNumber, str ? str : "");
    8639           0 :     return false;
    8640             : }
    8641             : 
    8642             : static bool
    8643           0 : EstablishPreconditions(JSContext* cx, AsmJSParser& parser)
    8644             : {
    8645           0 :     if (!HasCompilerSupport(cx))
    8646           0 :         return Warn(parser, JSMSG_USE_ASM_TYPE_FAIL, "Disabled by lack of compiler support");
    8647             : 
    8648           0 :     switch (parser.options().asmJSOption) {
    8649             :       case AsmJSOption::Disabled:
    8650           0 :         return Warn(parser, JSMSG_USE_ASM_TYPE_FAIL, "Disabled by 'asmjs' runtime option");
    8651             :       case AsmJSOption::DisabledByDebugger:
    8652           0 :         return Warn(parser, JSMSG_USE_ASM_TYPE_FAIL, "Disabled by debugger");
    8653             :       case AsmJSOption::Enabled:
    8654           0 :         break;
    8655             :     }
    8656             : 
    8657           0 :     if (parser.pc->isStarGenerator() || parser.pc->isLegacyGenerator())
    8658           0 :         return Warn(parser, JSMSG_USE_ASM_TYPE_FAIL, "Disabled by generator context");
    8659             : 
    8660           0 :     if (parser.pc->isAsync())
    8661           0 :         return Warn(parser, JSMSG_USE_ASM_TYPE_FAIL, "Disabled by async context");
    8662             : 
    8663           0 :     if (parser.pc->isArrowFunction())
    8664           0 :         return Warn(parser, JSMSG_USE_ASM_TYPE_FAIL, "Disabled by arrow function context");
    8665             : 
    8666             :     // Class constructors are also methods
    8667           0 :     if (parser.pc->isMethod())
    8668           0 :         return Warn(parser, JSMSG_USE_ASM_TYPE_FAIL, "Disabled by class constructor or method context");
    8669             : 
    8670           0 :     return true;
    8671             : }
    8672             : 
    8673             : static UniqueChars
    8674           0 : BuildConsoleMessage(JSContext* cx, unsigned time, JS::AsmJSCacheResult cacheResult)
    8675             : {
    8676             : #ifndef JS_MORE_DETERMINISTIC
    8677           0 :     const char* cacheString = "";
    8678           0 :     switch (cacheResult) {
    8679             :       case JS::AsmJSCache_Success:
    8680           0 :         cacheString = "stored in cache";
    8681           0 :         break;
    8682             :       case JS::AsmJSCache_ModuleTooSmall:
    8683           0 :         cacheString = "not stored in cache (too small to benefit)";
    8684           0 :         break;
    8685             :       case JS::AsmJSCache_SynchronousScript:
    8686           0 :         cacheString = "unable to cache asm.js in synchronous scripts; try loading "
    8687             :                       "asm.js via <script async> or createElement('script')";
    8688           0 :         break;
    8689             :       case JS::AsmJSCache_QuotaExceeded:
    8690           0 :         cacheString = "not enough temporary storage quota to store in cache";
    8691           0 :         break;
    8692             :       case JS::AsmJSCache_StorageInitFailure:
    8693           0 :         cacheString = "storage initialization failed (consider filing a bug)";
    8694           0 :         break;
    8695             :       case JS::AsmJSCache_Disabled_Internal:
    8696           0 :         cacheString = "caching disabled by internal configuration (consider filing a bug)";
    8697           0 :         break;
    8698             :       case JS::AsmJSCache_Disabled_ShellFlags:
    8699           0 :         cacheString = "caching disabled by missing command-line arguments";
    8700           0 :         break;
    8701             :       case JS::AsmJSCache_Disabled_JitInspector:
    8702           0 :         cacheString = "caching disabled by active JIT inspector";
    8703           0 :         break;
    8704             :       case JS::AsmJSCache_InternalError:
    8705           0 :         cacheString = "unable to store in cache due to internal error (consider filing a bug)";
    8706           0 :         break;
    8707             :       case JS::AsmJSCache_Disabled_PrivateBrowsing:
    8708           0 :         cacheString = "caching disabled by private browsing mode";
    8709           0 :         break;
    8710             :       case JS::AsmJSCache_LIMIT:
    8711           0 :         MOZ_CRASH("bad AsmJSCacheResult");
    8712             :         break;
    8713             :     }
    8714             : 
    8715           0 :     return JS_smprintf("total compilation time %dms; %s", time, cacheString);
    8716             : #else
    8717             :     return DuplicateString("");
    8718             : #endif
    8719             : }
    8720             : 
    8721             : bool
    8722           0 : js::CompileAsmJS(JSContext* cx, AsmJSParser& parser, ParseNode* stmtList, bool* validated)
    8723             : {
    8724           0 :     *validated = false;
    8725             : 
    8726             :     // Various conditions disable asm.js optimizations.
    8727           0 :     if (!EstablishPreconditions(cx, parser))
    8728           0 :         return NoExceptionPending(cx);
    8729             : 
    8730             :     // Before spending any time parsing the module, try to look it up in the
    8731             :     // embedding's cache using the chars about to be parsed as the key.
    8732             :     bool loadedFromCache;
    8733           0 :     SharedModule module;
    8734           0 :     UniqueChars message;
    8735           0 :     if (!LookupAsmJSModuleInCache(cx, parser, &loadedFromCache, &module, &message))
    8736           0 :         return false;
    8737             : 
    8738             :     // If not present in the cache, parse, validate and generate code in a
    8739             :     // single linear pass over the chars of the asm.js module.
    8740           0 :     if (!loadedFromCache) {
    8741             :         // "Checking" parses, validates and compiles, producing a fully compiled
    8742             :         // WasmModuleObject as result.
    8743             :         unsigned time;
    8744           0 :         module = CheckModule(cx, parser, stmtList, &time);
    8745           0 :         if (!module)
    8746           0 :             return NoExceptionPending(cx);
    8747             : 
    8748             :         // Try to store the AsmJSModule in the embedding's cache. The
    8749             :         // AsmJSModule must be stored before static linking since static linking
    8750             :         // specializes the AsmJSModule to the current process's address space
    8751             :         // and therefore must be executed after a cache hit.
    8752           0 :         JS::AsmJSCacheResult cacheResult = StoreAsmJSModuleInCache(parser, *module, cx);
    8753             : 
    8754             :         // Build the string message to display in the developer console.
    8755           0 :         message = BuildConsoleMessage(cx, time, cacheResult);
    8756           0 :         if (!message)
    8757           0 :             return NoExceptionPending(cx);
    8758             :     }
    8759             : 
    8760             :     // Hand over ownership to a GC object wrapper which can then be referenced
    8761             :     // from the module function.
    8762           0 :     Rooted<WasmModuleObject*> moduleObj(cx, WasmModuleObject::create(cx, *module));
    8763           0 :     if (!moduleObj)
    8764           0 :         return false;
    8765             : 
    8766             :     // The module function dynamically links the AsmJSModule when called and
    8767             :     // generates a set of functions wrapping all the exports.
    8768           0 :     FunctionBox* funbox = parser.pc->functionBox();
    8769           0 :     RootedFunction moduleFun(cx, NewAsmJSModuleFunction(cx, funbox->function(), moduleObj));
    8770           0 :     if (!moduleFun)
    8771           0 :         return false;
    8772             : 
    8773             :     // Finished! Clobber the default function created by the parser with the new
    8774             :     // asm.js module function. Special cases in the bytecode emitter avoid
    8775             :     // generating bytecode for asm.js functions, allowing this asm.js module
    8776             :     // function to be the finished result.
    8777           0 :     MOZ_ASSERT(funbox->function()->isInterpreted());
    8778           0 :     funbox->object = moduleFun;
    8779             : 
    8780             :     // Success! Write to the console with a "warning" message.
    8781           0 :     *validated = true;
    8782           0 :     Warn(parser, JSMSG_USE_ASM_TYPE_OK, message.get());
    8783           0 :     return NoExceptionPending(cx);
    8784             : }
    8785             : 
    8786             : /*****************************************************************************/
    8787             : // asm.js testing functions
    8788             : 
    8789             : bool
    8790           0 : js::IsAsmJSModuleNative(Native native)
    8791             : {
    8792           0 :     return native == InstantiateAsmJS;
    8793             : }
    8794             : 
    8795             : bool
    8796         958 : js::IsAsmJSModule(JSFunction* fun)
    8797             : {
    8798         958 :     return fun->maybeNative() == InstantiateAsmJS;
    8799             : }
    8800             : 
    8801             : bool
    8802           4 : js::IsAsmJSFunction(JSFunction* fun)
    8803             : {
    8804           4 :     if (IsExportedFunction(fun))
    8805           0 :         return ExportedFunctionToInstance(fun).metadata().isAsmJS();
    8806           4 :     return false;
    8807             : }
    8808             : 
    8809             : bool
    8810           0 : js::IsAsmJSStrictModeModuleOrFunction(JSFunction* fun)
    8811             : {
    8812           0 :     if (IsAsmJSModule(fun))
    8813           0 :         return AsmJSModuleFunctionToModule(fun).metadata().asAsmJS().strict;
    8814             : 
    8815           0 :     if (IsAsmJSFunction(fun))
    8816           0 :         return ExportedFunctionToInstance(fun).metadata().asAsmJS().strict;
    8817             : 
    8818           0 :     return false;
    8819             : }
    8820             : 
    8821             : bool
    8822           0 : js::IsAsmJSCompilationAvailable(JSContext* cx, unsigned argc, Value* vp)
    8823             : {
    8824           0 :     CallArgs args = CallArgsFromVp(argc, vp);
    8825             : 
    8826             :     // See EstablishPreconditions.
    8827           0 :     bool available = HasCompilerSupport(cx) && cx->options().asmJS();
    8828             : 
    8829           0 :     args.rval().set(BooleanValue(available));
    8830           0 :     return true;
    8831             : }
    8832             : 
    8833             : static JSFunction*
    8834           0 : MaybeWrappedNativeFunction(const Value& v)
    8835             : {
    8836           0 :     if (!v.isObject())
    8837           0 :         return nullptr;
    8838             : 
    8839           0 :     JSObject* obj = CheckedUnwrap(&v.toObject());
    8840           0 :     if (!obj)
    8841           0 :         return nullptr;
    8842             : 
    8843           0 :     if (!obj->is<JSFunction>())
    8844           0 :         return nullptr;
    8845             : 
    8846           0 :     return &obj->as<JSFunction>();
    8847             : }
    8848             : 
    8849             : bool
    8850           0 : js::IsAsmJSModule(JSContext* cx, unsigned argc, Value* vp)
    8851             : {
    8852           0 :     CallArgs args = CallArgsFromVp(argc, vp);
    8853             : 
    8854           0 :     bool rval = false;
    8855           0 :     if (JSFunction* fun = MaybeWrappedNativeFunction(args.get(0)))
    8856           0 :         rval = IsAsmJSModule(fun);
    8857             : 
    8858           0 :     args.rval().set(BooleanValue(rval));
    8859           0 :     return true;
    8860             : }
    8861             : 
    8862             : bool
    8863           0 : js::IsAsmJSFunction(JSContext* cx, unsigned argc, Value* vp)
    8864             : {
    8865           0 :     CallArgs args = CallArgsFromVp(argc, vp);
    8866             : 
    8867           0 :     bool rval = false;
    8868           0 :     if (JSFunction* fun = MaybeWrappedNativeFunction(args.get(0)))
    8869           0 :         rval = IsAsmJSFunction(fun);
    8870             : 
    8871           0 :     args.rval().set(BooleanValue(rval));
    8872           0 :     return true;
    8873             : }
    8874             : 
    8875             : bool
    8876           0 : js::IsAsmJSModuleLoadedFromCache(JSContext* cx, unsigned argc, Value* vp)
    8877             : {
    8878           0 :     CallArgs args = CallArgsFromVp(argc, vp);
    8879             : 
    8880           0 :     JSFunction* fun = MaybeWrappedNativeFunction(args.get(0));
    8881           0 :     if (!fun || !IsAsmJSModule(fun)) {
    8882             :         JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr, JSMSG_USE_ASM_TYPE_FAIL,
    8883             :                                   "argument passed to isAsmJSModuleLoadedFromCache is not a "
    8884           0 :                                   "validated asm.js module");
    8885           0 :         return false;
    8886             :     }
    8887             : 
    8888             :     bool loadedFromCache =
    8889           0 :         AsmJSModuleFunctionToModule(fun).metadata().asAsmJS().cacheResult == CacheResult::Hit;
    8890             : 
    8891           0 :     args.rval().set(BooleanValue(loadedFromCache));
    8892           0 :     return true;
    8893             : }
    8894             : 
    8895             : /*****************************************************************************/
    8896             : // asm.js toString/toSource support
    8897             : 
    8898             : JSString*
    8899           0 : js::AsmJSModuleToString(JSContext* cx, HandleFunction fun, bool addParenToLambda)
    8900             : {
    8901           0 :     MOZ_ASSERT(IsAsmJSModule(fun));
    8902             : 
    8903           0 :     const AsmJSMetadata& metadata = AsmJSModuleFunctionToModule(fun).metadata().asAsmJS();
    8904           0 :     uint32_t begin = metadata.toStringStart;
    8905           0 :     uint32_t end = metadata.srcEndAfterCurly();
    8906           0 :     ScriptSource* source = metadata.scriptSource.get();
    8907             : 
    8908           0 :     StringBuffer out(cx);
    8909             : 
    8910           0 :     if (addParenToLambda && fun->isLambda() && !out.append("("))
    8911           0 :         return nullptr;
    8912             : 
    8913           0 :     bool haveSource = source->hasSourceData();
    8914           0 :     if (!haveSource && !JSScript::loadSource(cx, source, &haveSource))
    8915           0 :         return nullptr;
    8916             : 
    8917           0 :     if (!haveSource) {
    8918           0 :         if (!out.append("function "))
    8919           0 :             return nullptr;
    8920           0 :          if (fun->explicitName() && !out.append(fun->explicitName()))
    8921           0 :              return nullptr;
    8922           0 :         if (!out.append("() {\n    [sourceless code]\n}"))
    8923           0 :             return nullptr;
    8924             :     } else {
    8925           0 :         Rooted<JSFlatString*> src(cx, source->substring(cx, begin, end));
    8926           0 :         if (!src)
    8927           0 :             return nullptr;
    8928             : 
    8929           0 :         if (!out.append(src))
    8930           0 :             return nullptr;
    8931             :     }
    8932             : 
    8933           0 :     if (addParenToLambda && fun->isLambda() && !out.append(")"))
    8934           0 :         return nullptr;
    8935             : 
    8936           0 :     return out.finishString();
    8937             : }
    8938             : 
    8939             : JSString*
    8940           0 : js::AsmJSFunctionToString(JSContext* cx, HandleFunction fun)
    8941             : {
    8942           0 :     MOZ_ASSERT(IsAsmJSFunction(fun));
    8943             : 
    8944           0 :     const AsmJSMetadata& metadata = ExportedFunctionToInstance(fun).metadata().asAsmJS();
    8945           0 :     const AsmJSExport& f = metadata.lookupAsmJSExport(ExportedFunctionToFuncIndex(fun));
    8946             : 
    8947           0 :     uint32_t begin = metadata.srcStart + f.startOffsetInModule();
    8948           0 :     uint32_t end = metadata.srcStart + f.endOffsetInModule();
    8949             : 
    8950           0 :     ScriptSource* source = metadata.scriptSource.get();
    8951           0 :     StringBuffer out(cx);
    8952             : 
    8953           0 :     if (!out.append("function "))
    8954           0 :         return nullptr;
    8955             : 
    8956           0 :     bool haveSource = source->hasSourceData();
    8957           0 :     if (!haveSource && !JSScript::loadSource(cx, source, &haveSource))
    8958           0 :         return nullptr;
    8959             : 
    8960           0 :     if (!haveSource) {
    8961             :         // asm.js functions can't be anonymous
    8962           0 :         MOZ_ASSERT(fun->explicitName());
    8963           0 :         if (!out.append(fun->explicitName()))
    8964           0 :             return nullptr;
    8965           0 :         if (!out.append("() {\n    [sourceless code]\n}"))
    8966           0 :             return nullptr;
    8967             :     } else {
    8968           0 :         Rooted<JSFlatString*> src(cx, source->substring(cx, begin, end));
    8969           0 :         if (!src)
    8970           0 :             return nullptr;
    8971           0 :         if (!out.append(src))
    8972           0 :             return nullptr;
    8973             :     }
    8974             : 
    8975           0 :     return out.finishString();
    8976             : }
    8977             : 
    8978             : bool
    8979           0 : js::IsValidAsmJSHeapLength(uint32_t length)
    8980             : {
    8981           0 :     if (length < MinHeapLength)
    8982           0 :         return false;
    8983             : 
    8984           0 :     return wasm::IsValidARMImmediate(length);
    8985             : }

Generated by: LCOV version 1.13