"Fossies" - the Fresh Open Source Software Archive

Member "UXP-2019.06.08/js/src/wasm/AsmJS.cpp" (8 Jun 2019, 288721 Bytes) of package /linux/www/UXP-2019.06.08.tar.gz:


As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) C and C++ source code syntax highlighting (style: standard) with prefixed line numbers and code folding option. Alternatively you can here view or download the uninterpreted source code file. See also the latest Fossies "Diffs" side-by-side code changes report for "AsmJS.cpp": 2019.03.27_vs_2019.06.08.

    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 
   26 #include "jsmath.h"
   27 #include "jsprf.h"
   28 #include "jsstr.h"
   29 #include "jsutil.h"
   30 
   31 #include "jswrapper.h"
   32 
   33 #include "builtin/SIMD.h"
   34 #include "frontend/Parser.h"
   35 #include "gc/Policy.h"
   36 #include "js/MemoryMetrics.h"
   37 #include "vm/StringBuffer.h"
   38 #include "vm/Time.h"
   39 #include "vm/TypedArrayObject.h"
   40 #include "wasm/WasmBinaryFormat.h"
   41 #include "wasm/WasmGenerator.h"
   42 #include "wasm/WasmInstance.h"
   43 #include "wasm/WasmJS.h"
   44 #include "wasm/WasmSerialize.h"
   45 
   46 #include "jsobjinlines.h"
   47 
   48 #include "frontend/ParseNode-inl.h"
   49 #include "vm/ArrayBufferObject-inl.h"
   50 
   51 using namespace js;
   52 using namespace js::frontend;
   53 using namespace js::jit;
   54 using namespace js::wasm;
   55 
   56 using mozilla::CeilingLog2;
   57 using mozilla::Compression::LZ4;
   58 using mozilla::HashGeneric;
   59 using mozilla::IsNaN;
   60 using mozilla::IsNegativeZero;
   61 using mozilla::IsPowerOfTwo;
   62 using mozilla::Maybe;
   63 using mozilla::Move;
   64 using mozilla::PodCopy;
   65 using mozilla::PodEqual;
   66 using mozilla::PodZero;
   67 using mozilla::PositiveInfinity;
   68 using JS::AsmJSOption;
   69 using JS::GenericNaN;
   70 
   71 /*****************************************************************************/
   72 
   73 // The asm.js valid heap lengths are precisely the WASM valid heap lengths for ARM
   74 // greater or equal to MinHeapLength
   75 static const size_t MinHeapLength = PageSize;
   76 
   77 static uint32_t
   78 RoundUpToNextValidAsmJSHeapLength(uint32_t length)
   79 {
   80     if (length <= MinHeapLength)
   81         return MinHeapLength;
   82 
   83     return wasm::RoundUpToNextValidARMImmediate(length);
   84 }
   85 
   86 
   87 /*****************************************************************************/
   88 // asm.js module object
   89 
   90 // The asm.js spec recognizes this set of builtin Math functions.
   91 enum AsmJSMathBuiltinFunction
   92 {
   93     AsmJSMathBuiltin_sin, AsmJSMathBuiltin_cos, AsmJSMathBuiltin_tan,
   94     AsmJSMathBuiltin_asin, AsmJSMathBuiltin_acos, AsmJSMathBuiltin_atan,
   95     AsmJSMathBuiltin_ceil, AsmJSMathBuiltin_floor, AsmJSMathBuiltin_exp,
   96     AsmJSMathBuiltin_log, AsmJSMathBuiltin_pow, AsmJSMathBuiltin_sqrt,
   97     AsmJSMathBuiltin_abs, AsmJSMathBuiltin_atan2, AsmJSMathBuiltin_imul,
   98     AsmJSMathBuiltin_fround, AsmJSMathBuiltin_min, AsmJSMathBuiltin_max,
   99     AsmJSMathBuiltin_clz32
  100 };
  101 
  102 // The asm.js spec will recognize this set of builtin Atomics functions.
  103 enum AsmJSAtomicsBuiltinFunction
  104 {
  105     AsmJSAtomicsBuiltin_compareExchange,
  106     AsmJSAtomicsBuiltin_exchange,
  107     AsmJSAtomicsBuiltin_load,
  108     AsmJSAtomicsBuiltin_store,
  109     AsmJSAtomicsBuiltin_add,
  110     AsmJSAtomicsBuiltin_sub,
  111     AsmJSAtomicsBuiltin_and,
  112     AsmJSAtomicsBuiltin_or,
  113     AsmJSAtomicsBuiltin_xor,
  114     AsmJSAtomicsBuiltin_isLockFree
  115 };
  116 
  117 
  118 // An AsmJSGlobal represents a JS global variable in the asm.js module function.
  119 class AsmJSGlobal
  120 {
  121   public:
  122     enum Which { Variable, FFI, ArrayView, ArrayViewCtor, MathBuiltinFunction,
  123                  AtomicsBuiltinFunction, Constant, SimdCtor, SimdOp };
  124     enum VarInitKind { InitConstant, InitImport };
  125     enum ConstantKind { GlobalConstant, MathConstant };
  126 
  127   private:
  128     struct CacheablePod {
  129         Which which_;
  130         union V {
  131             struct {
  132                 VarInitKind initKind_;
  133                 union U {
  134                     ValType importType_;
  135                     Val val_;
  136                     U() {}
  137                 } u;
  138             } var;
  139             uint32_t ffiIndex_;
  140             Scalar::Type viewType_;
  141             AsmJSMathBuiltinFunction mathBuiltinFunc_;
  142             AsmJSAtomicsBuiltinFunction atomicsBuiltinFunc_;
  143             SimdType simdCtorType_;
  144             struct {
  145                 SimdType type_;
  146                 SimdOperation which_;
  147             } simdOp;
  148             struct {
  149                 ConstantKind kind_;
  150                 double value_;
  151             } constant;
  152             V() {}
  153         } u;
  154     } pod;
  155     CacheableChars field_;
  156 
  157     friend class ModuleValidator;
  158 
  159   public:
  160     AsmJSGlobal() = default;
  161     AsmJSGlobal(Which which, UniqueChars field) {
  162         mozilla::PodZero(&pod);  // zero padding for Valgrind
  163         pod.which_ = which;
  164         field_ = Move(field);
  165     }
  166     const char* field() const {
  167         return field_.get();
  168     }
  169     Which which() const {
  170         return pod.which_;
  171     }
  172     VarInitKind varInitKind() const {
  173         MOZ_ASSERT(pod.which_ == Variable);
  174         return pod.u.var.initKind_;
  175     }
  176     Val varInitVal() const {
  177         MOZ_ASSERT(pod.which_ == Variable);
  178         MOZ_ASSERT(pod.u.var.initKind_ == InitConstant);
  179         return pod.u.var.u.val_;
  180     }
  181     ValType varInitImportType() const {
  182         MOZ_ASSERT(pod.which_ == Variable);
  183         MOZ_ASSERT(pod.u.var.initKind_ == InitImport);
  184         return pod.u.var.u.importType_;
  185     }
  186     uint32_t ffiIndex() const {
  187         MOZ_ASSERT(pod.which_ == FFI);
  188         return pod.u.ffiIndex_;
  189     }
  190     // When a view is created from an imported constructor:
  191     //   var I32 = stdlib.Int32Array;
  192     //   var i32 = new I32(buffer);
  193     // the second import has nothing to validate and thus has a null field.
  194     Scalar::Type viewType() const {
  195         MOZ_ASSERT(pod.which_ == ArrayView || pod.which_ == ArrayViewCtor);
  196         return pod.u.viewType_;
  197     }
  198     AsmJSMathBuiltinFunction mathBuiltinFunction() const {
  199         MOZ_ASSERT(pod.which_ == MathBuiltinFunction);
  200         return pod.u.mathBuiltinFunc_;
  201     }
  202     AsmJSAtomicsBuiltinFunction atomicsBuiltinFunction() const {
  203         MOZ_ASSERT(pod.which_ == AtomicsBuiltinFunction);
  204         return pod.u.atomicsBuiltinFunc_;
  205     }
  206     SimdType simdCtorType() const {
  207         MOZ_ASSERT(pod.which_ == SimdCtor);
  208         return pod.u.simdCtorType_;
  209     }
  210     SimdOperation simdOperation() const {
  211         MOZ_ASSERT(pod.which_ == SimdOp);
  212         return pod.u.simdOp.which_;
  213     }
  214     SimdType simdOperationType() const {
  215         MOZ_ASSERT(pod.which_ == SimdOp);
  216         return pod.u.simdOp.type_;
  217     }
  218     ConstantKind constantKind() const {
  219         MOZ_ASSERT(pod.which_ == Constant);
  220         return pod.u.constant.kind_;
  221     }
  222     double constantValue() const {
  223         MOZ_ASSERT(pod.which_ == Constant);
  224         return pod.u.constant.value_;
  225     }
  226 
  227     WASM_DECLARE_SERIALIZABLE(AsmJSGlobal);
  228 };
  229 
  230 typedef Vector<AsmJSGlobal, 0, SystemAllocPolicy> AsmJSGlobalVector;
  231 
  232 // An AsmJSImport is slightly different than an asm.js FFI function: a single
  233 // asm.js FFI function can be called with many different signatures. When
  234 // compiled to wasm, each unique FFI function paired with signature generates a
  235 // wasm import.
  236 class AsmJSImport
  237 {
  238     uint32_t ffiIndex_;
  239   public:
  240     AsmJSImport() = default;
  241     explicit AsmJSImport(uint32_t ffiIndex) : ffiIndex_(ffiIndex) {}
  242     uint32_t ffiIndex() const { return ffiIndex_; }
  243 };
  244 
  245 typedef Vector<AsmJSImport, 0, SystemAllocPolicy> AsmJSImportVector;
  246 
  247 // An AsmJSExport logically extends Export with the extra information needed for
  248 // an asm.js exported function, viz., the offsets in module's source chars in
  249 // case the function is toString()ed.
  250 class AsmJSExport
  251 {
  252     uint32_t funcIndex_ = 0;
  253 
  254     // All fields are treated as cacheable POD:
  255     uint32_t startOffsetInModule_ = 0;  // Store module-start-relative offsets
  256     uint32_t endOffsetInModule_ = 0;    // so preserved by serialization.
  257 
  258   public:
  259     AsmJSExport() = default;
  260     AsmJSExport(uint32_t funcIndex, uint32_t startOffsetInModule, uint32_t endOffsetInModule)
  261       : funcIndex_(funcIndex),
  262         startOffsetInModule_(startOffsetInModule),
  263         endOffsetInModule_(endOffsetInModule)
  264     {}
  265     uint32_t funcIndex() const {
  266         return funcIndex_;
  267     }
  268     uint32_t startOffsetInModule() const {
  269         return startOffsetInModule_;
  270     }
  271     uint32_t endOffsetInModule() const {
  272         return endOffsetInModule_;
  273     }
  274 };
  275 
  276 typedef Vector<AsmJSExport, 0, SystemAllocPolicy> AsmJSExportVector;
  277 
  278 enum class CacheResult
  279 {
  280     Hit,
  281     Miss
  282 };
  283 
  284 // Holds the immutable guts of an AsmJSModule.
  285 //
  286 // AsmJSMetadata is built incrementally by ModuleValidator and then shared
  287 // immutably between AsmJSModules.
  288 
  289 struct AsmJSMetadataCacheablePod
  290 {
  291     uint32_t                numFFIs = 0;
  292     uint32_t                srcLength = 0;
  293     uint32_t                srcLengthWithRightBrace = 0;
  294     bool                    usesSimd = false;
  295 
  296     AsmJSMetadataCacheablePod() = default;
  297 };
  298 
  299 struct js::AsmJSMetadata : Metadata, AsmJSMetadataCacheablePod
  300 {
  301     AsmJSGlobalVector       asmJSGlobals;
  302     AsmJSImportVector       asmJSImports;
  303     AsmJSExportVector       asmJSExports;
  304     CacheableCharsVector    asmJSFuncNames;
  305     CacheableChars          globalArgumentName;
  306     CacheableChars          importArgumentName;
  307     CacheableChars          bufferArgumentName;
  308 
  309     CacheResult             cacheResult;
  310 
  311     // These values are not serialized since they are relative to the
  312     // containing script which can be different between serialization and
  313     // deserialization contexts. Thus, they must be set explicitly using the
  314     // ambient Parser/ScriptSource after deserialization.
  315     //
  316     // srcStart refers to the offset in the ScriptSource to the beginning of
  317     // the asm.js module function. If the function has been created with the
  318     // Function constructor, this will be the first character in the function
  319     // source. Otherwise, it will be the opening parenthesis of the arguments
  320     // list.
  321     uint32_t                preludeStart;
  322     uint32_t                srcStart;
  323     uint32_t                srcBodyStart;
  324     bool                    strict;
  325     ScriptSourceHolder      scriptSource;
  326 
  327     uint32_t srcEndBeforeCurly() const {
  328         return srcStart + srcLength;
  329     }
  330     uint32_t srcEndAfterCurly() const {
  331         return srcStart + srcLengthWithRightBrace;
  332     }
  333 
  334     AsmJSMetadata()
  335       : Metadata(ModuleKind::AsmJS),
  336         cacheResult(CacheResult::Miss),
  337         srcStart(0),
  338         srcBodyStart(0),
  339         strict(false)
  340     {}
  341     ~AsmJSMetadata() override {}
  342 
  343     const AsmJSExport& lookupAsmJSExport(uint32_t funcIndex) const {
  344         // The AsmJSExportVector isn't stored in sorted order so do a linear
  345         // search. This is for the super-cold and already-expensive toString()
  346         // path and the number of exports is generally small.
  347         for (const AsmJSExport& exp : asmJSExports) {
  348             if (exp.funcIndex() == funcIndex)
  349                 return exp;
  350         }
  351         MOZ_CRASH("missing asm.js func export");
  352     }
  353 
  354     bool mutedErrors() const override {
  355         return scriptSource.get()->mutedErrors();
  356     }
  357     const char16_t* displayURL() const override {
  358         return scriptSource.get()->hasDisplayURL() ? scriptSource.get()->displayURL() : nullptr;
  359     }
  360     ScriptSource* maybeScriptSource() const override {
  361         return scriptSource.get();
  362     }
  363     bool getFuncName(JSContext* cx, const Bytes*, uint32_t funcIndex,
  364                      TwoByteName* name) const override
  365     {
  366         // asm.js doesn't allow exporting imports or putting imports in tables
  367         MOZ_ASSERT(funcIndex >= AsmJSFirstDefFuncIndex);
  368 
  369         const char* p = asmJSFuncNames[funcIndex - AsmJSFirstDefFuncIndex].get();
  370         UTF8Chars utf8(p, strlen(p));
  371 
  372         size_t twoByteLength;
  373         UniqueTwoByteChars chars(JS::UTF8CharsToNewTwoByteCharsZ(cx, utf8, &twoByteLength).get());
  374         if (!chars)
  375             return false;
  376 
  377         if (!name->growByUninitialized(twoByteLength))
  378             return false;
  379 
  380         PodCopy(name->begin(), chars.get(), twoByteLength);
  381         return true;
  382     }
  383 
  384     AsmJSMetadataCacheablePod& pod() { return *this; }
  385     const AsmJSMetadataCacheablePod& pod() const { return *this; }
  386 
  387     WASM_DECLARE_SERIALIZABLE_OVERRIDE(AsmJSMetadata)
  388 };
  389 
  390 typedef RefPtr<AsmJSMetadata> MutableAsmJSMetadata;
  391 
  392 /*****************************************************************************/
  393 // ParseNode utilities
  394 
  395 static inline ParseNode*
  396 NextNode(ParseNode* pn)
  397 {
  398     return pn->pn_next;
  399 }
  400 
  401 static inline ParseNode*
  402 UnaryKid(ParseNode* pn)
  403 {
  404     MOZ_ASSERT(pn->isArity(PN_UNARY));
  405     return pn->pn_kid;
  406 }
  407 
  408 static inline ParseNode*
  409 BinaryRight(ParseNode* pn)
  410 {
  411     MOZ_ASSERT(pn->isArity(PN_BINARY));
  412     return pn->pn_right;
  413 }
  414 
  415 static inline ParseNode*
  416 BinaryLeft(ParseNode* pn)
  417 {
  418     MOZ_ASSERT(pn->isArity(PN_BINARY));
  419     return pn->pn_left;
  420 }
  421 
  422 static inline ParseNode*
  423 ReturnExpr(ParseNode* pn)
  424 {
  425     MOZ_ASSERT(pn->isKind(PNK_RETURN));
  426     return UnaryKid(pn);
  427 }
  428 
  429 static inline ParseNode*
  430 TernaryKid1(ParseNode* pn)
  431 {
  432     MOZ_ASSERT(pn->isArity(PN_TERNARY));
  433     return pn->pn_kid1;
  434 }
  435 
  436 static inline ParseNode*
  437 TernaryKid2(ParseNode* pn)
  438 {
  439     MOZ_ASSERT(pn->isArity(PN_TERNARY));
  440     return pn->pn_kid2;
  441 }
  442 
  443 static inline ParseNode*
  444 TernaryKid3(ParseNode* pn)
  445 {
  446     MOZ_ASSERT(pn->isArity(PN_TERNARY));
  447     return pn->pn_kid3;
  448 }
  449 
  450 static inline ParseNode*
  451 ListHead(ParseNode* pn)
  452 {
  453     MOZ_ASSERT(pn->isArity(PN_LIST));
  454     return pn->pn_head;
  455 }
  456 
  457 static inline unsigned
  458 ListLength(ParseNode* pn)
  459 {
  460     MOZ_ASSERT(pn->isArity(PN_LIST));
  461     return pn->pn_count;
  462 }
  463 
  464 static inline ParseNode*
  465 CallCallee(ParseNode* pn)
  466 {
  467     MOZ_ASSERT(pn->isKind(PNK_CALL));
  468     return ListHead(pn);
  469 }
  470 
  471 static inline unsigned
  472 CallArgListLength(ParseNode* pn)
  473 {
  474     MOZ_ASSERT(pn->isKind(PNK_CALL));
  475     MOZ_ASSERT(ListLength(pn) >= 1);
  476     return ListLength(pn) - 1;
  477 }
  478 
  479 static inline ParseNode*
  480 CallArgList(ParseNode* pn)
  481 {
  482     MOZ_ASSERT(pn->isKind(PNK_CALL));
  483     return NextNode(ListHead(pn));
  484 }
  485 
  486 static inline ParseNode*
  487 VarListHead(ParseNode* pn)
  488 {
  489     MOZ_ASSERT(pn->isKind(PNK_VAR) || pn->isKind(PNK_CONST));
  490     return ListHead(pn);
  491 }
  492 
  493 static inline bool
  494 IsDefaultCase(ParseNode* pn)
  495 {
  496     return pn->as<CaseClause>().isDefault();
  497 }
  498 
  499 static inline ParseNode*
  500 CaseExpr(ParseNode* pn)
  501 {
  502     return pn->as<CaseClause>().caseExpression();
  503 }
  504 
  505 static inline ParseNode*
  506 CaseBody(ParseNode* pn)
  507 {
  508     return pn->as<CaseClause>().statementList();
  509 }
  510 
  511 static inline ParseNode*
  512 BinaryOpLeft(ParseNode* pn)
  513 {
  514     MOZ_ASSERT(pn->isBinaryOperation());
  515     MOZ_ASSERT(pn->isArity(PN_LIST));
  516     MOZ_ASSERT(pn->pn_count == 2);
  517     return ListHead(pn);
  518 }
  519 
  520 static inline ParseNode*
  521 BinaryOpRight(ParseNode* pn)
  522 {
  523     MOZ_ASSERT(pn->isBinaryOperation());
  524     MOZ_ASSERT(pn->isArity(PN_LIST));
  525     MOZ_ASSERT(pn->pn_count == 2);
  526     return NextNode(ListHead(pn));
  527 }
  528 
  529 static inline ParseNode*
  530 BitwiseLeft(ParseNode* pn)
  531 {
  532     return BinaryOpLeft(pn);
  533 }
  534 
  535 static inline ParseNode*
  536 BitwiseRight(ParseNode* pn)
  537 {
  538     return BinaryOpRight(pn);
  539 }
  540 
  541 static inline ParseNode*
  542 MultiplyLeft(ParseNode* pn)
  543 {
  544     MOZ_ASSERT(pn->isKind(PNK_STAR));
  545     return BinaryOpLeft(pn);
  546 }
  547 
  548 static inline ParseNode*
  549 MultiplyRight(ParseNode* pn)
  550 {
  551     MOZ_ASSERT(pn->isKind(PNK_STAR));
  552     return BinaryOpRight(pn);
  553 }
  554 
  555 static inline ParseNode*
  556 AddSubLeft(ParseNode* pn)
  557 {
  558     MOZ_ASSERT(pn->isKind(PNK_ADD) || pn->isKind(PNK_SUB));
  559     return BinaryOpLeft(pn);
  560 }
  561 
  562 static inline ParseNode*
  563 AddSubRight(ParseNode* pn)
  564 {
  565     MOZ_ASSERT(pn->isKind(PNK_ADD) || pn->isKind(PNK_SUB));
  566     return BinaryOpRight(pn);
  567 }
  568 
  569 static inline ParseNode*
  570 DivOrModLeft(ParseNode* pn)
  571 {
  572     MOZ_ASSERT(pn->isKind(PNK_DIV) || pn->isKind(PNK_MOD));
  573     return BinaryOpLeft(pn);
  574 }
  575 
  576 static inline ParseNode*
  577 DivOrModRight(ParseNode* pn)
  578 {
  579     MOZ_ASSERT(pn->isKind(PNK_DIV) || pn->isKind(PNK_MOD));
  580     return BinaryOpRight(pn);
  581 }
  582 
  583 static inline ParseNode*
  584 ComparisonLeft(ParseNode* pn)
  585 {
  586     return BinaryOpLeft(pn);
  587 }
  588 
  589 static inline ParseNode*
  590 ComparisonRight(ParseNode* pn)
  591 {
  592     return BinaryOpRight(pn);
  593 }
  594 
  595 static inline bool
  596 IsExpressionStatement(ParseNode* pn)
  597 {
  598     return pn->isKind(PNK_SEMI);
  599 }
  600 
  601 static inline ParseNode*
  602 ExpressionStatementExpr(ParseNode* pn)
  603 {
  604     MOZ_ASSERT(pn->isKind(PNK_SEMI));
  605     return UnaryKid(pn);
  606 }
  607 
  608 static inline PropertyName*
  609 LoopControlMaybeLabel(ParseNode* pn)
  610 {
  611     MOZ_ASSERT(pn->isKind(PNK_BREAK) || pn->isKind(PNK_CONTINUE));
  612     MOZ_ASSERT(pn->isArity(PN_NULLARY));
  613     return pn->as<LoopControlStatement>().label();
  614 }
  615 
  616 static inline PropertyName*
  617 LabeledStatementLabel(ParseNode* pn)
  618 {
  619     return pn->as<LabeledStatement>().label();
  620 }
  621 
  622 static inline ParseNode*
  623 LabeledStatementStatement(ParseNode* pn)
  624 {
  625     return pn->as<LabeledStatement>().statement();
  626 }
  627 
  628 static double
  629 NumberNodeValue(ParseNode* pn)
  630 {
  631     MOZ_ASSERT(pn->isKind(PNK_NUMBER));
  632     return pn->pn_dval;
  633 }
  634 
  635 static bool
  636 NumberNodeHasFrac(ParseNode* pn)
  637 {
  638     MOZ_ASSERT(pn->isKind(PNK_NUMBER));
  639     return pn->pn_u.number.decimalPoint == HasDecimal;
  640 }
  641 
  642 static ParseNode*
  643 DotBase(ParseNode* pn)
  644 {
  645     MOZ_ASSERT(pn->isKind(PNK_DOT));
  646     MOZ_ASSERT(pn->isArity(PN_NAME));
  647     return pn->expr();
  648 }
  649 
  650 static PropertyName*
  651 DotMember(ParseNode* pn)
  652 {
  653     MOZ_ASSERT(pn->isKind(PNK_DOT));
  654     MOZ_ASSERT(pn->isArity(PN_NAME));
  655     return pn->pn_atom->asPropertyName();
  656 }
  657 
  658 static ParseNode*
  659 ElemBase(ParseNode* pn)
  660 {
  661     MOZ_ASSERT(pn->isKind(PNK_ELEM));
  662     return BinaryLeft(pn);
  663 }
  664 
  665 static ParseNode*
  666 ElemIndex(ParseNode* pn)
  667 {
  668     MOZ_ASSERT(pn->isKind(PNK_ELEM));
  669     return BinaryRight(pn);
  670 }
  671 
  672 static inline JSFunction*
  673 FunctionObject(ParseNode* fn)
  674 {
  675     MOZ_ASSERT(fn->isKind(PNK_FUNCTION));
  676     MOZ_ASSERT(fn->isArity(PN_CODE));
  677     return fn->pn_funbox->function();
  678 }
  679 
  680 static inline PropertyName*
  681 FunctionName(ParseNode* fn)
  682 {
  683     if (JSAtom* name = FunctionObject(fn)->explicitName())
  684         return name->asPropertyName();
  685     return nullptr;
  686 }
  687 
  688 static inline ParseNode*
  689 FunctionStatementList(ParseNode* fn)
  690 {
  691     MOZ_ASSERT(fn->pn_body->isKind(PNK_PARAMSBODY));
  692     ParseNode* last = fn->pn_body->last();
  693     MOZ_ASSERT(last->isKind(PNK_LEXICALSCOPE));
  694     MOZ_ASSERT(last->isEmptyScope());
  695     ParseNode* body = last->scopeBody();
  696     MOZ_ASSERT(body->isKind(PNK_STATEMENTLIST));
  697     return body;
  698 }
  699 
  700 static inline bool
  701 IsNormalObjectField(ExclusiveContext* cx, ParseNode* pn)
  702 {
  703     return pn->isKind(PNK_COLON) &&
  704            pn->getOp() == JSOP_INITPROP &&
  705            BinaryLeft(pn)->isKind(PNK_OBJECT_PROPERTY_NAME);
  706 }
  707 
  708 static inline PropertyName*
  709 ObjectNormalFieldName(ExclusiveContext* cx, ParseNode* pn)
  710 {
  711     MOZ_ASSERT(IsNormalObjectField(cx, pn));
  712     MOZ_ASSERT(BinaryLeft(pn)->isKind(PNK_OBJECT_PROPERTY_NAME));
  713     return BinaryLeft(pn)->pn_atom->asPropertyName();
  714 }
  715 
  716 static inline ParseNode*
  717 ObjectNormalFieldInitializer(ExclusiveContext* cx, ParseNode* pn)
  718 {
  719     MOZ_ASSERT(IsNormalObjectField(cx, pn));
  720     return BinaryRight(pn);
  721 }
  722 
  723 static inline ParseNode*
  724 MaybeInitializer(ParseNode* pn)
  725 {
  726     return pn->expr();
  727 }
  728 
  729 static inline bool
  730 IsUseOfName(ParseNode* pn, PropertyName* name)
  731 {
  732     return pn->isKind(PNK_NAME) && pn->name() == name;
  733 }
  734 
  735 static inline bool
  736 IsIgnoredDirectiveName(ExclusiveContext* cx, JSAtom* atom)
  737 {
  738     return atom != cx->names().useStrict;
  739 }
  740 
  741 static inline bool
  742 IsIgnoredDirective(ExclusiveContext* cx, ParseNode* pn)
  743 {
  744     return pn->isKind(PNK_SEMI) &&
  745            UnaryKid(pn) &&
  746            UnaryKid(pn)->isKind(PNK_STRING) &&
  747            IsIgnoredDirectiveName(cx, UnaryKid(pn)->pn_atom);
  748 }
  749 
  750 static inline bool
  751 IsEmptyStatement(ParseNode* pn)
  752 {
  753     return pn->isKind(PNK_SEMI) && !UnaryKid(pn);
  754 }
  755 
  756 static inline ParseNode*
  757 SkipEmptyStatements(ParseNode* pn)
  758 {
  759     while (pn && IsEmptyStatement(pn))
  760         pn = pn->pn_next;
  761     return pn;
  762 }
  763 
  764 static inline ParseNode*
  765 NextNonEmptyStatement(ParseNode* pn)
  766 {
  767     return SkipEmptyStatements(pn->pn_next);
  768 }
  769 
  770 static bool
  771 GetToken(AsmJSParser& parser, TokenKind* tkp)
  772 {
  773     TokenStream& ts = parser.tokenStream;
  774     TokenKind tk;
  775     while (true) {
  776         if (!ts.getToken(&tk, TokenStream::Operand))
  777             return false;
  778         if (tk != TOK_SEMI)
  779             break;
  780     }
  781     *tkp = tk;
  782     return true;
  783 }
  784 
  785 static bool
  786 PeekToken(AsmJSParser& parser, TokenKind* tkp)
  787 {
  788     TokenStream& ts = parser.tokenStream;
  789     TokenKind tk;
  790     while (true) {
  791         if (!ts.peekToken(&tk, TokenStream::Operand))
  792             return false;
  793         if (tk != TOK_SEMI)
  794             break;
  795         ts.consumeKnownToken(TOK_SEMI, TokenStream::Operand);
  796     }
  797     *tkp = tk;
  798     return true;
  799 }
  800 
  801 static bool
  802 ParseVarOrConstStatement(AsmJSParser& parser, ParseNode** var)
  803 {
  804     TokenKind tk;
  805     if (!PeekToken(parser, &tk))
  806         return false;
  807     if (tk != TOK_VAR && tk != TOK_CONST) {
  808         *var = nullptr;
  809         return true;
  810     }
  811 
  812     *var = parser.statementListItem(YieldIsName);
  813     if (!*var)
  814         return false;
  815 
  816     MOZ_ASSERT((*var)->isKind(PNK_VAR) || (*var)->isKind(PNK_CONST));
  817     return true;
  818 }
  819 
  820 /*****************************************************************************/
  821 
  822 // Represents the type and value of an asm.js numeric literal.
  823 //
  824 // A literal is a double iff the literal contains a decimal point (even if the
  825 // fractional part is 0). Otherwise, integers may be classified:
  826 //  fixnum: [0, 2^31)
  827 //  negative int: [-2^31, 0)
  828 //  big unsigned: [2^31, 2^32)
  829 //  out of range: otherwise
  830 // Lastly, a literal may be a float literal which is any double or integer
  831 // literal coerced with Math.fround.
  832 //
  833 // This class distinguishes between signed and unsigned integer SIMD types like
  834 // Int32x4 and Uint32x4, and so does Type below. The wasm ValType and ExprType
  835 // enums, and the wasm::Val class do not.
  836 class NumLit
  837 {
  838   public:
  839     enum Which {
  840         Fixnum,
  841         NegativeInt,
  842         BigUnsigned,
  843         Double,
  844         Float,
  845         Int8x16,
  846         Int16x8,
  847         Int32x4,
  848         Uint8x16,
  849         Uint16x8,
  850         Uint32x4,
  851         Float32x4,
  852         Bool8x16,
  853         Bool16x8,
  854         Bool32x4,
  855         OutOfRangeInt = -1
  856     };
  857 
  858   private:
  859     Which which_;
  860     union {
  861         JS::UninitializedValue scalar_;
  862         SimdConstant simd_;
  863     } u;
  864 
  865   public:
  866     NumLit() = default;
  867 
  868     NumLit(Which w, const Value& v) : which_(w) {
  869         u.scalar_ = v;
  870         MOZ_ASSERT(!isSimd());
  871     }
  872 
  873     NumLit(Which w, SimdConstant c) : which_(w) {
  874         u.simd_ = c;
  875         MOZ_ASSERT(isSimd());
  876     }
  877 
  878     Which which() const {
  879         return which_;
  880     }
  881 
  882     int32_t toInt32() const {
  883         MOZ_ASSERT(which_ == Fixnum || which_ == NegativeInt || which_ == BigUnsigned);
  884         return u.scalar_.asValueRef().toInt32();
  885     }
  886 
  887     uint32_t toUint32() const {
  888         return (uint32_t)toInt32();
  889     }
  890 
  891     RawF64 toDouble() const {
  892         MOZ_ASSERT(which_ == Double);
  893         return RawF64(u.scalar_.asValueRef().toDouble());
  894     }
  895 
  896     RawF32 toFloat() const {
  897         MOZ_ASSERT(which_ == Float);
  898         return RawF32(float(u.scalar_.asValueRef().toDouble()));
  899     }
  900 
  901     Value scalarValue() const {
  902         MOZ_ASSERT(which_ != OutOfRangeInt);
  903         return u.scalar_.asValueRef();
  904     }
  905 
  906     bool isSimd() const
  907     {
  908         return which_ == Int8x16 || which_ == Uint8x16 || which_ == Int16x8 ||
  909                which_ == Uint16x8 || which_ == Int32x4 || which_ == Uint32x4 ||
  910                which_ == Float32x4 || which_ == Bool8x16 || which_ == Bool16x8 ||
  911                which_ == Bool32x4;
  912     }
  913 
  914     const SimdConstant& simdValue() const {
  915         MOZ_ASSERT(isSimd());
  916         return u.simd_;
  917     }
  918 
  919     bool valid() const {
  920         return which_ != OutOfRangeInt;
  921     }
  922 
  923     bool isZeroBits() const {
  924         MOZ_ASSERT(valid());
  925         switch (which()) {
  926           case NumLit::Fixnum:
  927           case NumLit::NegativeInt:
  928           case NumLit::BigUnsigned:
  929             return toInt32() == 0;
  930           case NumLit::Double:
  931             return toDouble().bits() == 0;
  932           case NumLit::Float:
  933             return toFloat().bits() == 0;
  934           case NumLit::Int8x16:
  935           case NumLit::Uint8x16:
  936           case NumLit::Bool8x16:
  937             return simdValue() == SimdConstant::SplatX16(0);
  938           case NumLit::Int16x8:
  939           case NumLit::Uint16x8:
  940           case NumLit::Bool16x8:
  941             return simdValue() == SimdConstant::SplatX8(0);
  942           case NumLit::Int32x4:
  943           case NumLit::Uint32x4:
  944           case NumLit::Bool32x4:
  945             return simdValue() == SimdConstant::SplatX4(0);
  946           case NumLit::Float32x4:
  947             return simdValue() == SimdConstant::SplatX4(0.f);
  948           case NumLit::OutOfRangeInt:
  949             MOZ_CRASH("can't be here because of valid() check above");
  950         }
  951         return false;
  952     }
  953 
  954     Val value() const {
  955         switch (which_) {
  956           case NumLit::Fixnum:
  957           case NumLit::NegativeInt:
  958           case NumLit::BigUnsigned:
  959             return Val(toUint32());
  960           case NumLit::Float:
  961             return Val(toFloat());
  962           case NumLit::Double:
  963             return Val(toDouble());
  964           case NumLit::Int8x16:
  965           case NumLit::Uint8x16:
  966             return Val(simdValue().asInt8x16());
  967           case NumLit::Int16x8:
  968           case NumLit::Uint16x8:
  969             return Val(simdValue().asInt16x8());
  970           case NumLit::Int32x4:
  971           case NumLit::Uint32x4:
  972             return Val(simdValue().asInt32x4());
  973           case NumLit::Float32x4:
  974             return Val(simdValue().asFloat32x4());
  975           case NumLit::Bool8x16:
  976             return Val(simdValue().asInt8x16(), ValType::B8x16);
  977           case NumLit::Bool16x8:
  978             return Val(simdValue().asInt16x8(), ValType::B16x8);
  979           case NumLit::Bool32x4:
  980             return Val(simdValue().asInt32x4(), ValType::B32x4);
  981           case NumLit::OutOfRangeInt:;
  982         }
  983         MOZ_CRASH("bad literal");
  984     }
  985 };
  986 
  987 // Represents the type of a general asm.js expression.
  988 //
  989 // A canonical subset of types representing the coercion targets: Int, Float,
  990 // Double, and the SIMD types. This is almost equivalent to wasm::ValType,
  991 // except the integer SIMD types have signed/unsigned variants.
  992 //
  993 // Void is also part of the canonical subset which then maps to wasm::ExprType.
  994 //
  995 // Note that while the canonical subset distinguishes signed and unsigned SIMD
  996 // types, it only uses |Int| to represent signed and unsigned 32-bit integers.
  997 // This is because the scalar coersions x|0 and x>>>0 work with any kind of
  998 // integer input, while the SIMD check functions throw a TypeError if the passed
  999 // type doesn't match.
 1000 //
 1001 class Type
 1002 {
 1003   public:
 1004     enum Which {
 1005         Fixnum = NumLit::Fixnum,
 1006         Signed = NumLit::NegativeInt,
 1007         Unsigned = NumLit::BigUnsigned,
 1008         DoubleLit = NumLit::Double,
 1009         Float = NumLit::Float,
 1010         Int8x16 = NumLit::Int8x16,
 1011         Int16x8 = NumLit::Int16x8,
 1012         Int32x4 = NumLit::Int32x4,
 1013         Uint8x16 = NumLit::Uint8x16,
 1014         Uint16x8 = NumLit::Uint16x8,
 1015         Uint32x4 = NumLit::Uint32x4,
 1016         Float32x4 = NumLit::Float32x4,
 1017         Bool8x16 = NumLit::Bool8x16,
 1018         Bool16x8 = NumLit::Bool16x8,
 1019         Bool32x4 = NumLit::Bool32x4,
 1020         Double,
 1021         MaybeDouble,
 1022         MaybeFloat,
 1023         Floatish,
 1024         Int,
 1025         Intish,
 1026         Void
 1027     };
 1028 
 1029   private:
 1030     Which which_;
 1031 
 1032   public:
 1033     Type() = default;
 1034     MOZ_IMPLICIT Type(Which w) : which_(w) {}
 1035     MOZ_IMPLICIT Type(SimdType type) {
 1036         switch (type) {
 1037           case SimdType::Int8x16:   which_ = Int8x16;   return;
 1038           case SimdType::Int16x8:   which_ = Int16x8;   return;
 1039           case SimdType::Int32x4:   which_ = Int32x4;   return;
 1040           case SimdType::Uint8x16:  which_ = Uint8x16;  return;
 1041           case SimdType::Uint16x8:  which_ = Uint16x8;  return;
 1042           case SimdType::Uint32x4:  which_ = Uint32x4;  return;
 1043           case SimdType::Float32x4: which_ = Float32x4; return;
 1044           case SimdType::Bool8x16:  which_ = Bool8x16;  return;
 1045           case SimdType::Bool16x8:  which_ = Bool16x8;  return;
 1046           case SimdType::Bool32x4:  which_ = Bool32x4;  return;
 1047           default:                  break;
 1048         }
 1049         MOZ_MAKE_COMPILER_ASSUME_IS_UNREACHABLE("bad SimdType");
 1050     }
 1051 
 1052     // Map an already canonicalized Type to the return type of a function call.
 1053     static Type ret(Type t) {
 1054         MOZ_ASSERT(t.isCanonical());
 1055         // The 32-bit external type is Signed, not Int.
 1056         return t.isInt() ? Signed: t;
 1057     }
 1058 
 1059     static Type lit(const NumLit& lit) {
 1060         MOZ_ASSERT(lit.valid());
 1061         Which which = Type::Which(lit.which());
 1062         MOZ_ASSERT(which >= Fixnum && which <= Bool32x4);
 1063         Type t;
 1064         t.which_ = which;
 1065         return t;
 1066     }
 1067 
 1068     // Map |t| to one of the canonical vartype representations of a
 1069     // wasm::ExprType.
 1070     static Type canonicalize(Type t) {
 1071         switch(t.which()) {
 1072           case Fixnum:
 1073           case Signed:
 1074           case Unsigned:
 1075           case Int:
 1076             return Int;
 1077 
 1078           case Float:
 1079             return Float;
 1080 
 1081           case DoubleLit:
 1082           case Double:
 1083             return Double;
 1084 
 1085           case Void:
 1086             return Void;
 1087 
 1088           case Int8x16:
 1089           case Int16x8:
 1090           case Int32x4:
 1091           case Uint8x16:
 1092           case Uint16x8:
 1093           case Uint32x4:
 1094           case Float32x4:
 1095           case Bool8x16:
 1096           case Bool16x8:
 1097           case Bool32x4:
 1098             return t;
 1099 
 1100           case MaybeDouble:
 1101           case MaybeFloat:
 1102           case Floatish:
 1103           case Intish:
 1104             // These types need some kind of coercion, they can't be mapped
 1105             // to an ExprType.
 1106             break;
 1107         }
 1108         MOZ_CRASH("Invalid vartype");
 1109     }
 1110 
 1111     Which which() const { return which_; }
 1112 
 1113     bool operator==(Type rhs) const { return which_ == rhs.which_; }
 1114     bool operator!=(Type rhs) const { return which_ != rhs.which_; }
 1115 
 1116     bool operator<=(Type rhs) const {
 1117         switch (rhs.which_) {
 1118           case Signed:      return isSigned();
 1119           case Unsigned:    return isUnsigned();
 1120           case DoubleLit:   return isDoubleLit();
 1121           case Double:      return isDouble();
 1122           case Float:       return isFloat();
 1123           case Int8x16:     return isInt8x16();
 1124           case Int16x8:     return isInt16x8();
 1125           case Int32x4:     return isInt32x4();
 1126           case Uint8x16:    return isUint8x16();
 1127           case Uint16x8:    return isUint16x8();
 1128           case Uint32x4:    return isUint32x4();
 1129           case Float32x4:   return isFloat32x4();
 1130           case Bool8x16:    return isBool8x16();
 1131           case Bool16x8:    return isBool16x8();
 1132           case Bool32x4:    return isBool32x4();
 1133           case MaybeDouble: return isMaybeDouble();
 1134           case MaybeFloat:  return isMaybeFloat();
 1135           case Floatish:    return isFloatish();
 1136           case Int:         return isInt();
 1137           case Intish:      return isIntish();
 1138           case Fixnum:      return isFixnum();
 1139           case Void:        return isVoid();
 1140         }
 1141         MOZ_MAKE_COMPILER_ASSUME_IS_UNREACHABLE("unexpected rhs type");
 1142     }
 1143 
 1144     bool isFixnum() const {
 1145         return which_ == Fixnum;
 1146     }
 1147 
 1148     bool isSigned() const {
 1149         return which_ == Signed || which_ == Fixnum;
 1150     }
 1151 
 1152     bool isUnsigned() const {
 1153         return which_ == Unsigned || which_ == Fixnum;
 1154     }
 1155 
 1156     bool isInt() const {
 1157         return isSigned() || isUnsigned() || which_ == Int;
 1158     }
 1159 
 1160     bool isIntish() const {
 1161         return isInt() || which_ == Intish;
 1162     }
 1163 
 1164     bool isDoubleLit() const {
 1165         return which_ == DoubleLit;
 1166     }
 1167 
 1168     bool isDouble() const {
 1169         return isDoubleLit() || which_ == Double;
 1170     }
 1171 
 1172     bool isMaybeDouble() const {
 1173         return isDouble() || which_ == MaybeDouble;
 1174     }
 1175 
 1176     bool isFloat() const {
 1177         return which_ == Float;
 1178     }
 1179 
 1180     bool isMaybeFloat() const {
 1181         return isFloat() || which_ == MaybeFloat;
 1182     }
 1183 
 1184     bool isFloatish() const {
 1185         return isMaybeFloat() || which_ == Floatish;
 1186     }
 1187 
 1188     bool isVoid() const {
 1189         return which_ == Void;
 1190     }
 1191 
 1192     bool isExtern() const {
 1193         return isDouble() || isSigned();
 1194     }
 1195 
 1196     bool isInt8x16() const {
 1197         return which_ == Int8x16;
 1198     }
 1199 
 1200     bool isInt16x8() const {
 1201         return which_ == Int16x8;
 1202     }
 1203 
 1204     bool isInt32x4() const {
 1205         return which_ == Int32x4;
 1206     }
 1207 
 1208     bool isUint8x16() const {
 1209         return which_ == Uint8x16;
 1210     }
 1211 
 1212     bool isUint16x8() const {
 1213         return which_ == Uint16x8;
 1214     }
 1215 
 1216     bool isUint32x4() const {
 1217         return which_ == Uint32x4;
 1218     }
 1219 
 1220     bool isFloat32x4() const {
 1221         return which_ == Float32x4;
 1222     }
 1223 
 1224     bool isBool8x16() const {
 1225         return which_ == Bool8x16;
 1226     }
 1227 
 1228     bool isBool16x8() const {
 1229         return which_ == Bool16x8;
 1230     }
 1231 
 1232     bool isBool32x4() const {
 1233         return which_ == Bool32x4;
 1234     }
 1235 
 1236     bool isSimd() const {
 1237         return isInt8x16() || isInt16x8() || isInt32x4() || isUint8x16() || isUint16x8() ||
 1238                isUint32x4() || isFloat32x4() || isBool8x16() || isBool16x8() || isBool32x4();
 1239     }
 1240 
 1241     bool isUnsignedSimd() const {
 1242         return isUint8x16() || isUint16x8() || isUint32x4();
 1243     }
 1244 
 1245     // Check if this is one of the valid types for a function argument.
 1246     bool isArgType() const {
 1247         return isInt() || isFloat() || isDouble() || (isSimd() && !isUnsignedSimd());
 1248     }
 1249 
 1250     // Check if this is one of the valid types for a function return value.
 1251     bool isReturnType() const {
 1252         return isSigned() || isFloat() || isDouble() || (isSimd() && !isUnsignedSimd()) ||
 1253                isVoid();
 1254     }
 1255 
 1256     // Check if this is one of the valid types for a global variable.
 1257     bool isGlobalVarType() const {
 1258         return isArgType();
 1259     }
 1260 
 1261     // Check if this is one of the canonical vartype representations of a
 1262     // wasm::ExprType. See Type::canonicalize().
 1263     bool isCanonical() const {
 1264         switch (which()) {
 1265           case Int:
 1266           case Float:
 1267           case Double:
 1268           case Void:
 1269             return true;
 1270           default:
 1271             return isSimd();
 1272         }
 1273     }
 1274 
 1275     // Check if this is a canonical representation of a wasm::ValType.
 1276     bool isCanonicalValType() const {
 1277         return !isVoid() && isCanonical();
 1278     }
 1279 
 1280     // Convert this canonical type to a wasm::ExprType.
 1281     ExprType canonicalToExprType() const {
 1282         switch (which()) {
 1283           case Int:       return ExprType::I32;
 1284           case Float:     return ExprType::F32;
 1285           case Double:    return ExprType::F64;
 1286           case Void:      return ExprType::Void;
 1287           case Uint8x16:
 1288           case Int8x16:   return ExprType::I8x16;
 1289           case Uint16x8:
 1290           case Int16x8:   return ExprType::I16x8;
 1291           case Uint32x4:
 1292           case Int32x4:   return ExprType::I32x4;
 1293           case Float32x4: return ExprType::F32x4;
 1294           case Bool8x16:  return ExprType::B8x16;
 1295           case Bool16x8:  return ExprType::B16x8;
 1296           case Bool32x4:  return ExprType::B32x4;
 1297           default:        MOZ_CRASH("Need canonical type");
 1298         }
 1299     }
 1300 
 1301     // Convert this canonical type to a wasm::ValType.
 1302     ValType canonicalToValType() const {
 1303         return NonVoidToValType(canonicalToExprType());
 1304     }
 1305 
 1306     // Convert this type to a wasm::ExprType for use in a wasm
 1307     // block signature. This works for all types, including non-canonical
 1308     // ones. Consequently, the type isn't valid for subsequent asm.js
 1309     // validation; it's only valid for use in producing wasm.
 1310     ExprType toWasmBlockSignatureType() const {
 1311         switch (which()) {
 1312           case Fixnum:
 1313           case Signed:
 1314           case Unsigned:
 1315           case Int:
 1316           case Intish:
 1317             return ExprType::I32;
 1318 
 1319           case Float:
 1320           case MaybeFloat:
 1321           case Floatish:
 1322             return ExprType::F32;
 1323 
 1324           case DoubleLit:
 1325           case Double:
 1326           case MaybeDouble:
 1327             return ExprType::F64;
 1328 
 1329           case Void:
 1330             return ExprType::Void;
 1331 
 1332           case Uint8x16:
 1333           case Int8x16:   return ExprType::I8x16;
 1334           case Uint16x8:
 1335           case Int16x8:   return ExprType::I16x8;
 1336           case Uint32x4:
 1337           case Int32x4:   return ExprType::I32x4;
 1338           case Float32x4: return ExprType::F32x4;
 1339           case Bool8x16:  return ExprType::B8x16;
 1340           case Bool16x8:  return ExprType::B16x8;
 1341           case Bool32x4:  return ExprType::B32x4;
 1342         }
 1343         MOZ_CRASH("Invalid Type");
 1344     }
 1345 
 1346     const char* toChars() const {
 1347         switch (which_) {
 1348           case Double:      return "double";
 1349           case DoubleLit:   return "doublelit";
 1350           case MaybeDouble: return "double?";
 1351           case Float:       return "float";
 1352           case Floatish:    return "floatish";
 1353           case MaybeFloat:  return "float?";
 1354           case Fixnum:      return "fixnum";
 1355           case Int:         return "int";
 1356           case Signed:      return "signed";
 1357           case Unsigned:    return "unsigned";
 1358           case Intish:      return "intish";
 1359           case Int8x16:     return "int8x16";
 1360           case Int16x8:     return "int16x8";
 1361           case Int32x4:     return "int32x4";
 1362           case Uint8x16:    return "uint8x16";
 1363           case Uint16x8:    return "uint16x8";
 1364           case Uint32x4:    return "uint32x4";
 1365           case Float32x4:   return "float32x4";
 1366           case Bool8x16:    return "bool8x16";
 1367           case Bool16x8:    return "bool16x8";
 1368           case Bool32x4:    return "bool32x4";
 1369           case Void:        return "void";
 1370         }
 1371         MOZ_CRASH("Invalid Type");
 1372     }
 1373 };
 1374 
 1375 static const unsigned VALIDATION_LIFO_DEFAULT_CHUNK_SIZE = 4 * 1024;
 1376 
 1377 // The ModuleValidator encapsulates the entire validation of an asm.js module.
 1378 // Its lifetime goes from the validation of the top components of an asm.js
 1379 // module (all the globals), the emission of bytecode for all the functions in
 1380 // the module and the validation of function's pointer tables. It also finishes
 1381 // the compilation of all the module's stubs.
 1382 //
 1383 // Rooting note: ModuleValidator is a stack class that contains unrooted
 1384 // PropertyName (JSAtom) pointers.  This is safe because it cannot be
 1385 // constructed without a TokenStream reference.  TokenStream is itself a stack
 1386 // class that cannot be constructed without an AutoKeepAtoms being live on the
 1387 // stack, which prevents collection of atoms.
 1388 //
 1389 // ModuleValidator is marked as rooted in the rooting analysis.  Don't add
 1390 // non-JSAtom pointers, or this will break!
 1391 class MOZ_STACK_CLASS ModuleValidator
 1392 {
 1393   public:
 1394     class Func
 1395     {
 1396         PropertyName* name_;
 1397         uint32_t firstUse_;
 1398         uint32_t index_;
 1399         uint32_t srcBegin_;
 1400         uint32_t srcEnd_;
 1401         bool defined_;
 1402 
 1403       public:
 1404         Func(PropertyName* name, uint32_t firstUse, uint32_t index)
 1405           : name_(name), firstUse_(firstUse), index_(index),
 1406             srcBegin_(0), srcEnd_(0), defined_(false)
 1407         {}
 1408 
 1409         PropertyName* name() const { return name_; }
 1410         uint32_t firstUse() const { return firstUse_; }
 1411         bool defined() const { return defined_; }
 1412         uint32_t index() const { return index_; }
 1413 
 1414         void define(ParseNode* fn) {
 1415             MOZ_ASSERT(!defined_);
 1416             defined_ = true;
 1417             srcBegin_ = fn->pn_pos.begin;
 1418             srcEnd_ = fn->pn_pos.end;
 1419         }
 1420 
 1421         uint32_t srcBegin() const { MOZ_ASSERT(defined_); return srcBegin_; }
 1422         uint32_t srcEnd() const { MOZ_ASSERT(defined_); return srcEnd_; }
 1423     };
 1424 
 1425     typedef Vector<const Func*> ConstFuncVector;
 1426     typedef Vector<Func*> FuncVector;
 1427 
 1428     class FuncPtrTable
 1429     {
 1430         uint32_t sigIndex_;
 1431         PropertyName* name_;
 1432         uint32_t firstUse_;
 1433         uint32_t mask_;
 1434         bool defined_;
 1435 
 1436         FuncPtrTable(FuncPtrTable&& rhs) = delete;
 1437 
 1438       public:
 1439         FuncPtrTable(uint32_t sigIndex, PropertyName* name, uint32_t firstUse, uint32_t mask)
 1440           : sigIndex_(sigIndex), name_(name), firstUse_(firstUse), mask_(mask), defined_(false)
 1441         {}
 1442 
 1443         uint32_t sigIndex() const { return sigIndex_; }
 1444         PropertyName* name() const { return name_; }
 1445         uint32_t firstUse() const { return firstUse_; }
 1446         unsigned mask() const { return mask_; }
 1447         bool defined() const { return defined_; }
 1448         void define() { MOZ_ASSERT(!defined_); defined_ = true; }
 1449     };
 1450 
 1451     typedef Vector<FuncPtrTable*> FuncPtrTableVector;
 1452 
 1453     class Global
 1454     {
 1455       public:
 1456         enum Which {
 1457             Variable,
 1458             ConstantLiteral,
 1459             ConstantImport,
 1460             Function,
 1461             FuncPtrTable,
 1462             FFI,
 1463             ArrayView,
 1464             ArrayViewCtor,
 1465             MathBuiltinFunction,
 1466             AtomicsBuiltinFunction,
 1467             SimdCtor,
 1468             SimdOp
 1469         };
 1470 
 1471       private:
 1472         Which which_;
 1473         union {
 1474             struct {
 1475                 Type::Which type_;
 1476                 unsigned index_;
 1477                 NumLit literalValue_;
 1478             } varOrConst;
 1479             uint32_t funcIndex_;
 1480             uint32_t funcPtrTableIndex_;
 1481             uint32_t ffiIndex_;
 1482             struct {
 1483                 Scalar::Type viewType_;
 1484             } viewInfo;
 1485             AsmJSMathBuiltinFunction mathBuiltinFunc_;
 1486             AsmJSAtomicsBuiltinFunction atomicsBuiltinFunc_;
 1487             SimdType simdCtorType_;
 1488             struct {
 1489                 SimdType type_;
 1490                 SimdOperation which_;
 1491             } simdOp;
 1492         } u;
 1493 
 1494         friend class ModuleValidator;
 1495         friend class js::LifoAlloc;
 1496 
 1497         explicit Global(Which which) : which_(which) {}
 1498 
 1499       public:
 1500         Which which() const {
 1501             return which_;
 1502         }
 1503         Type varOrConstType() const {
 1504             MOZ_ASSERT(which_ == Variable || which_ == ConstantLiteral || which_ == ConstantImport);
 1505             return u.varOrConst.type_;
 1506         }
 1507         unsigned varOrConstIndex() const {
 1508             MOZ_ASSERT(which_ == Variable || which_ == ConstantImport);
 1509             return u.varOrConst.index_;
 1510         }
 1511         bool isConst() const {
 1512             return which_ == ConstantLiteral || which_ == ConstantImport;
 1513         }
 1514         NumLit constLiteralValue() const {
 1515             MOZ_ASSERT(which_ == ConstantLiteral);
 1516             return u.varOrConst.literalValue_;
 1517         }
 1518         uint32_t funcIndex() const {
 1519             MOZ_ASSERT(which_ == Function);
 1520             return u.funcIndex_;
 1521         }
 1522         uint32_t funcPtrTableIndex() const {
 1523             MOZ_ASSERT(which_ == FuncPtrTable);
 1524             return u.funcPtrTableIndex_;
 1525         }
 1526         unsigned ffiIndex() const {
 1527             MOZ_ASSERT(which_ == FFI);
 1528             return u.ffiIndex_;
 1529         }
 1530         bool isAnyArrayView() const {
 1531             return which_ == ArrayView || which_ == ArrayViewCtor;
 1532         }
 1533         Scalar::Type viewType() const {
 1534             MOZ_ASSERT(isAnyArrayView());
 1535             return u.viewInfo.viewType_;
 1536         }
 1537         bool isMathFunction() const {
 1538             return which_ == MathBuiltinFunction;
 1539         }
 1540         AsmJSMathBuiltinFunction mathBuiltinFunction() const {
 1541             MOZ_ASSERT(which_ == MathBuiltinFunction);
 1542             return u.mathBuiltinFunc_;
 1543         }
 1544         bool isAtomicsFunction() const {
 1545             return which_ == AtomicsBuiltinFunction;
 1546         }
 1547         AsmJSAtomicsBuiltinFunction atomicsBuiltinFunction() const {
 1548             MOZ_ASSERT(which_ == AtomicsBuiltinFunction);
 1549             return u.atomicsBuiltinFunc_;
 1550         }
 1551         bool isSimdCtor() const {
 1552             return which_ == SimdCtor;
 1553         }
 1554         SimdType simdCtorType() const {
 1555             MOZ_ASSERT(which_ == SimdCtor);
 1556             return u.simdCtorType_;
 1557         }
 1558         bool isSimdOperation() const {
 1559             return which_ == SimdOp;
 1560         }
 1561         SimdOperation simdOperation() const {
 1562             MOZ_ASSERT(which_ == SimdOp);
 1563             return u.simdOp.which_;
 1564         }
 1565         SimdType simdOperationType() const {
 1566             MOZ_ASSERT(which_ == SimdOp);
 1567             return u.simdOp.type_;
 1568         }
 1569     };
 1570 
 1571     struct MathBuiltin
 1572     {
 1573         enum Kind { Function, Constant };
 1574         Kind kind;
 1575 
 1576         union {
 1577             double cst;
 1578             AsmJSMathBuiltinFunction func;
 1579         } u;
 1580 
 1581         MathBuiltin() : kind(Kind(-1)) {}
 1582         explicit MathBuiltin(double cst) : kind(Constant) {
 1583             u.cst = cst;
 1584         }
 1585         explicit MathBuiltin(AsmJSMathBuiltinFunction func) : kind(Function) {
 1586             u.func = func;
 1587         }
 1588     };
 1589 
 1590     struct ArrayView
 1591     {
 1592         ArrayView(PropertyName* name, Scalar::Type type)
 1593           : name(name), type(type)
 1594         {}
 1595 
 1596         PropertyName* name;
 1597         Scalar::Type type;
 1598     };
 1599 
 1600   private:
 1601     class NamedSig
 1602     {
 1603         PropertyName* name_;
 1604         const SigWithId* sig_;
 1605 
 1606       public:
 1607         NamedSig(PropertyName* name, const SigWithId& sig)
 1608           : name_(name), sig_(&sig)
 1609         {}
 1610         PropertyName* name() const {
 1611             return name_;
 1612         }
 1613         const Sig& sig() const {
 1614             return *sig_;
 1615         }
 1616 
 1617         // Implement HashPolicy:
 1618         struct Lookup {
 1619             PropertyName* name;
 1620             const Sig& sig;
 1621             Lookup(PropertyName* name, const Sig& sig) : name(name), sig(sig) {}
 1622         };
 1623         static HashNumber hash(Lookup l) {
 1624             return HashGeneric(l.name, l.sig.hash());
 1625         }
 1626         static bool match(NamedSig lhs, Lookup rhs) {
 1627             return lhs.name_ == rhs.name && *lhs.sig_ == rhs.sig;
 1628         }
 1629     };
 1630     typedef HashMap<NamedSig, uint32_t, NamedSig> ImportMap;
 1631     typedef HashMap<const SigWithId*, uint32_t, SigHashPolicy> SigMap;
 1632     typedef HashMap<PropertyName*, Global*> GlobalMap;
 1633     typedef HashMap<PropertyName*, MathBuiltin> MathNameMap;
 1634     typedef HashMap<PropertyName*, AsmJSAtomicsBuiltinFunction> AtomicsNameMap;
 1635     typedef HashMap<PropertyName*, SimdOperation> SimdOperationNameMap;
 1636     typedef Vector<ArrayView> ArrayViewVector;
 1637 
 1638     ExclusiveContext*     cx_;
 1639     AsmJSParser&          parser_;
 1640     ParseNode*            moduleFunctionNode_;
 1641     PropertyName*         moduleFunctionName_;
 1642     PropertyName*         globalArgumentName_;
 1643     PropertyName*         importArgumentName_;
 1644     PropertyName*         bufferArgumentName_;
 1645     MathNameMap           standardLibraryMathNames_;
 1646     AtomicsNameMap        standardLibraryAtomicsNames_;
 1647     SimdOperationNameMap  standardLibrarySimdOpNames_;
 1648     RootedFunction        dummyFunction_;
 1649 
 1650     // Validation-internal state:
 1651     LifoAlloc             validationLifo_;
 1652     FuncVector            functions_;
 1653     FuncPtrTableVector    funcPtrTables_;
 1654     GlobalMap             globalMap_;
 1655     SigMap                sigMap_;
 1656     ImportMap             importMap_;
 1657     ArrayViewVector       arrayViews_;
 1658     bool                  atomicsPresent_;
 1659     bool                  simdPresent_;
 1660 
 1661     // State used to build the AsmJSModule in finish():
 1662     ModuleGenerator       mg_;
 1663     MutableAsmJSMetadata  asmJSMetadata_;
 1664 
 1665     // Error reporting:
 1666     UniqueChars           errorString_;
 1667     uint32_t              errorOffset_;
 1668     bool                  errorOverRecursed_;
 1669 
 1670     // Helpers:
 1671     bool addStandardLibraryMathName(const char* name, AsmJSMathBuiltinFunction func) {
 1672         JSAtom* atom = Atomize(cx_, name, strlen(name));
 1673         if (!atom)
 1674             return false;
 1675         MathBuiltin builtin(func);
 1676         return standardLibraryMathNames_.putNew(atom->asPropertyName(), builtin);
 1677     }
 1678     bool addStandardLibraryMathName(const char* name, double cst) {
 1679         JSAtom* atom = Atomize(cx_, name, strlen(name));
 1680         if (!atom)
 1681             return false;
 1682         MathBuiltin builtin(cst);
 1683         return standardLibraryMathNames_.putNew(atom->asPropertyName(), builtin);
 1684     }
 1685     bool addStandardLibraryAtomicsName(const char* name, AsmJSAtomicsBuiltinFunction func) {
 1686         JSAtom* atom = Atomize(cx_, name, strlen(name));
 1687         if (!atom)
 1688             return false;
 1689         return standardLibraryAtomicsNames_.putNew(atom->asPropertyName(), func);
 1690     }
 1691     bool addStandardLibrarySimdOpName(const char* name, SimdOperation op) {
 1692         JSAtom* atom = Atomize(cx_, name, strlen(name));
 1693         if (!atom)
 1694             return false;
 1695         return standardLibrarySimdOpNames_.putNew(atom->asPropertyName(), op);
 1696     }
 1697     bool newSig(Sig&& sig, uint32_t* sigIndex) {
 1698         *sigIndex = 0;
 1699         if (mg_.numSigs() >= MaxSigs)
 1700             return failCurrentOffset("too many signatures");
 1701 
 1702         *sigIndex = mg_.numSigs();
 1703         mg_.initSig(*sigIndex, Move(sig));
 1704         return true;
 1705     }
 1706     bool declareSig(Sig&& sig, uint32_t* sigIndex) {
 1707         SigMap::AddPtr p = sigMap_.lookupForAdd(sig);
 1708         if (p) {
 1709             *sigIndex = p->value();
 1710             MOZ_ASSERT(mg_.sig(*sigIndex) == sig);
 1711             return true;
 1712         }
 1713 
 1714         return newSig(Move(sig), sigIndex) &&
 1715                sigMap_.add(p, &mg_.sig(*sigIndex), *sigIndex);
 1716     }
 1717 
 1718   public:
 1719     ModuleValidator(ExclusiveContext* cx, AsmJSParser& parser, ParseNode* moduleFunctionNode)
 1720       : cx_(cx),
 1721         parser_(parser),
 1722         moduleFunctionNode_(moduleFunctionNode),
 1723         moduleFunctionName_(FunctionName(moduleFunctionNode)),
 1724         globalArgumentName_(nullptr),
 1725         importArgumentName_(nullptr),
 1726         bufferArgumentName_(nullptr),
 1727         standardLibraryMathNames_(cx),
 1728         standardLibraryAtomicsNames_(cx),
 1729         standardLibrarySimdOpNames_(cx),
 1730         dummyFunction_(cx),
 1731         validationLifo_(VALIDATION_LIFO_DEFAULT_CHUNK_SIZE),
 1732         functions_(cx),
 1733         funcPtrTables_(cx),
 1734         globalMap_(cx),
 1735         sigMap_(cx),
 1736         importMap_(cx),
 1737         arrayViews_(cx),
 1738         atomicsPresent_(false),
 1739         simdPresent_(false),
 1740         mg_(ImportVector()),
 1741         errorString_(nullptr),
 1742         errorOffset_(UINT32_MAX),
 1743         errorOverRecursed_(false)
 1744     {}
 1745 
 1746     ~ModuleValidator() {
 1747         if (errorString_) {
 1748             MOZ_ASSERT(errorOffset_ != UINT32_MAX);
 1749             tokenStream().reportAsmJSError(errorOffset_,
 1750                                            JSMSG_USE_ASM_TYPE_FAIL,
 1751                                            errorString_.get());
 1752         }
 1753         if (errorOverRecursed_)
 1754             ReportOverRecursed(cx_);
 1755     }
 1756 
 1757     bool init() {
 1758         asmJSMetadata_ = cx_->new_<AsmJSMetadata>();
 1759         if (!asmJSMetadata_)
 1760             return false;
 1761 
 1762         asmJSMetadata_->preludeStart = moduleFunctionNode_->pn_funbox->preludeStart;
 1763         asmJSMetadata_->srcStart = moduleFunctionNode_->pn_body->pn_pos.begin;
 1764         asmJSMetadata_->srcBodyStart = parser_.tokenStream.currentToken().pos.end;
 1765         asmJSMetadata_->strict = parser_.pc->sc()->strict() &&
 1766                                  !parser_.pc->sc()->hasExplicitUseStrict();
 1767         asmJSMetadata_->scriptSource.reset(parser_.ss);
 1768 
 1769         if (!globalMap_.init() || !sigMap_.init() || !importMap_.init())
 1770             return false;
 1771 
 1772         if (!standardLibraryMathNames_.init() ||
 1773             !addStandardLibraryMathName("sin", AsmJSMathBuiltin_sin) ||
 1774             !addStandardLibraryMathName("cos", AsmJSMathBuiltin_cos) ||
 1775             !addStandardLibraryMathName("tan", AsmJSMathBuiltin_tan) ||
 1776             !addStandardLibraryMathName("asin", AsmJSMathBuiltin_asin) ||
 1777             !addStandardLibraryMathName("acos", AsmJSMathBuiltin_acos) ||
 1778             !addStandardLibraryMathName("atan", AsmJSMathBuiltin_atan) ||
 1779             !addStandardLibraryMathName("ceil", AsmJSMathBuiltin_ceil) ||
 1780             !addStandardLibraryMathName("floor", AsmJSMathBuiltin_floor) ||
 1781             !addStandardLibraryMathName("exp", AsmJSMathBuiltin_exp) ||
 1782             !addStandardLibraryMathName("log", AsmJSMathBuiltin_log) ||
 1783             !addStandardLibraryMathName("pow", AsmJSMathBuiltin_pow) ||
 1784             !addStandardLibraryMathName("sqrt", AsmJSMathBuiltin_sqrt) ||
 1785             !addStandardLibraryMathName("abs", AsmJSMathBuiltin_abs) ||
 1786             !addStandardLibraryMathName("atan2", AsmJSMathBuiltin_atan2) ||
 1787             !addStandardLibraryMathName("imul", AsmJSMathBuiltin_imul) ||
 1788             !addStandardLibraryMathName("clz32", AsmJSMathBuiltin_clz32) ||
 1789             !addStandardLibraryMathName("fround", AsmJSMathBuiltin_fround) ||
 1790             !addStandardLibraryMathName("min", AsmJSMathBuiltin_min) ||
 1791             !addStandardLibraryMathName("max", AsmJSMathBuiltin_max) ||
 1792             !addStandardLibraryMathName("E", M_E) ||
 1793             !addStandardLibraryMathName("LN10", M_LN10) ||
 1794             !addStandardLibraryMathName("LN2", M_LN2) ||
 1795             !addStandardLibraryMathName("LOG2E", M_LOG2E) ||
 1796             !addStandardLibraryMathName("LOG10E", M_LOG10E) ||
 1797             !addStandardLibraryMathName("PI", M_PI) ||
 1798             !addStandardLibraryMathName("SQRT1_2", M_SQRT1_2) ||
 1799             !addStandardLibraryMathName("SQRT2", M_SQRT2))
 1800         {
 1801             return false;
 1802         }
 1803 
 1804         if (!standardLibraryAtomicsNames_.init() ||
 1805             !addStandardLibraryAtomicsName("compareExchange", AsmJSAtomicsBuiltin_compareExchange) ||
 1806             !addStandardLibraryAtomicsName("exchange", AsmJSAtomicsBuiltin_exchange) ||
 1807             !addStandardLibraryAtomicsName("load", AsmJSAtomicsBuiltin_load) ||
 1808             !addStandardLibraryAtomicsName("store", AsmJSAtomicsBuiltin_store) ||
 1809             !addStandardLibraryAtomicsName("add", AsmJSAtomicsBuiltin_add) ||
 1810             !addStandardLibraryAtomicsName("sub", AsmJSAtomicsBuiltin_sub) ||
 1811             !addStandardLibraryAtomicsName("and", AsmJSAtomicsBuiltin_and) ||
 1812             !addStandardLibraryAtomicsName("or", AsmJSAtomicsBuiltin_or) ||
 1813             !addStandardLibraryAtomicsName("xor", AsmJSAtomicsBuiltin_xor) ||
 1814             !addStandardLibraryAtomicsName("isLockFree", AsmJSAtomicsBuiltin_isLockFree))
 1815         {
 1816             return false;
 1817         }
 1818 
 1819 #define ADDSTDLIBSIMDOPNAME(op) || !addStandardLibrarySimdOpName(#op, SimdOperation::Fn_##op)
 1820         if (!standardLibrarySimdOpNames_.init()
 1821             FORALL_SIMD_ASMJS_OP(ADDSTDLIBSIMDOPNAME))
 1822         {
 1823             return false;
 1824         }
 1825 #undef ADDSTDLIBSIMDOPNAME
 1826 
 1827         // This flows into FunctionBox, so must be tenured.
 1828         dummyFunction_ = NewScriptedFunction(cx_, 0, JSFunction::INTERPRETED, nullptr,
 1829                                              /* proto = */ nullptr, gc::AllocKind::FUNCTION,
 1830                                              TenuredObject);
 1831         if (!dummyFunction_)
 1832             return false;
 1833 
 1834         ScriptedCaller scriptedCaller;
 1835         if (parser_.ss->filename()) {
 1836             scriptedCaller.line = scriptedCaller.column = 0;  // unused
 1837             scriptedCaller.filename = DuplicateString(parser_.ss->filename());
 1838             if (!scriptedCaller.filename)
 1839                 return false;
 1840         }
 1841 
 1842         CompileArgs args;
 1843         if (!args.initFromContext(cx_, Move(scriptedCaller)))
 1844             return false;
 1845 
 1846         auto genData = MakeUnique<ModuleGeneratorData>(ModuleKind::AsmJS);
 1847         if (!genData ||
 1848             !genData->sigs.resize(MaxSigs) ||
 1849             !genData->funcSigs.resize(MaxFuncs) ||
 1850             !genData->funcImportGlobalDataOffsets.resize(AsmJSMaxImports) ||
 1851             !genData->tables.resize(MaxTables) ||
 1852             !genData->asmJSSigToTableIndex.resize(MaxSigs))
 1853         {
 1854             return false;
 1855         }
 1856 
 1857         genData->minMemoryLength = RoundUpToNextValidAsmJSHeapLength(0);
 1858 
 1859         if (!mg_.init(Move(genData), args, asmJSMetadata_.get()))
 1860             return false;
 1861 
 1862         return true;
 1863     }
 1864 
 1865     ExclusiveContext* cx() const             { return cx_; }
 1866     PropertyName* moduleFunctionName() const { return moduleFunctionName_; }
 1867     PropertyName* globalArgumentName() const { return globalArgumentName_; }
 1868     PropertyName* importArgumentName() const { return importArgumentName_; }
 1869     PropertyName* bufferArgumentName() const { return bufferArgumentName_; }
 1870     ModuleGenerator& mg()                    { return mg_; }
 1871     AsmJSParser& parser() const              { return parser_; }
 1872     TokenStream& tokenStream() const         { return parser_.tokenStream; }
 1873     RootedFunction& dummyFunction()          { return dummyFunction_; }
 1874     bool supportsSimd() const                { return cx_->jitSupportsSimd(); }
 1875     bool atomicsPresent() const              { return atomicsPresent_; }
 1876     uint32_t minMemoryLength() const         { return mg_.minMemoryLength(); }
 1877 
 1878     void initModuleFunctionName(PropertyName* name) {
 1879         MOZ_ASSERT(!moduleFunctionName_);
 1880         moduleFunctionName_ = name;
 1881     }
 1882     MOZ_MUST_USE bool initGlobalArgumentName(PropertyName* n) {
 1883         MOZ_ASSERT(n->isTenured());
 1884         globalArgumentName_ = n;
 1885         if (n) {
 1886             asmJSMetadata_->globalArgumentName = StringToNewUTF8CharsZ(cx_, *n);
 1887             if (!asmJSMetadata_->globalArgumentName)
 1888                 return false;
 1889         }
 1890         return true;
 1891     }
 1892     MOZ_MUST_USE bool initImportArgumentName(PropertyName* n) {
 1893         MOZ_ASSERT(n->isTenured());
 1894         importArgumentName_ = n;
 1895         if (n) {
 1896             asmJSMetadata_->importArgumentName = StringToNewUTF8CharsZ(cx_, *n);
 1897             if (!asmJSMetadata_->importArgumentName)
 1898                 return false;
 1899         }
 1900         return true;
 1901     }
 1902     MOZ_MUST_USE bool initBufferArgumentName(PropertyName* n) {
 1903         MOZ_ASSERT(n->isTenured());
 1904         bufferArgumentName_ = n;
 1905         if (n) {
 1906             asmJSMetadata_->bufferArgumentName = StringToNewUTF8CharsZ(cx_, *n);
 1907             if (!asmJSMetadata_->bufferArgumentName)
 1908                 return false;
 1909         }
 1910         return true;
 1911     }
 1912     bool addGlobalVarInit(PropertyName* var, const NumLit& lit, Type type, bool isConst) {
 1913         MOZ_ASSERT(type.isGlobalVarType());
 1914         MOZ_ASSERT(type == Type::canonicalize(Type::lit(lit)));
 1915 
 1916         uint32_t index;
 1917         if (!mg_.addGlobal(type.canonicalToValType(), isConst, &index))
 1918             return false;
 1919 
 1920         Global::Which which = isConst ? Global::ConstantLiteral : Global::Variable;
 1921         Global* global = validationLifo_.new_<Global>(which);
 1922         if (!global)
 1923             return false;
 1924         global->u.varOrConst.index_ = index;
 1925         global->u.varOrConst.type_ = (isConst ? Type::lit(lit) : type).which();
 1926         if (isConst)
 1927             global->u.varOrConst.literalValue_ = lit;
 1928         if (!globalMap_.putNew(var, global))
 1929             return false;
 1930 
 1931         AsmJSGlobal g(AsmJSGlobal::Variable, nullptr);
 1932         g.pod.u.var.initKind_ = AsmJSGlobal::InitConstant;
 1933         g.pod.u.var.u.val_ = lit.value();
 1934         return asmJSMetadata_->asmJSGlobals.append(Move(g));
 1935     }
 1936     bool addGlobalVarImport(PropertyName* var, PropertyName* field, Type type, bool isConst) {
 1937         MOZ_ASSERT(type.isGlobalVarType());
 1938 
 1939         UniqueChars fieldChars = StringToNewUTF8CharsZ(cx_, *field);
 1940         if (!fieldChars)
 1941             return false;
 1942 
 1943         uint32_t index;
 1944         ValType valType = type.canonicalToValType();
 1945         if (!mg_.addGlobal(valType, isConst, &index))
 1946             return false;
 1947 
 1948         Global::Which which = isConst ? Global::ConstantImport : Global::Variable;
 1949         Global* global = validationLifo_.new_<Global>(which);
 1950         if (!global)
 1951             return false;
 1952         global->u.varOrConst.index_ = index;
 1953         global->u.varOrConst.type_ = type.which();
 1954         if (!globalMap_.putNew(var, global))
 1955             return false;
 1956 
 1957         AsmJSGlobal g(AsmJSGlobal::Variable, Move(fieldChars));
 1958         g.pod.u.var.initKind_ = AsmJSGlobal::InitImport;
 1959         g.pod.u.var.u.importType_ = valType;
 1960         return asmJSMetadata_->asmJSGlobals.append(Move(g));
 1961     }
 1962     bool addArrayView(PropertyName* var, Scalar::Type vt, PropertyName* maybeField) {
 1963         UniqueChars fieldChars;
 1964         if (maybeField) {
 1965             fieldChars = StringToNewUTF8CharsZ(cx_, *maybeField);
 1966             if (!fieldChars)
 1967                 return false;
 1968         }
 1969 
 1970         if (!arrayViews_.append(ArrayView(var, vt)))
 1971             return false;
 1972 
 1973         Global* global = validationLifo_.new_<Global>(Global::ArrayView);
 1974         if (!global)
 1975             return false;
 1976         global->u.viewInfo.viewType_ = vt;
 1977         if (!globalMap_.putNew(var, global))
 1978             return false;
 1979 
 1980         AsmJSGlobal g(AsmJSGlobal::ArrayView, Move(fieldChars));
 1981         g.pod.u.viewType_ = vt;
 1982         return asmJSMetadata_->asmJSGlobals.append(Move(g));
 1983     }
 1984     bool addMathBuiltinFunction(PropertyName* var, AsmJSMathBuiltinFunction func,
 1985                                 PropertyName* field)
 1986     {
 1987         UniqueChars fieldChars = StringToNewUTF8CharsZ(cx_, *field);
 1988         if (!fieldChars)
 1989             return false;
 1990 
 1991         Global* global = validationLifo_.new_<Global>(Global::MathBuiltinFunction);
 1992         if (!global)
 1993             return false;
 1994         global->u.mathBuiltinFunc_ = func;
 1995         if (!globalMap_.putNew(var, global))
 1996             return false;
 1997 
 1998         AsmJSGlobal g(AsmJSGlobal::MathBuiltinFunction, Move(fieldChars));
 1999         g.pod.u.mathBuiltinFunc_ = func;
 2000         return asmJSMetadata_->asmJSGlobals.append(Move(g));
 2001     }
 2002   private:
 2003     bool addGlobalDoubleConstant(PropertyName* var, double constant) {
 2004         Global* global = validationLifo_.new_<Global>(Global::ConstantLiteral);
 2005         if (!global)
 2006             return false;
 2007         global->u.varOrConst.type_ = Type::Double;
 2008         global->u.varOrConst.literalValue_ = NumLit(NumLit::Double, DoubleValue(constant));
 2009         return globalMap_.putNew(var, global);
 2010     }
 2011   public:
 2012     bool addMathBuiltinConstant(PropertyName* var, double constant, PropertyName* field) {
 2013         UniqueChars fieldChars = StringToNewUTF8CharsZ(cx_, *field);
 2014         if (!fieldChars)
 2015             return false;
 2016 
 2017         if (!addGlobalDoubleConstant(var, constant))
 2018             return false;
 2019 
 2020         AsmJSGlobal g(AsmJSGlobal::Constant, Move(fieldChars));
 2021         g.pod.u.constant.value_ = constant;
 2022         g.pod.u.constant.kind_ = AsmJSGlobal::MathConstant;
 2023         return asmJSMetadata_->asmJSGlobals.append(Move(g));
 2024     }
 2025     bool addGlobalConstant(PropertyName* var, double constant, PropertyName* field) {
 2026         UniqueChars fieldChars = StringToNewUTF8CharsZ(cx_, *field);
 2027         if (!fieldChars)
 2028             return false;
 2029 
 2030         if (!addGlobalDoubleConstant(var, constant))
 2031             return false;
 2032 
 2033         AsmJSGlobal g(AsmJSGlobal::Constant, Move(fieldChars));
 2034         g.pod.u.constant.value_ = constant;
 2035         g.pod.u.constant.kind_ = AsmJSGlobal::GlobalConstant;
 2036         return asmJSMetadata_->asmJSGlobals.append(Move(g));
 2037     }
 2038     bool addAtomicsBuiltinFunction(PropertyName* var, AsmJSAtomicsBuiltinFunction func,
 2039                                    PropertyName* field)
 2040     {
 2041         if (!JitOptions.asmJSAtomicsEnable)
 2042             return failCurrentOffset("asm.js Atomics only enabled in wasm test mode");
 2043 
 2044         atomicsPresent_ = true;
 2045 
 2046         UniqueChars fieldChars = StringToNewUTF8CharsZ(cx_, *field);
 2047         if (!fieldChars)
 2048             return false;
 2049 
 2050         Global* global = validationLifo_.new_<Global>(Global::AtomicsBuiltinFunction);
 2051         if (!global)
 2052             return false;
 2053         global->u.atomicsBuiltinFunc_ = func;
 2054         if (!globalMap_.putNew(var, global))
 2055             return false;
 2056 
 2057         AsmJSGlobal g(AsmJSGlobal::AtomicsBuiltinFunction, Move(fieldChars));
 2058         g.pod.u.atomicsBuiltinFunc_ = func;
 2059         return asmJSMetadata_->asmJSGlobals.append(Move(g));
 2060     }
 2061     bool addSimdCtor(PropertyName* var, SimdType type, PropertyName* field) {
 2062         simdPresent_ = true;
 2063 
 2064         UniqueChars fieldChars = StringToNewUTF8CharsZ(cx_, *field);
 2065         if (!fieldChars)
 2066             return false;
 2067 
 2068         Global* global = validationLifo_.new_<Global>(Global::SimdCtor);
 2069         if (!global)
 2070             return false;
 2071         global->u.simdCtorType_ = type;
 2072         if (!globalMap_.putNew(var, global))
 2073             return false;
 2074 
 2075         AsmJSGlobal g(AsmJSGlobal::SimdCtor, Move(fieldChars));
 2076         g.pod.u.simdCtorType_ = type;
 2077         return asmJSMetadata_->asmJSGlobals.append(Move(g));
 2078     }
 2079     bool addSimdOperation(PropertyName* var, SimdType type, SimdOperation op, PropertyName* field) {
 2080         simdPresent_ = true;
 2081 
 2082         UniqueChars fieldChars = StringToNewUTF8CharsZ(cx_, *field);
 2083         if (!fieldChars)
 2084             return false;
 2085 
 2086         Global* global = validationLifo_.new_<Global>(Global::SimdOp);
 2087         if (!global)
 2088             return false;
 2089         global->u.simdOp.type_ = type;
 2090         global->u.simdOp.which_ = op;
 2091         if (!globalMap_.putNew(var, global))
 2092             return false;
 2093 
 2094         AsmJSGlobal g(AsmJSGlobal::SimdOp, Move(fieldChars));
 2095         g.pod.u.simdOp.type_ = type;
 2096         g.pod.u.simdOp.which_ = op;
 2097         return asmJSMetadata_->asmJSGlobals.append(Move(g));
 2098     }
 2099     bool addArrayViewCtor(PropertyName* var, Scalar::Type vt, PropertyName* field) {
 2100         UniqueChars fieldChars = StringToNewUTF8CharsZ(cx_, *field);
 2101         if (!fieldChars)
 2102             return false;
 2103 
 2104         Global* global = validationLifo_.new_<Global>(Global::ArrayViewCtor);
 2105         if (!global)
 2106             return false;
 2107         global->u.viewInfo.viewType_ = vt;
 2108         if (!globalMap_.putNew(var, global))
 2109             return false;
 2110 
 2111         AsmJSGlobal g(AsmJSGlobal::ArrayViewCtor, Move(fieldChars));
 2112         g.pod.u.viewType_ = vt;
 2113         return asmJSMetadata_->asmJSGlobals.append(Move(g));
 2114     }
 2115     bool addFFI(PropertyName* var, PropertyName* field) {
 2116         UniqueChars fieldChars = StringToNewUTF8CharsZ(cx_, *field);
 2117         if (!fieldChars)
 2118             return false;
 2119 
 2120         if (asmJSMetadata_->numFFIs == UINT32_MAX)
 2121             return false;
 2122         uint32_t ffiIndex = asmJSMetadata_->numFFIs++;
 2123 
 2124         Global* global = validationLifo_.new_<Global>(Global::FFI);
 2125         if (!global)
 2126             return false;
 2127         global->u.ffiIndex_ = ffiIndex;
 2128         if (!globalMap_.putNew(var, global))
 2129             return false;
 2130 
 2131         AsmJSGlobal g(AsmJSGlobal::FFI, Move(fieldChars));
 2132         g.pod.u.ffiIndex_ = ffiIndex;
 2133         return asmJSMetadata_->asmJSGlobals.append(Move(g));
 2134     }
 2135     bool addExportField(ParseNode* pn, const Func& func, PropertyName* maybeField) {
 2136         // Record the field name of this export.
 2137         CacheableChars fieldChars;
 2138         if (maybeField)
 2139             fieldChars = StringToNewUTF8CharsZ(cx_, *maybeField);
 2140         else
 2141             fieldChars = DuplicateString("");
 2142         if (!fieldChars)
 2143             return false;
 2144 
 2145         // Declare which function is exported which gives us an index into the
 2146         // module FuncExportVector.
 2147         if (!mg_.addFuncExport(Move(fieldChars), func.index()))
 2148             return false;
 2149 
 2150         // The exported function might have already been exported in which case
 2151         // the index will refer into the range of AsmJSExports.
 2152         return asmJSMetadata_->asmJSExports.emplaceBack(func.index(),
 2153                                                         func.srcBegin() - asmJSMetadata_->srcStart,
 2154                                                         func.srcEnd() - asmJSMetadata_->srcStart);
 2155     }
 2156     bool addFunction(PropertyName* name, uint32_t firstUse, Sig&& sig, Func** func) {
 2157         uint32_t sigIndex;
 2158         if (!declareSig(Move(sig), &sigIndex))
 2159             return false;
 2160         uint32_t funcIndex = AsmJSFirstDefFuncIndex + numFunctions();
 2161         if (funcIndex >= MaxFuncs)
 2162             return failCurrentOffset("too many functions");
 2163         mg_.initFuncSig(funcIndex, sigIndex);
 2164         Global* global = validationLifo_.new_<Global>(Global::Function);
 2165         if (!global)
 2166             return false;
 2167         global->u.funcIndex_ = funcIndex;
 2168         if (!globalMap_.putNew(name, global))
 2169             return false;
 2170         *func = validationLifo_.new_<Func>(name, firstUse, funcIndex);
 2171         return *func && functions_.append(*func);
 2172     }
 2173     bool declareFuncPtrTable(Sig&& sig, PropertyName* name, uint32_t firstUse, uint32_t mask,
 2174                              uint32_t* index)
 2175     {
 2176         if (mask > MaxTableElems)
 2177             return failCurrentOffset("function pointer table too big");
 2178         uint32_t sigIndex;
 2179         if (!newSig(Move(sig), &sigIndex))
 2180             return false;
 2181         if (!mg_.initSigTableLength(sigIndex, mask + 1))
 2182             return false;
 2183         Global* global = validationLifo_.new_<Global>(Global::FuncPtrTable);
 2184         if (!global)
 2185             return false;
 2186         global->u.funcPtrTableIndex_ = *index = funcPtrTables_.length();
 2187         if (!globalMap_.putNew(name, global))
 2188             return false;
 2189         FuncPtrTable* t = validationLifo_.new_<FuncPtrTable>(sigIndex, name, firstUse, mask);
 2190         return t && funcPtrTables_.append(t);
 2191     }
 2192     bool defineFuncPtrTable(uint32_t funcPtrTableIndex, Uint32Vector&& elems) {
 2193         FuncPtrTable& table = *funcPtrTables_[funcPtrTableIndex];
 2194         if (table.defined())
 2195             return false;
 2196         table.define();
 2197         return mg_.initSigTableElems(table.sigIndex(), Move(elems));
 2198     }
 2199     bool declareImport(PropertyName* name, Sig&& sig, unsigned ffiIndex, uint32_t* funcIndex) {
 2200         ImportMap::AddPtr p = importMap_.lookupForAdd(NamedSig::Lookup(name, sig));
 2201         if (p) {
 2202             *funcIndex = p->value();
 2203             return true;
 2204         }
 2205         *funcIndex = asmJSMetadata_->asmJSImports.length();
 2206         if (*funcIndex > AsmJSMaxImports)
 2207             return failCurrentOffset("too many imports");
 2208         if (!asmJSMetadata_->asmJSImports.emplaceBack(ffiIndex))
 2209             return false;
 2210         uint32_t sigIndex;
 2211         if (!declareSig(Move(sig), &sigIndex))
 2212             return false;
 2213         if (!mg_.initImport(*funcIndex, sigIndex))
 2214             return false;
 2215         return importMap_.add(p, NamedSig(name, mg_.sig(sigIndex)), *funcIndex);
 2216     }
 2217 
 2218     bool tryConstantAccess(uint64_t start, uint64_t width) {
 2219         MOZ_ASSERT(UINT64_MAX - start > width);
 2220         uint64_t len = start + width;
 2221         if (len > uint64_t(INT32_MAX) + 1)
 2222             return false;
 2223         len = RoundUpToNextValidAsmJSHeapLength(len);
 2224         if (len > mg_.minMemoryLength())
 2225             mg_.bumpMinMemoryLength(len);
 2226         return true;
 2227     }
 2228 
 2229     // Error handling.
 2230     bool hasAlreadyFailed() const {
 2231         return !!errorString_;
 2232     }
 2233 
 2234     bool failOffset(uint32_t offset, const char* str) {
 2235         MOZ_ASSERT(!hasAlreadyFailed());
 2236         MOZ_ASSERT(errorOffset_ == UINT32_MAX);
 2237         MOZ_ASSERT(str);
 2238         errorOffset_ = offset;
 2239         errorString_ = DuplicateString(str);
 2240         return false;
 2241     }
 2242 
 2243     bool failCurrentOffset(const char* str) {
 2244         return failOffset(tokenStream().currentToken().pos.begin, str);
 2245     }
 2246 
 2247     bool fail(ParseNode* pn, const char* str) {
 2248         return failOffset(pn->pn_pos.begin, str);
 2249     }
 2250 
 2251     bool failfVAOffset(uint32_t offset, const char* fmt, va_list ap) {
 2252         MOZ_ASSERT(!hasAlreadyFailed());
 2253         MOZ_ASSERT(errorOffset_ == UINT32_MAX);
 2254         MOZ_ASSERT(fmt);
 2255         errorOffset_ = offset;
 2256         errorString_.reset(JS_vsmprintf(fmt, ap));
 2257         return false;
 2258     }
 2259 
 2260     bool failfOffset(uint32_t offset, const char* fmt, ...) MOZ_FORMAT_PRINTF(3, 4) {
 2261         va_list ap;
 2262         va_start(ap, fmt);
 2263         failfVAOffset(offset, fmt, ap);
 2264         va_end(ap);
 2265         return false;
 2266     }
 2267 
 2268     bool failf(ParseNode* pn, const char* fmt, ...) MOZ_FORMAT_PRINTF(3, 4) {
 2269         va_list ap;
 2270         va_start(ap, fmt);
 2271         failfVAOffset(pn->pn_pos.begin, fmt, ap);
 2272         va_end(ap);
 2273         return false;
 2274     }
 2275 
 2276     bool failNameOffset(uint32_t offset, const char* fmt, PropertyName* name) {
 2277         // This function is invoked without the caller properly rooting its locals.
 2278         gc::AutoSuppressGC suppress(cx_);
 2279         JSAutoByteString bytes;
 2280         if (AtomToPrintableString(cx_, name, &bytes))
 2281             failfOffset(offset, fmt, bytes.ptr());
 2282         return false;
 2283     }
 2284 
 2285     bool failName(ParseNode* pn, const char* fmt, PropertyName* name) {
 2286         return failNameOffset(pn->pn_pos.begin, fmt, name);
 2287     }
 2288 
 2289     bool failOverRecursed() {
 2290         errorOverRecursed_ = true;
 2291         return false;
 2292     }
 2293 
 2294     unsigned numArrayViews() const {
 2295         return arrayViews_.length();
 2296     }
 2297     const ArrayView& arrayView(unsigned i) const {
 2298         return arrayViews_[i];
 2299     }
 2300     unsigned numFunctions() const {
 2301         return functions_.length();
 2302     }
 2303     Func& function(unsigned i) const {
 2304         return *functions_[i];
 2305     }
 2306     unsigned numFuncPtrTables() const {
 2307         return funcPtrTables_.length();
 2308     }
 2309     FuncPtrTable& funcPtrTable(unsigned i) const {
 2310         return *funcPtrTables_[i];
 2311     }
 2312 
 2313     const Global* lookupGlobal(PropertyName* name) const {
 2314         if (GlobalMap::Ptr p = globalMap_.lookup(name))
 2315             return p->value();
 2316         return nullptr;
 2317     }
 2318 
 2319     Func* lookupFunction(PropertyName* name) {
 2320         if (GlobalMap::Ptr p = globalMap_.lookup(name)) {
 2321             Global* value = p->value();
 2322             if (value->which() == Global::Function) {
 2323                 MOZ_ASSERT(value->funcIndex() >= AsmJSFirstDefFuncIndex);
 2324                 return functions_[value->funcIndex() - AsmJSFirstDefFuncIndex];
 2325             }
 2326         }
 2327         return nullptr;
 2328     }
 2329 
 2330     bool lookupStandardLibraryMathName(PropertyName* name, MathBuiltin* mathBuiltin) const {
 2331         if (MathNameMap::Ptr p = standardLibraryMathNames_.lookup(name)) {
 2332             *mathBuiltin = p->value();
 2333             return true;
 2334         }
 2335         return false;
 2336     }
 2337     bool lookupStandardLibraryAtomicsName(PropertyName* name, AsmJSAtomicsBuiltinFunction* atomicsBuiltin) const {
 2338         if (AtomicsNameMap::Ptr p = standardLibraryAtomicsNames_.lookup(name)) {
 2339             *atomicsBuiltin = p->value();
 2340             return true;
 2341         }
 2342         return false;
 2343     }
 2344     bool lookupStandardSimdOpName(PropertyName* name, SimdOperation* op) const {
 2345         if (SimdOperationNameMap::Ptr p = standardLibrarySimdOpNames_.lookup(name)) {
 2346             *op = p->value();
 2347             return true;
 2348         }
 2349         return false;
 2350     }
 2351 
 2352     bool startFunctionBodies() {
 2353         return mg_.startFuncDefs();
 2354     }
 2355     bool finishFunctionBodies() {
 2356         return mg_.finishFuncDefs();
 2357     }
 2358     SharedModule finish() {
 2359         if (!arrayViews_.empty())
 2360             mg_.initMemoryUsage(atomicsPresent_ ? MemoryUsage::Shared : MemoryUsage::Unshared);
 2361 
 2362         asmJSMetadata_->usesSimd = simdPresent_;
 2363 
 2364         MOZ_ASSERT(asmJSMetadata_->asmJSFuncNames.empty());
 2365         for (const Func* func : functions_) {
 2366             CacheableChars funcName = StringToNewUTF8CharsZ(cx_, *func->name());
 2367             if (!funcName || !asmJSMetadata_->asmJSFuncNames.emplaceBack(Move(funcName)))
 2368                 return nullptr;
 2369         }
 2370 
 2371         uint32_t endBeforeCurly = tokenStream().currentToken().pos.end;
 2372         asmJSMetadata_->srcLength = endBeforeCurly - asmJSMetadata_->srcStart;
 2373 
 2374         TokenPos pos;
 2375         JS_ALWAYS_TRUE(tokenStream().peekTokenPos(&pos, TokenStream::Operand));
 2376         uint32_t endAfterCurly = pos.end;
 2377         asmJSMetadata_->srcLengthWithRightBrace = endAfterCurly - asmJSMetadata_->srcStart;
 2378 
 2379         // asm.js does not have any wasm bytecode to save; view-source is
 2380         // provided through the ScriptSource.
 2381         SharedBytes bytes = js_new<ShareableBytes>();
 2382         if (!bytes)
 2383             return nullptr;
 2384 
 2385         return mg_.finish(*bytes);
 2386     }
 2387 };
 2388 
 2389 /*****************************************************************************/
 2390 // Numeric literal utilities
 2391 
 2392 static bool
 2393 IsNumericNonFloatLiteral(ParseNode* pn)
 2394 {
 2395     // Note: '-' is never rolled into the number; numbers are always positive
 2396     // and negations must be applied manually.
 2397     return pn->isKind(PNK_NUMBER) ||
 2398            (pn->isKind(PNK_NEG) && UnaryKid(pn)->isKind(PNK_NUMBER));
 2399 }
 2400 
 2401 static bool
 2402 IsCallToGlobal(ModuleValidator& m, ParseNode* pn, const ModuleValidator::Global** global)
 2403 {
 2404     if (!pn->isKind(PNK_CALL))
 2405         return false;
 2406 
 2407     ParseNode* callee = CallCallee(pn);
 2408     if (!callee->isKind(PNK_NAME))
 2409         return false;
 2410 
 2411     *global = m.lookupGlobal(callee->name());
 2412     return !!*global;
 2413 }
 2414 
 2415 static bool
 2416 IsCoercionCall(ModuleValidator& m, ParseNode* pn, Type* coerceTo, ParseNode** coercedExpr)
 2417 {
 2418     const ModuleValidator::Global* global;
 2419     if (!IsCallToGlobal(m, pn, &global))
 2420         return false;
 2421 
 2422     if (CallArgListLength(pn) != 1)
 2423         return false;
 2424 
 2425     if (coercedExpr)
 2426         *coercedExpr = CallArgList(pn);
 2427 
 2428     if (global->isMathFunction() && global->mathBuiltinFunction() == AsmJSMathBuiltin_fround) {
 2429         *coerceTo = Type::Float;
 2430         return true;
 2431     }
 2432 
 2433     if (global->isSimdOperation() && global->simdOperation() == SimdOperation::Fn_check) {
 2434         *coerceTo = global->simdOperationType();
 2435         return true;
 2436     }
 2437 
 2438     return false;
 2439 }
 2440 
 2441 static bool
 2442 IsFloatLiteral(ModuleValidator& m, ParseNode* pn)
 2443 {
 2444     ParseNode* coercedExpr;
 2445     Type coerceTo;
 2446     if (!IsCoercionCall(m, pn, &coerceTo, &coercedExpr))
 2447         return false;
 2448     // Don't fold into || to avoid clang/memcheck bug (bug 1077031).
 2449     if (!coerceTo.isFloat())
 2450         return false;
 2451     return IsNumericNonFloatLiteral(coercedExpr);
 2452 }
 2453 
 2454 static bool
 2455 IsSimdTuple(ModuleValidator& m, ParseNode* pn, SimdType* type)
 2456 {
 2457     const ModuleValidator::Global* global;
 2458     if (!IsCallToGlobal(m, pn, &global))
 2459         return false;
 2460 
 2461     if (!global->isSimdCtor())
 2462         return false;
 2463 
 2464     if (CallArgListLength(pn) != GetSimdLanes(global->simdCtorType()))
 2465         return false;
 2466 
 2467     *type = global->simdCtorType();
 2468     return true;
 2469 }
 2470 
 2471 static bool
 2472 IsNumericLiteral(ModuleValidator& m, ParseNode* pn, bool* isSimd = nullptr);
 2473 
 2474 static NumLit
 2475 ExtractNumericLiteral(ModuleValidator& m, ParseNode* pn);
 2476 
 2477 static inline bool
 2478 IsLiteralInt(ModuleValidator& m, ParseNode* pn, uint32_t* u32);
 2479 
 2480 static bool
 2481 IsSimdLiteral(ModuleValidator& m, ParseNode* pn)
 2482 {
 2483     SimdType type;
 2484     if (!IsSimdTuple(m, pn, &type))
 2485         return false;
 2486 
 2487     ParseNode* arg = CallArgList(pn);
 2488     unsigned length = GetSimdLanes(type);
 2489     for (unsigned i = 0; i < length; i++) {
 2490         if (!IsNumericLiteral(m, arg))
 2491             return false;
 2492 
 2493         uint32_t _;
 2494         switch (type) {
 2495           case SimdType::Int8x16:
 2496           case SimdType::Int16x8:
 2497           case SimdType::Int32x4:
 2498           case SimdType::Uint8x16:
 2499           case SimdType::Uint16x8:
 2500           case SimdType::Uint32x4:
 2501           case SimdType::Bool8x16:
 2502           case SimdType::Bool16x8:
 2503           case SimdType::Bool32x4:
 2504             if (!IsLiteralInt(m, arg, &_))
 2505                 return false;
 2506             break;
 2507           case SimdType::Float32x4:
 2508             if (!IsNumericNonFloatLiteral(arg))
 2509                 return false;
 2510             break;
 2511           default:
 2512             MOZ_CRASH("unhandled simd type");
 2513         }
 2514 
 2515         arg = NextNode(arg);
 2516     }
 2517 
 2518     MOZ_ASSERT(arg == nullptr);
 2519     return true;
 2520 }
 2521 
 2522 static bool
 2523 IsNumericLiteral(ModuleValidator& m, ParseNode* pn, bool* isSimd)
 2524 {
 2525     if (IsNumericNonFloatLiteral(pn) || IsFloatLiteral(m, pn))
 2526         return true;
 2527     if (IsSimdLiteral(m, pn)) {
 2528         if (isSimd)
 2529             *isSimd = true;
 2530         return true;
 2531     }
 2532     return false;
 2533 }
 2534 
 2535 // The JS grammar treats -42 as -(42) (i.e., with separate grammar
 2536 // productions) for the unary - and literal 42). However, the asm.js spec
 2537 // recognizes -42 (modulo parens, so -(42) and -((42))) as a single literal
 2538 // so fold the two potential parse nodes into a single double value.
 2539 static double
 2540 ExtractNumericNonFloatValue(ParseNode* pn, ParseNode** out = nullptr)
 2541 {
 2542     MOZ_ASSERT(IsNumericNonFloatLiteral(pn));
 2543 
 2544     if (pn->isKind(PNK_NEG)) {
 2545         pn = UnaryKid(pn);
 2546         if (out)
 2547             *out = pn;
 2548         return -NumberNodeValue(pn);
 2549     }
 2550 
 2551     return NumberNodeValue(pn);
 2552 }
 2553 
 2554 static NumLit
 2555 ExtractSimdValue(ModuleValidator& m, ParseNode* pn)
 2556 {
 2557     MOZ_ASSERT(IsSimdLiteral(m, pn));
 2558 
 2559     SimdType type = SimdType::Count;
 2560     JS_ALWAYS_TRUE(IsSimdTuple(m, pn, &type));
 2561     MOZ_ASSERT(CallArgListLength(pn) == GetSimdLanes(type));
 2562 
 2563     ParseNode* arg = CallArgList(pn);
 2564     switch (type) {
 2565       case SimdType::Int8x16:
 2566       case SimdType::Uint8x16: {
 2567         MOZ_ASSERT(GetSimdLanes(type) == 16);
 2568         int8_t val[16];
 2569         for (size_t i = 0; i < 16; i++, arg = NextNode(arg)) {
 2570             uint32_t u32;
 2571             JS_ALWAYS_TRUE(IsLiteralInt(m, arg, &u32));
 2572             val[i] = int8_t(u32);
 2573         }
 2574         MOZ_ASSERT(arg == nullptr);
 2575         NumLit::Which w = type == SimdType::Uint8x16 ? NumLit::Uint8x16 : NumLit::Int8x16;
 2576         return NumLit(w, SimdConstant::CreateX16(val));
 2577       }
 2578       case SimdType::Int16x8:
 2579       case SimdType::Uint16x8: {
 2580         MOZ_ASSERT(GetSimdLanes(type) == 8);
 2581         int16_t val[8];
 2582         for (size_t i = 0; i < 8; i++, arg = NextNode(arg)) {
 2583             uint32_t u32;
 2584             JS_ALWAYS_TRUE(IsLiteralInt(m, arg, &u32));
 2585             val[i] = int16_t(u32);
 2586         }
 2587         MOZ_ASSERT(arg == nullptr);
 2588         NumLit::Which w = type == SimdType::Uint16x8 ? NumLit::Uint16x8 : NumLit::Int16x8;
 2589         return NumLit(w, SimdConstant::CreateX8(val));
 2590       }
 2591       case SimdType::Int32x4:
 2592       case SimdType::Uint32x4: {
 2593         MOZ_ASSERT(GetSimdLanes(type) == 4);
 2594         int32_t val[4];
 2595         for (size_t i = 0; i < 4; i++, arg = NextNode(arg)) {
 2596             uint32_t u32;
 2597             JS_ALWAYS_TRUE(IsLiteralInt(m, arg, &u32));
 2598             val[i] = int32_t(u32);
 2599         }
 2600         MOZ_ASSERT(arg == nullptr);
 2601         NumLit::Which w = type == SimdType::Uint32x4 ? NumLit::Uint32x4 : NumLit::Int32x4;
 2602         return NumLit(w, SimdConstant::CreateX4(val));
 2603       }
 2604       case SimdType::Float32x4: {
 2605         MOZ_ASSERT(GetSimdLanes(type) == 4);
 2606         float val[4];
 2607         for (size_t i = 0; i < 4; i++, arg = NextNode(arg))
 2608             val[i] = float(ExtractNumericNonFloatValue(arg));
 2609         MOZ_ASSERT(arg == nullptr);
 2610         return NumLit(NumLit::Float32x4, SimdConstant::CreateX4(val));
 2611       }
 2612       case SimdType::Bool8x16: {
 2613         MOZ_ASSERT(GetSimdLanes(type) == 16);
 2614         int8_t val[16];
 2615         for (size_t i = 0; i < 16; i++, arg = NextNode(arg)) {
 2616             uint32_t u32;
 2617             JS_ALWAYS_TRUE(IsLiteralInt(m, arg, &u32));
 2618             val[i] = u32 ? -1 : 0;
 2619         }
 2620         MOZ_ASSERT(arg == nullptr);
 2621         return NumLit(NumLit::Bool8x16, SimdConstant::CreateX16(val));
 2622       }
 2623       case SimdType::Bool16x8: {
 2624         MOZ_ASSERT(GetSimdLanes(type) == 8);
 2625         int16_t val[8];
 2626         for (size_t i = 0; i < 8; i++, arg = NextNode(arg)) {
 2627             uint32_t u32;
 2628             JS_ALWAYS_TRUE(IsLiteralInt(m, arg, &u32));
 2629             val[i] = u32 ? -1 : 0;
 2630         }
 2631         MOZ_ASSERT(arg == nullptr);
 2632         return NumLit(NumLit::Bool16x8, SimdConstant::CreateX8(val));
 2633       }
 2634       case SimdType::Bool32x4: {
 2635         MOZ_ASSERT(GetSimdLanes(type) == 4);
 2636         int32_t val[4];
 2637         for (size_t i = 0; i < 4; i++, arg = NextNode(arg)) {
 2638             uint32_t u32;
 2639             JS_ALWAYS_TRUE(IsLiteralInt(m, arg, &u32));
 2640             val[i] = u32 ? -1 : 0;
 2641         }
 2642         MOZ_ASSERT(arg == nullptr);
 2643         return NumLit(NumLit::Bool32x4, SimdConstant::CreateX4(val));
 2644       }
 2645       default:
 2646         break;
 2647     }
 2648 
 2649     MOZ_CRASH("Unexpected SIMD type.");
 2650 }
 2651 
 2652 static NumLit
 2653 ExtractNumericLiteral(ModuleValidator& m, ParseNode* pn)
 2654 {
 2655     MOZ_ASSERT(IsNumericLiteral(m, pn));
 2656 
 2657     if (pn->isKind(PNK_CALL)) {
 2658         // Float literals are explicitly coerced and thus the coerced literal may be
 2659         // any valid (non-float) numeric literal.
 2660         if (CallArgListLength(pn) == 1) {
 2661             pn = CallArgList(pn);
 2662             double d = ExtractNumericNonFloatValue(pn);
 2663             return NumLit(NumLit::Float, DoubleValue(d));
 2664         }
 2665 
 2666         return ExtractSimdValue(m, pn);
 2667     }
 2668 
 2669     double d = ExtractNumericNonFloatValue(pn, &pn);
 2670 
 2671     // The asm.js spec syntactically distinguishes any literal containing a
 2672     // decimal point or the literal -0 as having double type.
 2673     if (NumberNodeHasFrac(pn) || IsNegativeZero(d))
 2674         return NumLit(NumLit::Double, DoubleValue(d));
 2675 
 2676     // The syntactic checks above rule out these double values.
 2677     MOZ_ASSERT(!IsNegativeZero(d));
 2678     MOZ_ASSERT(!IsNaN(d));
 2679 
 2680     // Although doubles can only *precisely* represent 53-bit integers, they
 2681     // can *imprecisely* represent integers much bigger than an int64_t.
 2682     // Furthermore, d may be inf or -inf. In both cases, casting to an int64_t
 2683     // is undefined, so test against the integer bounds using doubles.
 2684     if (d < double(INT32_MIN) || d > double(UINT32_MAX))
 2685         return NumLit(NumLit::OutOfRangeInt, UndefinedValue());
 2686 
 2687     // With the above syntactic and range limitations, d is definitely an
 2688     // integer in the range [INT32_MIN, UINT32_MAX] range.
 2689     int64_t i64 = int64_t(d);
 2690     if (i64 >= 0) {
 2691         if (i64 <= INT32_MAX)
 2692             return NumLit(NumLit::Fixnum, Int32Value(i64));
 2693         MOZ_ASSERT(i64 <= UINT32_MAX);
 2694         return NumLit(NumLit::BigUnsigned, Int32Value(uint32_t(i64)));
 2695     }
 2696     MOZ_ASSERT(i64 >= INT32_MIN);
 2697     return NumLit(NumLit::NegativeInt, Int32Value(i64));
 2698 }
 2699 
 2700 static inline bool
 2701 IsLiteralInt(const NumLit& lit, uint32_t* u32)
 2702 {
 2703     switch (lit.which()) {
 2704       case NumLit::Fixnum:
 2705       case NumLit::BigUnsigned:
 2706       case NumLit::NegativeInt:
 2707         *u32 = lit.toUint32();
 2708         return true;
 2709       case NumLit::Double:
 2710       case NumLit::Float:
 2711       case NumLit::OutOfRangeInt:
 2712       case NumLit::Int8x16:
 2713       case NumLit::Uint8x16:
 2714       case NumLit::Int16x8:
 2715       case NumLit::Uint16x8:
 2716       case NumLit::Int32x4:
 2717       case NumLit::Uint32x4:
 2718       case NumLit::Float32x4:
 2719       case NumLit::Bool8x16:
 2720       case NumLit::Bool16x8:
 2721       case NumLit::Bool32x4:
 2722         return false;
 2723     }
 2724     MOZ_MAKE_COMPILER_ASSUME_IS_UNREACHABLE("Bad literal type");
 2725 }
 2726 
 2727 static inline bool
 2728 IsLiteralInt(ModuleValidator& m, ParseNode* pn, uint32_t* u32)
 2729 {
 2730     return IsNumericLiteral(m, pn) &&
 2731            IsLiteralInt(ExtractNumericLiteral(m, pn), u32);
 2732 }
 2733 
 2734 /*****************************************************************************/
 2735 
 2736 namespace {
 2737 
 2738 #define CASE(TYPE, OP) case SimdOperation::Fn_##OP: return Op::TYPE##OP;
 2739 #define I8x16CASE(OP) CASE(I8x16, OP)
 2740 #define I16x8CASE(OP) CASE(I16x8, OP)
 2741 #define I32x4CASE(OP) CASE(I32x4, OP)
 2742 #define F32x4CASE(OP) CASE(F32x4, OP)
 2743 #define B8x16CASE(OP) CASE(B8x16, OP)
 2744 #define B16x8CASE(OP) CASE(B16x8, OP)
 2745 #define B32x4CASE(OP) CASE(B32x4, OP)
 2746 #define ENUMERATE(TYPE, FOR_ALL, DO)                                     \
 2747     switch(op) {                                                         \
 2748         case SimdOperation::Constructor: return Op::TYPE##Constructor;   \
 2749         FOR_ALL(DO)                                                      \
 2750         default: break;                                                  \
 2751     }
 2752 
 2753 static inline Op
 2754 SimdToOp(SimdType type, SimdOperation op)
 2755 {
 2756     switch (type) {
 2757       case SimdType::Uint8x16:
 2758         // Handle the special unsigned opcodes, then fall through to Int8x16.
 2759         switch (op) {
 2760           case SimdOperation::Fn_addSaturate:        return Op::I8x16addSaturateU;
 2761           case SimdOperation::Fn_subSaturate:        return Op::I8x16subSaturateU;
 2762           case SimdOperation::Fn_extractLane:        return Op::I8x16extractLaneU;
 2763           case SimdOperation::Fn_shiftRightByScalar: return Op::I8x16shiftRightByScalarU;
 2764           case SimdOperation::Fn_lessThan:           return Op::I8x16lessThanU;
 2765           case SimdOperation::Fn_lessThanOrEqual:    return Op::I8x16lessThanOrEqualU;
 2766           case SimdOperation::Fn_greaterThan:        return Op::I8x16greaterThanU;
 2767           case SimdOperation::Fn_greaterThanOrEqual: return Op::I8x16greaterThanOrEqualU;
 2768           case SimdOperation::Fn_fromInt8x16Bits:    return Op::Limit;
 2769           default: break;
 2770         }
 2771         MOZ_FALLTHROUGH;
 2772       case SimdType::Int8x16:
 2773         // Bitcasts Uint8x16 <--> Int8x16 become noops.
 2774         switch (op) {
 2775           case SimdOperation::Fn_fromUint8x16Bits: return Op::Limit;
 2776           case SimdOperation::Fn_fromUint16x8Bits: return Op::I8x16fromInt16x8Bits;
 2777           case SimdOperation::Fn_fromUint32x4Bits: return Op::I8x16fromInt32x4Bits;
 2778           default: break;
 2779         }
 2780         ENUMERATE(I8x16, FORALL_INT8X16_ASMJS_OP, I8x16CASE)
 2781         break;
 2782 
 2783       case SimdType::Uint16x8:
 2784         // Handle the special unsigned opcodes, then fall through to Int16x8.
 2785         switch(op) {
 2786           case SimdOperation::Fn_addSaturate:        return Op::I16x8addSaturateU;
 2787           case SimdOperation::Fn_subSaturate:        return Op::I16x8subSaturateU;
 2788           case SimdOperation::Fn_extractLane:        return Op::I16x8extractLaneU;
 2789           case SimdOperation::Fn_shiftRightByScalar: return Op::I16x8shiftRightByScalarU;
 2790           case SimdOperation::Fn_lessThan:           return Op::I16x8lessThanU;
 2791           case SimdOperation::Fn_lessThanOrEqual:    return Op::I16x8lessThanOrEqualU;
 2792           case SimdOperation::Fn_greaterThan:        return Op::I16x8greaterThanU;
 2793           case SimdOperation::Fn_greaterThanOrEqual: return Op::I16x8greaterThanOrEqualU;
 2794           case SimdOperation::Fn_fromInt16x8Bits:    return Op::Limit;
 2795           default: break;
 2796         }
 2797         MOZ_FALLTHROUGH;
 2798       case SimdType::Int16x8:
 2799         // Bitcasts Uint16x8 <--> Int16x8 become noops.
 2800         switch (op) {
 2801           case SimdOperation::Fn_fromUint8x16Bits: return Op::I16x8fromInt8x16Bits;
 2802           case SimdOperation::Fn_fromUint16x8Bits: return Op::Limit;
 2803           case SimdOperation::Fn_fromUint32x4Bits: return Op::I16x8fromInt32x4Bits;
 2804           default: break;
 2805         }
 2806         ENUMERATE(I16x8, FORALL_INT16X8_ASMJS_OP, I16x8CASE)
 2807         break;
 2808 
 2809       case SimdType::Uint32x4:
 2810         // Handle the special unsigned opcodes, then fall through to Int32x4.
 2811         switch(op) {
 2812           case SimdOperation::Fn_shiftRightByScalar: return Op::I32x4shiftRightByScalarU;
 2813           case SimdOperation::Fn_lessThan:           return Op::I32x4lessThanU;
 2814           case SimdOperation::Fn_lessThanOrEqual:    return Op::I32x4lessThanOrEqualU;
 2815           case SimdOperation::Fn_greaterThan:        return Op::I32x4greaterThanU;
 2816           case SimdOperation::Fn_greaterThanOrEqual: return Op::I32x4greaterThanOrEqualU;
 2817           case SimdOperation::Fn_fromFloat32x4:      return Op::I32x4fromFloat32x4U;
 2818           case SimdOperation::Fn_fromInt32x4Bits:    return Op::Limit;
 2819           default: break;
 2820         }
 2821         MOZ_FALLTHROUGH;
 2822       case SimdType::Int32x4:
 2823         // Bitcasts Uint32x4 <--> Int32x4 become noops.
 2824         switch (op) {
 2825           case SimdOperation::Fn_fromUint8x16Bits: return Op::I32x4fromInt8x16Bits;
 2826           case SimdOperation::Fn_fromUint16x8Bits: return Op::I32x4fromInt16x8Bits;
 2827           case SimdOperation::Fn_fromUint32x4Bits: return Op::Limit;
 2828           default: break;
 2829         }
 2830         ENUMERATE(I32x4, FORALL_INT32X4_ASMJS_OP, I32x4CASE)
 2831         break;
 2832 
 2833       case SimdType::Float32x4:
 2834         switch (op) {
 2835           case SimdOperation::Fn_fromUint8x16Bits: return Op::F32x4fromInt8x16Bits;
 2836           case SimdOperation::Fn_fromUint16x8Bits: return Op::F32x4fromInt16x8Bits;
 2837           case SimdOperation::Fn_fromUint32x4Bits: return Op::F32x4fromInt32x4Bits;
 2838           default: break;
 2839         }
 2840         ENUMERATE(F32x4, FORALL_FLOAT32X4_ASMJS_OP, F32x4CASE)
 2841         break;
 2842 
 2843       case SimdType::Bool8x16:
 2844         ENUMERATE(B8x16, FORALL_BOOL_SIMD_OP, B8x16CASE)
 2845         break;
 2846 
 2847       case SimdType::Bool16x8:
 2848         ENUMERATE(B16x8, FORALL_BOOL_SIMD_OP, B16x8CASE)
 2849         break;
 2850 
 2851       case SimdType::Bool32x4:
 2852         ENUMERATE(B32x4, FORALL_BOOL_SIMD_OP, B32x4CASE)
 2853         break;
 2854 
 2855       default: break;
 2856     }
 2857     MOZ_CRASH("unexpected SIMD (type, operator) combination");
 2858 }
 2859 
 2860 #undef CASE
 2861 #undef I8x16CASE
 2862 #undef I16x8CASE
 2863 #undef I32x4CASE
 2864 #undef F32x4CASE
 2865 #undef B8x16CASE
 2866 #undef B16x8CASE
 2867 #undef B32x4CASE
 2868 #undef ENUMERATE
 2869 
 2870 typedef Vector<PropertyName*, 4, SystemAllocPolicy> NameVector;
 2871 
 2872 // Encapsulates the building of an asm bytecode function from an asm.js function
 2873 // source code, packing the asm.js code into the asm bytecode form that can
 2874 // be decoded and compiled with a FunctionCompiler.
 2875 class MOZ_STACK_CLASS FunctionValidator
 2876 {
 2877   public:
 2878     struct Local
 2879     {
 2880         Type type;
 2881         unsigned slot;
 2882         Local(Type t, unsigned slot) : type(t), slot(slot) {
 2883             MOZ_ASSERT(type.isCanonicalValType());
 2884         }
 2885     };
 2886 
 2887   private:
 2888     typedef HashMap<PropertyName*, Local> LocalMap;
 2889     typedef HashMap<PropertyName*, uint32_t> LabelMap;
 2890 
 2891     ModuleValidator&  m_;
 2892     ParseNode*        fn_;
 2893 
 2894     FunctionGenerator fg_;
 2895     Maybe<Encoder>    encoder_;
 2896 
 2897     LocalMap          locals_;
 2898 
 2899     // Labels
 2900     LabelMap          breakLabels_;
 2901     LabelMap          continueLabels_;
 2902     Uint32Vector      breakableStack_;
 2903     Uint32Vector      continuableStack_;
 2904     uint32_t          blockDepth_;
 2905 
 2906     bool              hasAlreadyReturned_;
 2907     ExprType          ret_;
 2908 
 2909   public:
 2910     FunctionValidator(ModuleValidator& m, ParseNode* fn)
 2911       : m_(m),
 2912         fn_(fn),
 2913         locals_(m.cx()),
 2914         breakLabels_(m.cx()),
 2915         continueLabels_(m.cx()),
 2916         blockDepth_(0),
 2917         hasAlreadyReturned_(false),
 2918         ret_(ExprType::Limit)
 2919     {}
 2920 
 2921     ModuleValidator& m() const        { return m_; }
 2922     ExclusiveContext* cx() const      { return m_.cx(); }
 2923     ParseNode* fn() const             { return fn_; }
 2924 
 2925     bool init(PropertyName* name, unsigned line) {
 2926         if (!locals_.init() || !breakLabels_.init() || !continueLabels_.init())
 2927             return false;
 2928 
 2929         if (!m_.mg().startFuncDef(line, &fg_))
 2930             return false;
 2931 
 2932         encoder_.emplace(fg_.bytes());
 2933         return true;
 2934     }
 2935 
 2936     bool finish(uint32_t funcIndex) {
 2937         MOZ_ASSERT(!blockDepth_);
 2938         MOZ_ASSERT(breakableStack_.empty());
 2939         MOZ_ASSERT(continuableStack_.empty());
 2940         MOZ_ASSERT(breakLabels_.empty());
 2941         MOZ_ASSERT(continueLabels_.empty());
 2942         for (auto iter = locals_.all(); !iter.empty(); iter.popFront()) {
 2943             if (iter.front().value().type.isSimd()) {
 2944                 setUsesSimd();
 2945                 break;
 2946             }
 2947         }
 2948 
 2949         return m_.mg().finishFuncDef(funcIndex, &fg_);
 2950     }
 2951 
 2952     bool fail(ParseNode* pn, const char* str) {
 2953         return m_.fail(pn, str);
 2954     }
 2955 
 2956     bool failf(ParseNode* pn, const char* fmt, ...) MOZ_FORMAT_PRINTF(3, 4) {
 2957         va_list ap;
 2958         va_start(ap, fmt);
 2959         m_.failfVAOffset(pn->pn_pos.begin, fmt, ap);
 2960         va_end(ap);
 2961         return false;
 2962     }
 2963 
 2964     bool failName(ParseNode* pn, const char* fmt, PropertyName* name) {
 2965         return m_.failName(pn, fmt, name);
 2966     }
 2967 
 2968     /***************************************************** Attributes */
 2969 
 2970     void setUsesSimd() {
 2971         fg_.setUsesSimd();
 2972     }
 2973 
 2974     void setUsesAtomics() {
 2975         fg_.setUsesAtomics();
 2976     }
 2977 
 2978     /***************************************************** Local scope setup */
 2979 
 2980     bool addLocal(ParseNode* pn, PropertyName* name, Type type) {
 2981         LocalMap::AddPtr p = locals_.lookupForAdd(name);
 2982         if (p)
 2983             return failName(pn, "duplicate local name '%s' not allowed", name);
 2984         return locals_.add(p, name, Local(type, locals_.count()));
 2985     }
 2986 
 2987     /****************************** For consistency of returns in a function */
 2988 
 2989     bool hasAlreadyReturned() const {
 2990         return hasAlreadyReturned_;
 2991     }
 2992 
 2993     ExprType returnedType() const {
 2994         return ret_;
 2995     }
 2996 
 2997     void setReturnedType(ExprType ret) {
 2998         ret_ = ret;
 2999         hasAlreadyReturned_ = true;
 3000     }
 3001 
 3002     /**************************************************************** Labels */
 3003   private:
 3004     bool writeBr(uint32_t absolute, Op op = Op::Br) {
 3005         MOZ_ASSERT(op == Op::Br || op == Op::BrIf);
 3006         MOZ_ASSERT(absolute < blockDepth_);
 3007         return encoder().writeOp(op) &&
 3008                encoder().writeVarU32(blockDepth_ - 1 - absolute);
 3009     }
 3010     void removeLabel(PropertyName* label, LabelMap* map) {
 3011         LabelMap::Ptr p = map->lookup(label);
 3012         MOZ_ASSERT(p);
 3013         map->remove(p);
 3014     }
 3015 
 3016   public:
 3017     bool pushBreakableBlock() {
 3018         return encoder().writeOp(Op::Block) &&
 3019                encoder().writeFixedU8(uint8_t(ExprType::Void)) &&
 3020                breakableStack_.append(blockDepth_++);
 3021     }
 3022     bool popBreakableBlock() {
 3023         JS_ALWAYS_TRUE(breakableStack_.popCopy() == --blockDepth_);
 3024         return encoder().writeOp(Op::End);
 3025     }
 3026 
 3027     bool pushUnbreakableBlock(const NameVector* labels = nullptr) {
 3028         if (labels) {
 3029             for (PropertyName* label : *labels) {
 3030                 if (!breakLabels_.putNew(label, blockDepth_))
 3031                     return false;
 3032             }
 3033         }
 3034         blockDepth_++;
 3035         return encoder().writeOp(Op::Block) &&
 3036                encoder().writeFixedU8(uint8_t(ExprType::Void));
 3037     }
 3038     bool popUnbreakableBlock(const NameVector* labels = nullptr) {
 3039         if (labels) {
 3040             for (PropertyName* label : *labels)
 3041                 removeLabel(label, &breakLabels_);
 3042         }
 3043         --blockDepth_;
 3044         return encoder().writeOp(Op::End);
 3045     }
 3046 
 3047     bool pushContinuableBlock() {
 3048         return encoder().writeOp(Op::Block) &&
 3049                encoder().writeFixedU8(uint8_t(ExprType::Void)) &&
 3050                continuableStack_.append(blockDepth_++);
 3051     }
 3052     bool popContinuableBlock() {
 3053         JS_ALWAYS_TRUE(continuableStack_.popCopy() == --blockDepth_);
 3054         return encoder().writeOp(Op::End);
 3055     }
 3056 
 3057     bool pushLoop() {
 3058         return encoder().writeOp(Op::Block) &&
 3059                encoder().writeFixedU8(uint8_t(ExprType::Void)) &&
 3060                encoder().writeOp(Op::Loop) &&
 3061                encoder().writeFixedU8(uint8_t(ExprType::Void)) &&
 3062                breakableStack_.append(blockDepth_++) &&
 3063                continuableStack_.append(blockDepth_++);
 3064     }
 3065     bool popLoop() {
 3066         JS_ALWAYS_TRUE(continuableStack_.popCopy() == --blockDepth_);
 3067         JS_ALWAYS_TRUE(breakableStack_.popCopy() == --blockDepth_);
 3068         return encoder().writeOp(Op::End) &&
 3069                encoder().writeOp(Op::End);
 3070     }
 3071 
 3072     bool pushIf(size_t* typeAt) {
 3073         ++blockDepth_;
 3074         return encoder().writeOp(Op::If) &&
 3075                encoder().writePatchableFixedU7(typeAt);
 3076     }
 3077     bool switchToElse() {
 3078         MOZ_ASSERT(blockDepth_ > 0);
 3079         return encoder().writeOp(Op::Else);
 3080     }
 3081     void setIfType(size_t typeAt, ExprType type) {
 3082         encoder().patchFixedU7(typeAt, uint8_t(type));
 3083     }
 3084     bool popIf() {
 3085         MOZ_ASSERT(blockDepth_ > 0);
 3086         --blockDepth_;
 3087         return encoder().writeOp(Op::End);
 3088     }
 3089     bool popIf(size_t typeAt, ExprType type) {
 3090         MOZ_ASSERT(blockDepth_ > 0);
 3091         --blockDepth_;
 3092         if (!encoder().writeOp(Op::End))
 3093             return false;
 3094 
 3095         setIfType(typeAt, type);
 3096         return true;
 3097     }
 3098 
 3099     bool writeBreakIf() {
 3100         return writeBr(breakableStack_.back(), Op::BrIf);
 3101     }
 3102     bool writeContinueIf() {
 3103         return writeBr(continuableStack_.back(), Op::BrIf);
 3104     }
 3105     bool writeUnlabeledBreakOrContinue(bool isBreak) {
 3106         return writeBr(isBreak? breakableStack_.back() : continuableStack_.back());
 3107     }
 3108     bool writeContinue() {
 3109         return writeBr(continuableStack_.back());
 3110     }
 3111 
 3112     bool addLabels(const NameVector& labels, uint32_t relativeBreakDepth,
 3113                    uint32_t relativeContinueDepth)
 3114     {
 3115         for (PropertyName* label : labels) {
 3116             if (!breakLabels_.putNew(label, blockDepth_ + relativeBreakDepth))
 3117                 return false;
 3118             if (!continueLabels_.putNew(label, blockDepth_ + relativeContinueDepth))
 3119                 return false;
 3120         }
 3121         return true;
 3122     }
 3123     void removeLabels(const NameVector& labels) {
 3124         for (PropertyName* label : labels) {
 3125             removeLabel(label, &breakLabels_);
 3126             removeLabel(label, &continueLabels_);
 3127         }
 3128     }
 3129     bool writeLabeledBreakOrContinue(PropertyName* label, bool isBreak) {
 3130         LabelMap& map = isBreak ? breakLabels_ : continueLabels_;
 3131         if (LabelMap::Ptr p = map.lookup(label))
 3132             return writeBr(p->value());
 3133         MOZ_CRASH("nonexistent label");
 3134     }
 3135 
 3136     /*************************************************** Read-only interface */
 3137 
 3138     const Local* lookupLocal(PropertyName* name) const {
 3139         if (auto p = locals_.lookup(name))
 3140             return &p->value();
 3141         return nullptr;
 3142     }
 3143 
 3144     const ModuleValidator::Global* lookupGlobal(PropertyName* name) const {
 3145         if (locals_.has(name))
 3146             return nullptr;
 3147         return m_.lookupGlobal(name);
 3148     }
 3149 
 3150     size_t numLocals() const { return locals_.count(); }
 3151 
 3152     /**************************************************** Encoding interface */
 3153 
 3154     Encoder& encoder() { return *encoder_; }
 3155 
 3156     MOZ_MUST_USE bool writeInt32Lit(int32_t i32) {
 3157         return encoder().writeOp(Op::I32Const) &&
 3158                encoder().writeVarS32(i32);
 3159     }
 3160     MOZ_MUST_USE bool writeConstExpr(const NumLit& lit) {
 3161         switch (lit.which()) {
 3162           case NumLit::Fixnum:
 3163           case NumLit::NegativeInt:
 3164           case NumLit::BigUnsigned:
 3165             return writeInt32Lit(lit.toInt32());
 3166           case NumLit::Float:
 3167             return encoder().writeOp(Op::F32Const) &&
 3168                    encoder().writeFixedF32(lit.toFloat());
 3169           case NumLit::Double:
 3170             return encoder().writeOp(Op::F64Const) &&
 3171                    encoder().writeFixedF64(lit.toDouble());
 3172           case NumLit::Int8x16:
 3173           case NumLit::Uint8x16:
 3174             return encoder().writeOp(Op::I8x16Const) &&
 3175                    encoder().writeFixedI8x16(lit.simdValue().asInt8x16());
 3176           case NumLit::Int16x8:
 3177           case NumLit::Uint16x8:
 3178             return encoder().writeOp(Op::I16x8Const) &&
 3179                    encoder().writeFixedI16x8(lit.simdValue().asInt16x8());
 3180           case NumLit::Int32x4:
 3181           case NumLit::Uint32x4:
 3182             return encoder().writeOp(Op::I32x4Const) &&
 3183                    encoder().writeFixedI32x4(lit.simdValue().asInt32x4());
 3184           case NumLit::Float32x4:
 3185             return encoder().writeOp(Op::F32x4Const) &&
 3186                    encoder().writeFixedF32x4(lit.simdValue().asFloat32x4());
 3187           case NumLit::Bool8x16:
 3188             // Boolean vectors use the Int8x16 memory representation.
 3189             return encoder().writeOp(Op::B8x16Const) &&
 3190                    encoder().writeFixedI8x16(lit.simdValue().asInt8x16());
 3191           case NumLit::Bool16x8:
 3192             // Boolean vectors use the Int16x8 memory representation.
 3193             return encoder().writeOp(Op::B16x8Const) &&
 3194                    encoder().writeFixedI16x8(lit.simdValue().asInt16x8());
 3195           case NumLit::Bool32x4:
 3196             // Boolean vectors use the Int32x4 memory representation.
 3197             return encoder().writeOp(Op::B32x4Const) &&
 3198                    encoder().writeFixedI32x4(lit.simdValue().asInt32x4());
 3199           case NumLit::OutOfRangeInt:
 3200             break;
 3201         }
 3202         MOZ_CRASH("unexpected literal type");
 3203     }
 3204     MOZ_MUST_USE bool writeCall(ParseNode* pn, Op op) {
 3205         return encoder().writeOp(op) &&
 3206                fg_.addCallSiteLineNum(m().tokenStream().srcCoords.lineNum(pn->pn_pos.begin));
 3207     }
 3208     MOZ_MUST_USE bool prepareCall(ParseNode* pn) {
 3209         return fg_.addCallSiteLineNum(m().tokenStream().srcCoords.lineNum(pn->pn_pos.begin));
 3210     }
 3211     MOZ_MUST_USE bool writeSimdOp(SimdType simdType, SimdOperation simdOp) {
 3212         Op op = SimdToOp(simdType, simdOp);
 3213         if (op == Op::Limit)
 3214             return true;
 3215         return encoder().writeOp(op);
 3216     }
 3217 };
 3218 
 3219 } /* anonymous namespace */
 3220 
 3221 /*****************************************************************************/
 3222 // asm.js type-checking and code-generation algorithm
 3223 
 3224 static bool
 3225 CheckIdentifier(ModuleValidator& m, ParseNode* usepn, PropertyName* name)
 3226 {
 3227     if (name == m.cx()->names().arguments || name == m.cx()->names().eval)
 3228         return m.failName(usepn, "'%s' is not an allowed identifier", name);
 3229     return true;
 3230 }
 3231 
 3232 static bool
 3233 CheckModuleLevelName(ModuleValidator& m, ParseNode* usepn, PropertyName* name)
 3234 {
 3235     if (!CheckIdentifier(m, usepn, name))
 3236         return false;
 3237 
 3238     if (name == m.moduleFunctionName() ||
 3239         name == m.globalArgumentName() ||
 3240         name == m.importArgumentName() ||
 3241         name == m.bufferArgumentName() ||
 3242         m.lookupGlobal(name))
 3243     {
 3244         return m.failName(usepn, "duplicate name '%s' not allowed", name);
 3245     }
 3246 
 3247     return true;
 3248 }
 3249 
 3250 static bool
 3251 CheckFunctionHead(ModuleValidator& m, ParseNode* fn)
 3252 {
 3253     JSFunction* fun = FunctionObject(fn);
 3254     if (fn->pn_funbox->hasRest())
 3255         return m.fail(fn, "rest args not allowed");
 3256     if (fun->isExprBody())
 3257         return m.fail(fn, "expression closures not allowed");
 3258     if (fn->pn_funbox->hasDestructuringArgs)
 3259         return m.fail(fn, "destructuring args not allowed");
 3260     return true;
 3261 }
 3262 
 3263 static bool
 3264 CheckArgument(ModuleValidator& m, ParseNode* arg, PropertyName** name)
 3265 {
 3266     *name = nullptr;
 3267 
 3268     if (!arg->isKind(PNK_NAME))
 3269         return m.fail(arg, "argument is not a plain name");
 3270 
 3271     if (!CheckIdentifier(m, arg, arg->name()))
 3272         return false;
 3273 
 3274     *name = arg->name();
 3275     return true;
 3276 }
 3277 
 3278 static bool
 3279 CheckModuleArgument(ModuleValidator& m, ParseNode* arg, PropertyName** name)
 3280 {
 3281     if (!CheckArgument(m, arg, name))
 3282         return false;
 3283 
 3284     if (!CheckModuleLevelName(m, arg, *name))
 3285         return false;
 3286 
 3287     return true;
 3288 }
 3289 
 3290 static bool
 3291 CheckModuleArguments(ModuleValidator& m, ParseNode* fn)
 3292 {
 3293     unsigned numFormals;
 3294     ParseNode* arg1 = FunctionFormalParametersList(fn, &numFormals);
 3295     ParseNode* arg2 = arg1 ? NextNode(arg1) : nullptr;
 3296     ParseNode* arg3 = arg2 ? NextNode(arg2) : nullptr;
 3297 
 3298     if (numFormals > 3)
 3299         return m.fail(fn, "asm.js modules takes at most 3 argument");
 3300 
 3301     PropertyName* arg1Name = nullptr;
 3302     if (arg1 && !CheckModuleArgument(m, arg1, &arg1Name))
 3303         return false;
 3304     if (!m.initGlobalArgumentName(arg1Name))
 3305         return false;
 3306 
 3307     PropertyName* arg2Name = nullptr;
 3308     if (arg2 && !CheckModuleArgument(m, arg2, &arg2Name))
 3309         return false;
 3310     if (!m.initImportArgumentName(arg2Name))
 3311         return false;
 3312 
 3313     PropertyName* arg3Name = nullptr;
 3314     if (arg3 && !CheckModuleArgument(m, arg3, &arg3Name))
 3315         return false;
 3316     if (!m.initBufferArgumentName(arg3Name))
 3317         return false;
 3318 
 3319     return true;
 3320 }
 3321 
 3322 static bool
 3323 CheckPrecedingStatements(ModuleValidator& m, ParseNode* stmtList)
 3324 {
 3325     MOZ_ASSERT(stmtList->isKind(PNK_STATEMENTLIST));
 3326 
 3327     ParseNode* stmt = ListHead(stmtList);
 3328     for (unsigned i = 0, n = ListLength(stmtList); i < n; i++) {
 3329         if (!IsIgnoredDirective(m.cx(), stmt))
 3330             return m.fail(stmt, "invalid asm.js statement");
 3331     }
 3332 
 3333     return true;
 3334 }
 3335 
 3336 static bool
 3337 CheckGlobalVariableInitConstant(ModuleValidator& m, PropertyName* varName, ParseNode* initNode,
 3338                                 bool isConst)
 3339 {
 3340     NumLit lit = ExtractNumericLiteral(m, initNode);
 3341     if (!lit.valid())
 3342         return m.fail(initNode, "global initializer is out of representable integer range");
 3343 
 3344     Type canonicalType = Type::canonicalize(Type::lit(lit));
 3345     if (!canonicalType.isGlobalVarType())
 3346         return m.fail(initNode, "global variable type not allowed");
 3347 
 3348     return m.addGlobalVarInit(varName, lit, canonicalType, isConst);
 3349 }
 3350 
 3351 static bool
 3352 CheckTypeAnnotation(ModuleValidator& m, ParseNode* coercionNode, Type* coerceTo,
 3353                     ParseNode** coercedExpr = nullptr)
 3354 {
 3355     switch (coercionNode->getKind()) {
 3356       case PNK_BITOR: {
 3357         ParseNode* rhs = BitwiseRight(coercionNode);
 3358         uint32_t i;
 3359         if (!IsLiteralInt(m, rhs, &i) || i != 0)
 3360             return m.fail(rhs, "must use |0 for argument/return coercion");
 3361         *coerceTo = Type::Int;
 3362         if (coercedExpr)
 3363             *coercedExpr = BitwiseLeft(coercionNode);
 3364         return true;
 3365       }
 3366       case PNK_POS: {
 3367         *coerceTo = Type::Double;
 3368         if (coercedExpr)
 3369             *coercedExpr = UnaryKid(coercionNode);
 3370         return true;
 3371       }
 3372       case PNK_CALL: {
 3373         if (IsCoercionCall(m, coercionNode, coerceTo, coercedExpr))
 3374             return true;
 3375         break;
 3376       }
 3377       default:;
 3378     }
 3379 
 3380     return m.fail(coercionNode, "must be of the form +x, x|0, fround(x), or a SIMD check(x)");
 3381 }
 3382 
 3383 static bool
 3384 CheckGlobalVariableInitImport(ModuleValidator& m, PropertyName* varName, ParseNode* initNode,
 3385                               bool isConst)
 3386 {
 3387     Type coerceTo;
 3388     ParseNode* coercedExpr;
 3389     if (!CheckTypeAnnotation(m, initNode, &coerceTo, &coercedExpr))
 3390         return false;
 3391 
 3392     if (!coercedExpr->isKind(PNK_DOT))
 3393         return m.failName(coercedExpr, "invalid import expression for global '%s'", varName);
 3394 
 3395     if (!coerceTo.isGlobalVarType())
 3396         return m.fail(initNode, "global variable type not allowed");
 3397 
 3398     ParseNode* base = DotBase(coercedExpr);
 3399     PropertyName* field = DotMember(coercedExpr);
 3400 
 3401     PropertyName* importName = m.importArgumentName();
 3402     if (!importName)
 3403         return m.fail(coercedExpr, "cannot import without an asm.js foreign parameter");
 3404     if (!IsUseOfName(base, importName))
 3405         return m.failName(coercedExpr, "base of import expression must be '%s'", importName);
 3406 
 3407     return m.addGlobalVarImport(varName, field, coerceTo, isConst);
 3408 }
 3409 
 3410 static bool
 3411 IsArrayViewCtorName(ModuleValidator& m, PropertyName* name, Scalar::Type* type)
 3412 {
 3413     JSAtomState& names = m.cx()->names();
 3414     if (name == names.Int8Array) {
 3415         *type = Scalar::Int8;
 3416     } else if (name == names.Uint8Array) {
 3417         *type = Scalar::Uint8;
 3418     } else if (name == names.Int16Array) {
 3419         *type = Scalar::Int16;
 3420     } else if (name == names.Uint16Array) {
 3421         *type = Scalar::Uint16;
 3422     } else if (name == names.Int32Array) {
 3423         *type = Scalar::Int32;
 3424     } else if (name == names.Uint32Array) {
 3425         *type = Scalar::Uint32;
 3426     } else if (name == names.Float32Array) {
 3427         *type = Scalar::Float32;
 3428     } else if (name == names.Float64Array) {
 3429         *type = Scalar::Float64;
 3430     } else {
 3431         return false;
 3432     }
 3433     return true;
 3434 }
 3435 
 3436 static bool
 3437 CheckNewArrayViewArgs(ModuleValidator& m, ParseNode* ctorExpr, PropertyName* bufferName)
 3438 {
 3439     ParseNode* bufArg = NextNode(ctorExpr);
 3440     if (!bufArg || NextNode(bufArg) != nullptr)
 3441         return m.fail(ctorExpr, "array view constructor takes exactly one argument");
 3442 
 3443     if (!IsUseOfName(bufArg, bufferName))
 3444         return m.failName(bufArg, "argument to array view constructor must be '%s'", bufferName);
 3445 
 3446     return true;
 3447 }
 3448 
 3449 static bool
 3450 CheckNewArrayView(ModuleValidator& m, PropertyName* varName, ParseNode* newExpr)
 3451 {
 3452     PropertyName* globalName = m.globalArgumentName();
 3453     if (!globalName)
 3454         return m.fail(newExpr, "cannot create array view without an asm.js global parameter");
 3455 
 3456     PropertyName* bufferName = m.bufferArgumentName();
 3457     if (!bufferName)
 3458         return m.fail(newExpr, "cannot create array view without an asm.js heap parameter");
 3459 
 3460     ParseNode* ctorExpr = ListHead(newExpr);
 3461 
 3462     PropertyName* field;
 3463     Scalar::Type type;
 3464     if (ctorExpr->isKind(PNK_DOT)) {
 3465         ParseNode* base = DotBase(ctorExpr);
 3466 
 3467         if (!IsUseOfName(base, globalName))
 3468             return m.failName(base, "expecting '%s.*Array", globalName);
 3469 
 3470         field = DotMember(ctorExpr);
 3471         if (!IsArrayViewCtorName(m, field, &type))
 3472             return m.fail(ctorExpr, "could not match typed array name");
 3473     } else {
 3474         if (!ctorExpr->isKind(PNK_NAME))
 3475             return m.fail(ctorExpr, "expecting name of imported array view constructor");
 3476 
 3477         PropertyName* globalName = ctorExpr->name();
 3478         const ModuleValidator::Global* global = m.lookupGlobal(globalName);
 3479         if (!global)
 3480             return m.failName(ctorExpr, "%s not found in module global scope", globalName);
 3481 
 3482         if (global->which() != ModuleValidator::Global::ArrayViewCtor)
 3483             return m.failName(ctorExpr, "%s must be an imported array view constructor", globalName);
 3484 
 3485         field = nullptr;
 3486         type = global->viewType();
 3487     }
 3488 
 3489     if (!CheckNewArrayViewArgs(m, ctorExpr, bufferName))
 3490         return false;
 3491 
 3492     return m.addArrayView(varName, type, field);
 3493 }
 3494 
 3495 static bool
 3496 IsSimdValidOperationType(SimdType type, SimdOperation op)
 3497 {
 3498 #define CASE(op) case SimdOperation::Fn_##op:
 3499     switch(type) {
 3500       case SimdType::Int8x16:
 3501         switch (op) {
 3502           case SimdOperation::Constructor:
 3503           case SimdOperation::Fn_fromUint8x16Bits:
 3504           case SimdOperation::Fn_fromUint16x8Bits:
 3505           case SimdOperation::Fn_fromUint32x4Bits:
 3506           FORALL_INT8X16_ASMJS_OP(CASE) return true;
 3507           default: return false;
 3508         }
 3509         break;
 3510       case SimdType::Int16x8:
 3511         switch (op) {
 3512           case SimdOperation::Constructor:
 3513           case SimdOperation::Fn_fromUint8x16Bits:
 3514           case SimdOperation::Fn_fromUint16x8Bits:
 3515           case SimdOperation::Fn_fromUint32x4Bits:
 3516           FORALL_INT16X8_ASMJS_OP(CASE) return true;
 3517           default: return false;
 3518         }
 3519         break;
 3520       case SimdType::Int32x4:
 3521         switch (op) {
 3522           case SimdOperation::Constructor:
 3523           case SimdOperation::Fn_fromUint8x16Bits:
 3524           case SimdOperation::Fn_fromUint16x8Bits:
 3525           case SimdOperation::Fn_fromUint32x4Bits:
 3526           FORALL_INT32X4_ASMJS_OP(CASE) return true;
 3527           default: return false;
 3528         }
 3529         break;
 3530       case SimdType::Uint8x16:
 3531         switch (op) {
 3532           case SimdOperation::Constructor:
 3533           case SimdOperation::Fn_fromInt8x16Bits:
 3534           case SimdOperation::Fn_fromUint16x8Bits:
 3535           case SimdOperation::Fn_fromUint32x4Bits:
 3536           FORALL_INT8X16_ASMJS_OP(CASE) return true;
 3537           default: return false;
 3538         }
 3539         break;
 3540       case SimdType::Uint16x8:
 3541         switch (op) {
 3542           case SimdOperation::Constructor:
 3543           case SimdOperation::Fn_fromUint8x16Bits:
 3544           case SimdOperation::Fn_fromInt16x8Bits:
 3545           case SimdOperation::Fn_fromUint32x4Bits:
 3546           FORALL_INT16X8_ASMJS_OP(CASE) return true;
 3547           default: return false;
 3548         }
 3549         break;
 3550       case SimdType::Uint32x4:
 3551         switch (op) {
 3552           case SimdOperation::Constructor:
 3553           case SimdOperation::Fn_fromUint8x16Bits:
 3554           case SimdOperation::Fn_fromUint16x8Bits:
 3555           case SimdOperation::Fn_fromInt32x4Bits:
 3556           FORALL_INT32X4_ASMJS_OP(CASE) return true;
 3557           default: return false;
 3558         }
 3559         break;
 3560       case SimdType::Float32x4:
 3561         switch (op) {
 3562           case SimdOperation::Constructor:
 3563           case SimdOperation::Fn_fromUint8x16Bits:
 3564           case SimdOperation::Fn_fromUint16x8Bits:
 3565           case SimdOperation::Fn_fromUint32x4Bits:
 3566           FORALL_FLOAT32X4_ASMJS_OP(CASE) return true;
 3567           default: return false;
 3568         }
 3569         break;
 3570       case SimdType::Bool8x16:
 3571       case SimdType::Bool16x8:
 3572       case SimdType::Bool32x4:
 3573         switch (op) {
 3574           case SimdOperation::Constructor:
 3575           FORALL_BOOL_SIMD_OP(CASE) return true;
 3576           default: return false;
 3577         }
 3578         break;
 3579       default:
 3580         // Unimplemented SIMD type.
 3581         return false;
 3582     }
 3583 #undef CASE
 3584 }
 3585 
 3586 static bool
 3587 CheckGlobalMathImport(ModuleValidator& m, ParseNode* initNode, PropertyName* varName,
 3588                       PropertyName* field)
 3589 {
 3590     // Math builtin, with the form glob.Math.[[builtin]]
 3591     ModuleValidator::MathBuiltin mathBuiltin;
 3592     if (!m.lookupStandardLibraryMathName(field, &mathBuiltin))
 3593         return m.failName(initNode, "'%s' is not a standard Math builtin", field);
 3594 
 3595     switch (mathBuiltin.kind) {
 3596       case ModuleValidator::MathBuiltin::Function:
 3597         return m.addMathBuiltinFunction(varName, mathBuiltin.u.func, field);
 3598       case ModuleValidator::MathBuiltin::Constant:
 3599         return m.addMathBuiltinConstant(varName, mathBuiltin.u.cst, field);
 3600       default:
 3601         break;
 3602     }
 3603     MOZ_CRASH("unexpected or uninitialized math builtin type");
 3604 }
 3605 
 3606 static bool
 3607 CheckGlobalAtomicsImport(ModuleValidator& m, ParseNode* initNode, PropertyName* varName,
 3608                          PropertyName* field)
 3609 {
 3610     // Atomics builtin, with the form glob.Atomics.[[builtin]]
 3611     AsmJSAtomicsBuiltinFunction func;
 3612     if (!m.lookupStandardLibraryAtomicsName(field, &func))
 3613         return m.failName(initNode, "'%s' is not a standard Atomics builtin", field);
 3614 
 3615     return m.addAtomicsBuiltinFunction(varName, func, field);
 3616 }
 3617 
 3618 static bool
 3619 CheckGlobalSimdImport(ModuleValidator& m, ParseNode* initNode, PropertyName* varName,
 3620                       PropertyName* field)
 3621 {
 3622     if (!m.supportsSimd())
 3623         return m.fail(initNode, "SIMD is not supported on this platform");
 3624 
 3625     // SIMD constructor, with the form glob.SIMD.[[type]]
 3626     SimdType simdType;
 3627     if (!IsSimdTypeName(m.cx()->names(), field, &simdType))
 3628         return m.failName(initNode, "'%s' is not a standard SIMD type", field);
 3629 
 3630     // IsSimdTypeName will return true for any SIMD type supported by the VM.
 3631     //
 3632     // Since we may not support all of those SIMD types in asm.js, use the
 3633     // asm.js-specific IsSimdValidOperationType() to check if this specific
 3634     // constructor is supported in asm.js.
 3635     if (!IsSimdValidOperationType(simdType, SimdOperation::Constructor))
 3636         return m.failName(initNode, "'%s' is not a supported SIMD type", field);
 3637 
 3638     return m.addSimdCtor(varName, simdType, field);
 3639 }
 3640 
 3641 static bool
 3642 CheckGlobalSimdOperationImport(ModuleValidator& m, const ModuleValidator::Global* global,
 3643                                ParseNode* initNode, PropertyName* varName, PropertyName* opName)
 3644 {
 3645     SimdType simdType = global->simdCtorType();
 3646     SimdOperation simdOp;
 3647     if (!m.lookupStandardSimdOpName(opName, &simdOp))
 3648         return m.failName(initNode, "'%s' is not a standard SIMD operation", opName);
 3649     if (!IsSimdValidOperationType(simdType, simdOp))
 3650         return m.failName(initNode, "'%s' is not an operation supported by the SIMD type", opName);
 3651     return m.addSimdOperation(varName, simdType, simdOp, opName);
 3652 }
 3653 
 3654 static bool
 3655 CheckGlobalDotImport(ModuleValidator& m, PropertyName* varName, ParseNode* initNode)
 3656 {
 3657     ParseNode* base = DotBase(initNode);
 3658     PropertyName* field = DotMember(initNode);
 3659 
 3660     if (base->isKind(PNK_DOT)) {
 3661         ParseNode* global = DotBase(base);
 3662         PropertyName* mathOrAtomicsOrSimd = DotMember(base);
 3663 
 3664         PropertyName* globalName = m.globalArgumentName();
 3665         if (!globalName)
 3666             return m.fail(base, "import statement requires the module have a stdlib parameter");
 3667 
 3668         if (!IsUseOfName(global, globalName)) {
 3669             if (global->isKind(PNK_DOT)) {
 3670                 return m.failName(base, "imports can have at most two dot accesses "
 3671                                         "(e.g. %s.Math.sin)", globalName);
 3672             }
 3673             return m.failName(base, "expecting %s.*", globalName);
 3674         }
 3675 
 3676         if (mathOrAtomicsOrSimd == m.cx()->names().Math)
 3677             return CheckGlobalMathImport(m, initNode, varName, field);
 3678         if (mathOrAtomicsOrSimd == m.cx()->names().Atomics)
 3679             return CheckGlobalAtomicsImport(m, initNode, varName, field);
 3680         if (mathOrAtomicsOrSimd == m.cx()->names().SIMD)
 3681             return CheckGlobalSimdImport(m, initNode, varName, field);
 3682         return m.failName(base, "expecting %s.{Math|SIMD}", globalName);
 3683     }
 3684 
 3685     if (!base->isKind(PNK_NAME))
 3686         return m.fail(base, "expected name of variable or parameter");
 3687 
 3688     if (base->name() == m.globalArgumentName()) {
 3689         if (field == m.cx()->names().NaN)
 3690             return m.addGlobalConstant(varName, GenericNaN(), field);
 3691         if (field == m.cx()->names().Infinity)
 3692             return m.addGlobalConstant(varName, PositiveInfinity<double>(), field);
 3693 
 3694         Scalar::Type type;
 3695         if (IsArrayViewCtorName(m, field, &type))
 3696             return m.addArrayViewCtor(varName, type, field);
 3697 
 3698         return m.failName(initNode, "'%s' is not a standard constant or typed array name", field);
 3699     }
 3700 
 3701     if (base->name() == m.importArgumentName())
 3702         return m.addFFI(varName, field);
 3703 
 3704     const ModuleValidator::Global* global = m.lookupGlobal(base->name());
 3705     if (!global)
 3706         return m.failName(initNode, "%s not found in module global scope", base->name());
 3707 
 3708     if (!global->isSimdCtor())
 3709         return m.failName(base, "expecting SIMD constructor name, got %s", field);
 3710 
 3711     return CheckGlobalSimdOperationImport(m, global, initNode, varName, field);
 3712 }
 3713 
 3714 static bool
 3715 CheckModuleGlobal(ModuleValidator& m, ParseNode* var, bool isConst)
 3716 {
 3717     if (!var->isKind(PNK_NAME))
 3718         return m.fail(var, "import variable is not a plain name");
 3719 
 3720     if (!CheckModuleLevelName(m, var, var->name()))
 3721         return false;
 3722 
 3723     ParseNode* initNode = MaybeInitializer(var);
 3724     if (!initNode)
 3725         return m.fail(var, "module import needs initializer");
 3726 
 3727     if (IsNumericLiteral(m, initNode))
 3728         return CheckGlobalVariableInitConstant(m, var->name(), initNode, isConst);
 3729 
 3730     if (initNode->isKind(PNK_BITOR) || initNode->isKind(PNK_POS) || initNode->isKind(PNK_CALL))
 3731         return CheckGlobalVariableInitImport(m, var->name(), initNode, isConst);
 3732 
 3733     if (initNode->isKind(PNK_NEW))
 3734         return CheckNewArrayView(m, var->name(), initNode);
 3735 
 3736     if (initNode->isKind(PNK_DOT))
 3737         return CheckGlobalDotImport(m, var->name(), initNode);
 3738 
 3739     return m.fail(initNode, "unsupported import expression");
 3740 }
 3741 
 3742 static bool
 3743 CheckModuleProcessingDirectives(ModuleValidator& m)
 3744 {
 3745     TokenStream& ts = m.parser().tokenStream;
 3746     while (true) {
 3747         bool matched;
 3748         if (!ts.matchToken(&matched, TOK_STRING, TokenStream::Operand))
 3749             return false;
 3750         if (!matched)
 3751             return true;
 3752 
 3753         if (!IsIgnoredDirectiveName(m.cx(), ts.currentToken().atom()))
 3754             return m.failCurrentOffset("unsupported processing directive");
 3755 
 3756         TokenKind tt;
 3757         if (!ts.getToken(&tt))
 3758             return false;
 3759         if (tt != TOK_SEMI)
 3760             return m.failCurrentOffset("expected semicolon after string literal");
 3761     }
 3762 }
 3763 
 3764 static bool
 3765 CheckModuleGlobals(ModuleValidator& m)
 3766 {
 3767     while (true) {
 3768         ParseNode* varStmt;
 3769         if (!ParseVarOrConstStatement(m.parser(), &varStmt))
 3770             return false;
 3771         if (!varStmt)
 3772             break;
 3773         for (ParseNode* var = VarListHead(varStmt); var; var = NextNode(var)) {
 3774             if (!CheckModuleGlobal(m, var, varStmt->isKind(PNK_CONST)))
 3775                 return false;
 3776         }
 3777     }
 3778 
 3779     return true;
 3780 }
 3781 
 3782 static bool
 3783 ArgFail(FunctionValidator& f, PropertyName* argName, ParseNode* stmt)
 3784 {
 3785     return f.failName(stmt, "expecting argument type declaration for '%s' of the "
 3786                       "form 'arg = arg|0' or 'arg = +arg' or 'arg = fround(arg)'", argName);
 3787 }
 3788 
 3789 static bool
 3790 CheckArgumentType(FunctionValidator& f, ParseNode* stmt, PropertyName* name, Type* type)
 3791 {
 3792     if (!stmt || !IsExpressionStatement(stmt))
 3793         return ArgFail(f, name, stmt ? stmt : f.fn());
 3794 
 3795     ParseNode* initNode = ExpressionStatementExpr(stmt);
 3796     if (!initNode || !initNode->isKind(PNK_ASSIGN))
 3797         return ArgFail(f, name, stmt);
 3798 
 3799     ParseNode* argNode = BinaryLeft(initNode);
 3800     ParseNode* coercionNode = BinaryRight(initNode);
 3801 
 3802     if (!IsUseOfName(argNode, name))
 3803         return ArgFail(f, name, stmt);
 3804 
 3805     ParseNode* coercedExpr;
 3806     if (!CheckTypeAnnotation(f.m(), coercionNode, type, &coercedExpr))
 3807         return false;
 3808 
 3809     if (!type->isArgType())
 3810         return f.failName(stmt, "invalid type for argument '%s'", name);
 3811 
 3812     if (!IsUseOfName(coercedExpr, name))
 3813         return ArgFail(f, name, stmt);
 3814 
 3815     return true;
 3816 }
 3817 
 3818 static bool
 3819 CheckProcessingDirectives(ModuleValidator& m, ParseNode** stmtIter)
 3820 {
 3821     ParseNode* stmt = *stmtIter;
 3822 
 3823     while (stmt && IsIgnoredDirective(m.cx(), stmt))
 3824         stmt = NextNode(stmt);
 3825 
 3826     *stmtIter = stmt;
 3827     return true;
 3828 }
 3829 
 3830 static bool
 3831 CheckArguments(FunctionValidator& f, ParseNode** stmtIter, ValTypeVector* argTypes)
 3832 {
 3833     ParseNode* stmt = *stmtIter;
 3834 
 3835     unsigned numFormals;
 3836     ParseNode* argpn = FunctionFormalParametersList(f.fn(), &numFormals);
 3837 
 3838     for (unsigned i = 0; i < numFormals; i++, argpn = NextNode(argpn), stmt = NextNode(stmt)) {
 3839         PropertyName* name;
 3840         if (!CheckArgument(f.m(), argpn, &name))
 3841             return false;
 3842 
 3843         Type type;
 3844         if (!CheckArgumentType(f, stmt, name, &type))
 3845             return false;
 3846 
 3847         if (!argTypes->append(type.canonicalToValType()))
 3848             return false;
 3849 
 3850         if (!f.addLocal(argpn, name, type))
 3851             return false;
 3852     }
 3853 
 3854     *stmtIter = stmt;
 3855     return true;
 3856 }
 3857 
 3858 static bool
 3859 IsLiteralOrConst(FunctionValidator& f, ParseNode* pn, NumLit* lit)
 3860 {
 3861     if (pn->isKind(PNK_NAME)) {
 3862         const ModuleValidator::Global* global = f.lookupGlobal(pn->name());
 3863         if (!global || global->which() != ModuleValidator::Global::ConstantLiteral)
 3864             return false;
 3865 
 3866         *lit = global->constLiteralValue();
 3867         return true;
 3868     }
 3869 
 3870     bool isSimd = false;
 3871     if (!IsNumericLiteral(f.m(), pn, &isSimd))
 3872         return false;
 3873 
 3874     if (isSimd)
 3875         f.setUsesSimd();
 3876 
 3877     *lit = ExtractNumericLiteral(f.m(), pn);
 3878     return true;
 3879 }
 3880 
 3881 static bool
 3882 CheckFinalReturn(FunctionValidator& f, ParseNode* lastNonEmptyStmt)
 3883 {
 3884     if (!f.encoder().writeOp(Op::End))
 3885         return false;
 3886 
 3887     if (!f.hasAlreadyReturned()) {
 3888         f.setReturnedType(ExprType::Void);
 3889         return true;
 3890     }
 3891 
 3892     if (!lastNonEmptyStmt->isKind(PNK_RETURN) && !IsVoid(f.returnedType()))
 3893         return f.fail(lastNonEmptyStmt, "void incompatible with previous return type");
 3894 
 3895     return true;
 3896 }
 3897 
 3898 static bool
 3899 CheckVariable(FunctionValidator& f, ParseNode* var, ValTypeVector* types, Vector<NumLit>* inits)
 3900 {
 3901     if (!var->isKind(PNK_NAME))
 3902         return f.fail(var, "local variable is not a plain name");
 3903 
 3904     PropertyName* name = var->name();
 3905 
 3906     if (!CheckIdentifier(f.m(), var, name))
 3907         return false;
 3908 
 3909     ParseNode* initNode = MaybeInitializer(var);
 3910     if (!initNode)
 3911         return f.failName(var, "var '%s' needs explicit type declaration via an initial value", name);
 3912 
 3913     NumLit lit;
 3914     if (!IsLiteralOrConst(f, initNode, &lit))
 3915         return f.failName(var, "var '%s' initializer must be literal or const literal", name);
 3916 
 3917     if (!lit.valid())
 3918         return f.failName(var, "var '%s' initializer out of range", name);
 3919 
 3920     Type type = Type::canonicalize(Type::lit(lit));
 3921 
 3922     return f.addLocal(var, name, type) &&
 3923            types->append(type.canonicalToValType()) &&
 3924            inits->append(lit);
 3925 }
 3926 
 3927 static bool
 3928 CheckVariables(FunctionValidator& f, ParseNode** stmtIter)
 3929 {
 3930     ParseNode* stmt = *stmtIter;
 3931 
 3932     uint32_t firstVar = f.numLocals();
 3933 
 3934     ValTypeVector types;
 3935     Vector<NumLit> inits(f.cx());
 3936 
 3937     for (; stmt && stmt->isKind(PNK_VAR); stmt = NextNonEmptyStatement(stmt)) {
 3938         for (ParseNode* var = VarListHead(stmt); var; var = NextNode(var)) {
 3939             if (!CheckVariable(f, var, &types, &inits))
 3940                 return false;
 3941         }
 3942     }
 3943 
 3944     MOZ_ASSERT(f.encoder().empty());
 3945 
 3946     if (!EncodeLocalEntries(f.encoder(), types))
 3947         return false;
 3948 
 3949     for (uint32_t i = 0; i < inits.length(); i++) {
 3950         NumLit lit = inits[i];
 3951         if (lit.isZeroBits())
 3952             continue;
 3953         if (!f.writeConstExpr(lit))
 3954             return false;
 3955         if (!f.encoder().writeOp(Op::SetLocal))
 3956             return false;
 3957         if (!f.encoder().writeVarU32(firstVar + i))
 3958             return false;
 3959     }
 3960 
 3961     *stmtIter = stmt;
 3962     return true;
 3963 }
 3964 
 3965 static bool
 3966 CheckExpr(FunctionValidator& f, ParseNode* op, Type* type);
 3967 
 3968 static bool
 3969 CheckNumericLiteral(FunctionValidator& f, ParseNode* num, Type* type)
 3970 {
 3971     NumLit lit = ExtractNumericLiteral(f.m(), num);
 3972     if (!lit.valid())
 3973         return f.fail(num, "numeric literal out of representable integer range");
 3974     *type = Type::lit(lit);
 3975     return f.writeConstExpr(lit);
 3976 }
 3977 
 3978 static bool
 3979 CheckVarRef(FunctionValidator& f, ParseNode* varRef, Type* type)
 3980 {
 3981     PropertyName* name = varRef->name();
 3982 
 3983     if (const FunctionValidator::Local* local = f.lookupLocal(name)) {
 3984         if (!f.encoder().writeOp(Op::GetLocal))
 3985             return false;
 3986         if (!f.encoder().writeVarU32(local->slot))
 3987             return false;
 3988         *type = local->type;
 3989         return true;
 3990     }
 3991 
 3992     if (const ModuleValidator::Global* global = f.lookupGlobal(name)) {
 3993         switch (global->which()) {
 3994           case ModuleValidator::Global::ConstantLiteral:
 3995             *type = global->varOrConstType();
 3996             return f.writeConstExpr(global->constLiteralValue());
 3997           case ModuleValidator::Global::ConstantImport:
 3998           case ModuleValidator::Global::Variable: {
 3999             *type = global->varOrConstType();
 4000             return f.encoder().writeOp(Op::GetGlobal) &&
 4001                    f.encoder().writeVarU32(global->varOrConstIndex());
 4002           }
 4003           case ModuleValidator::Global::Function:
 4004           case ModuleValidator::Global::FFI:
 4005           case ModuleValidator::Global::MathBuiltinFunction:
 4006           case ModuleValidator::Global::AtomicsBuiltinFunction:
 4007           case ModuleValidator::Global::FuncPtrTable:
 4008           case ModuleValidator::Global::ArrayView:
 4009           case ModuleValidator::Global::ArrayViewCtor:
 4010           case ModuleValidator::Global::SimdCtor:
 4011           case ModuleValidator::Global::SimdOp:
 4012             break;
 4013         }
 4014         return f.failName(varRef, "'%s' may not be accessed by ordinary expressions", name);
 4015     }
 4016 
 4017     return f.failName(varRef, "'%s' not found in local or asm.js module scope", name);
 4018 }
 4019 
 4020 static inline bool
 4021 IsLiteralOrConstInt(FunctionValidator& f, ParseNode* pn, uint32_t* u32)
 4022 {
 4023     NumLit lit;
 4024     if (!IsLiteralOrConst(f, pn, &lit))
 4025         return false;
 4026 
 4027     return IsLiteralInt(lit, u32);
 4028 }
 4029 
 4030 static const int32_t NoMask = -1;
 4031 static const bool YesSimd = true;
 4032 static const bool NoSimd = false;
 4033 
 4034 static bool
 4035 CheckArrayAccess(FunctionValidator& f, ParseNode* viewName, ParseNode* indexExpr,
 4036                  bool isSimd, Scalar::Type* viewType)
 4037 {
 4038     if (!viewName->isKind(PNK_NAME))
 4039         return f.fail(viewName, "base of array access must be a typed array view name");
 4040 
 4041     const ModuleValidator::Global* global = f.lookupGlobal(viewName->name());
 4042     if (!global || !global->isAnyArrayView())
 4043         return f.fail(viewName, "base of array access must be a typed array view name");
 4044 
 4045     *viewType = global->viewType();
 4046 
 4047     uint32_t index;
 4048     if (IsLiteralOrConstInt(f, indexExpr, &index)) {
 4049         uint64_t byteOffset = uint64_t(index) << TypedArrayShift(*viewType);
 4050         uint64_t width = isSimd ? Simd128DataSize : TypedArrayElemSize(*viewType);
 4051         if (!f.m().tryConstantAccess(byteOffset, width))
 4052             return f.fail(indexExpr, "constant index out of range");
 4053 
 4054         return f.writeInt32Lit(byteOffset);
 4055     }
 4056 
 4057     // Mask off the low bits to account for the clearing effect of a right shift
 4058     // followed by the left shift implicit in the array access. E.g., H32[i>>2]
 4059     // loses the low two bits.
 4060     int32_t mask = ~(TypedArrayElemSize(*viewType) - 1);
 4061 
 4062     if (indexExpr->isKind(PNK_RSH)) {
 4063         ParseNode* shiftAmountNode = BitwiseRight(indexExpr);
 4064 
 4065         uint32_t shift;
 4066         if (!IsLiteralInt(f.m(), shiftAmountNode, &shift))
 4067             return f.failf(shiftAmountNode, "shift amount must be constant");
 4068 
 4069         unsigned requiredShift = TypedArrayShift(*viewType);
 4070         if (shift != requiredShift)
 4071             return f.failf(shiftAmountNode, "shift amount must be %u", requiredShift);
 4072 
 4073         ParseNode* pointerNode = BitwiseLeft(indexExpr);
 4074 
 4075         Type pointerType;
 4076         if (!CheckExpr(f, pointerNode, &pointerType))
 4077             return false;
 4078 
 4079         if (!pointerType.isIntish())
 4080             return f.failf(pointerNode, "%s is not a subtype of int", pointerType.toChars());
 4081     } else {
 4082         // For SIMD access, and legacy scalar access compatibility, accept
 4083         // Int8/Uint8 accesses with no shift.
 4084         if (TypedArrayShift(*viewType) != 0)
 4085             return f.fail(indexExpr, "index expression isn't shifted; must be an Int8/Uint8 access");
 4086 
 4087         MOZ_ASSERT(mask == NoMask);
 4088 
 4089         ParseNode* pointerNode = indexExpr;
 4090 
 4091         Type pointerType;
 4092         if (!CheckExpr(f, pointerNode, &pointerType))
 4093             return false;
 4094 
 4095         if (isSimd) {
 4096             if (!pointerType.isIntish())
 4097                 return f.failf(pointerNode, "%s is not a subtype of intish", pointerType.toChars());
 4098         } else {
 4099             if (!pointerType.isInt())
 4100                 return f.failf(pointerNode, "%s is not a subtype of int", pointerType.toChars());
 4101         }
 4102     }
 4103 
 4104     // Don't generate the mask op if there is no need for it which could happen for
 4105     // a shift of zero or a SIMD access.
 4106     if (mask != NoMask) {
 4107         return f.writeInt32Lit(mask) &&
 4108                f.encoder().writeOp(Op::I32And);
 4109     }
 4110 
 4111     return true;
 4112 }
 4113 
 4114 static bool
 4115 CheckAndPrepareArrayAccess(FunctionValidator& f, ParseNode* viewName, ParseNode* indexExpr,
 4116                            bool isSimd, Scalar::Type* viewType)
 4117 {
 4118     return CheckArrayAccess(f, viewName, indexExpr, isSimd, viewType);
 4119 }
 4120 
 4121 static bool
 4122 WriteArrayAccessFlags(FunctionValidator& f, Scalar::Type viewType)
 4123 {
 4124     // asm.js only has naturally-aligned accesses.
 4125     size_t align = TypedArrayElemSize(viewType);
 4126     MOZ_ASSERT(IsPowerOfTwo(align));
 4127     if (!f.encoder().writeFixedU8(CeilingLog2(align)))
 4128         return false;
 4129 
 4130     // asm.js doesn't have constant offsets, so just encode a 0.
 4131     if (!f.encoder().writeVarU32(0))
 4132         return false;
 4133 
 4134     return true;
 4135 }
 4136 
 4137 static bool
 4138 CheckLoadArray(FunctionValidator& f, ParseNode* elem, Type* type)
 4139 {
 4140     Scalar::Type viewType;
 4141 
 4142     if (!CheckAndPrepareArrayAccess(f, ElemBase(elem), ElemIndex(elem), NoSimd, &viewType))
 4143         return false;
 4144 
 4145     switch (viewType) {
 4146       case Scalar::Int8:    if (!f.encoder().writeOp(Op::I32Load8S))  return false; break;
 4147       case Scalar::Uint8:   if (!f.encoder().writeOp(Op::I32Load8U))  return false; break;
 4148       case Scalar::Int16:   if (!f.encoder().writeOp(Op::I32Load16S)) return false; break;
 4149       case Scalar::Uint16:  if (!f.encoder().writeOp(Op::I32Load16U)) return false; break;
 4150       case Scalar::Uint32:
 4151       case Scalar::Int32:   if (!f.encoder().writeOp(Op::I32Load))    return false; break;
 4152       case Scalar::Float32: if (!f.encoder().writeOp(Op::F32Load))    return false; break;
 4153       case Scalar::Float64: if (!f.encoder().writeOp(Op::F64Load))    return false; break;
 4154       default: MOZ_CRASH("unexpected scalar type");
 4155     }
 4156 
 4157     switch (viewType) {
 4158       case Scalar::Int8:
 4159       case Scalar::Int16:
 4160       case Scalar::Int32:
 4161       case Scalar::Uint8:
 4162       case Scalar::Uint16:
 4163       case Scalar::Uint32:
 4164         *type = Type::Intish;
 4165         break;
 4166       case Scalar::Float32:
 4167         *type = Type::MaybeFloat;
 4168         break;
 4169       case Scalar::Float64:
 4170         *type = Type::MaybeDouble;
 4171         break;
 4172       default: MOZ_CRASH("Unexpected array type");
 4173     }
 4174 
 4175     if (!WriteArrayAccessFlags(f, viewType))
 4176         return false;
 4177 
 4178     return true;
 4179 }
 4180 
 4181 static bool
 4182 CheckStoreArray(FunctionValidator& f, ParseNode* lhs, ParseNode* rhs, Type* type)
 4183 {
 4184     Scalar::Type viewType;
 4185     if (!CheckAndPrepareArrayAccess(f, ElemBase(lhs), ElemIndex(lhs), NoSimd, &viewType))
 4186         return false;
 4187 
 4188     Type rhsType;
 4189     if (!CheckExpr(f, rhs, &rhsType))
 4190         return false;
 4191 
 4192     switch (viewType) {
 4193       case Scalar::Int8:
 4194       case Scalar::Int16:
 4195       case Scalar::Int32:
 4196       case Scalar::Uint8:
 4197       case Scalar::Uint16:
 4198       case Scalar::Uint32:
 4199         if (!rhsType.isIntish())
 4200             return f.failf(lhs, "%s is not a subtype of intish", rhsType.toChars());
 4201         break;
 4202       case Scalar::Float32:
 4203         if (!rhsType.isMaybeDouble() && !rhsType.isFloatish())
 4204             return f.failf(lhs, "%s is not a subtype of double? or floatish", rhsType.toChars());
 4205         break;
 4206       case Scalar::Float64:
 4207         if (!rhsType.isMaybeFloat() && !rhsType.isMaybeDouble())
 4208             return f.failf(lhs, "%s is not a subtype of float? or double?", rhsType.toChars());
 4209         break;
 4210       default:
 4211         MOZ_CRASH("Unexpected view type");
 4212     }
 4213 
 4214     switch (viewType) {
 4215       case Scalar::Int8:
 4216       case Scalar::Uint8:
 4217         if (!f.encoder().writeOp(Op::I32TeeStore8))
 4218             return false;
 4219         break;
 4220       case Scalar::Int16:
 4221       case Scalar::Uint16:
 4222         if (!f.encoder().writeOp(Op::I32TeeStore16))
 4223             return false;
 4224         break;
 4225       case Scalar::Int32:
 4226       case Scalar::Uint32:
 4227         if (!f.encoder().writeOp(Op::I32TeeStore))
 4228             return false;
 4229         break;
 4230       case Scalar::Float32:
 4231         if (rhsType.isFloatish()) {
 4232             if (!f.encoder().writeOp(Op::F32TeeStore))
 4233                 return false;
 4234         } else {
 4235             if (!f.encoder().writeOp(Op::F64TeeStoreF32))
 4236                 return false;
 4237         }
 4238         break;
 4239       case Scalar::Float64:
 4240         if (rhsType.isFloatish()) {
 4241             if (!f.encoder().writeOp(Op::F32TeeStoreF64))
 4242                 return false;
 4243         } else {
 4244             if (!f.encoder().writeOp(Op::F64TeeStore))
 4245                 return false;
 4246         }
 4247         break;
 4248       default: MOZ_CRASH("unexpected scalar type");
 4249     }
 4250 
 4251     if (!WriteArrayAccessFlags(f, viewType))
 4252         return false;
 4253 
 4254     *type = rhsType;
 4255     return true;
 4256 }
 4257 
 4258 static bool
 4259 CheckAssignName(FunctionValidator& f, ParseNode* lhs, ParseNode* rhs, Type* type)
 4260 {
 4261     RootedPropertyName name(f.cx(), lhs->name());
 4262 
 4263     if (const FunctionValidator::Local* lhsVar = f.lookupLocal(name)) {
 4264         Type rhsType;
 4265         if (!CheckExpr(f, rhs, &rhsType))
 4266             return false;
 4267 
 4268         if (!f.encoder().writeOp(Op::TeeLocal))
 4269             return false;
 4270         if (!f.encoder().writeVarU32(lhsVar->slot))
 4271             return false;
 4272 
 4273         if (!(rhsType <= lhsVar->type)) {
 4274             return f.failf(lhs, "%s is not a subtype of %s",
 4275                            rhsType.toChars(), lhsVar->type.toChars());
 4276         }
 4277         *type = rhsType;
 4278         return true;
 4279     }
 4280 
 4281     if (const ModuleValidator::Global* global = f.lookupGlobal(name)) {
 4282         if (global->which() != ModuleValidator::Global::Variable)
 4283             return f.failName(lhs, "'%s' is not a mutable variable", name);
 4284 
 4285         Type rhsType;
 4286         if (!CheckExpr(f, rhs, &rhsType))
 4287             return false;
 4288 
 4289         Type globType = global->varOrConstType();
 4290         if (!(rhsType <= globType))
 4291             return f.failf(lhs, "%s is not a subtype of %s", rhsType.toChars(), globType.toChars());
 4292         if (!f.encoder().writeOp(Op::TeeGlobal))
 4293             return false;
 4294         if (!f.encoder().writeVarU32(global->varOrConstIndex()))
 4295             return false;
 4296 
 4297         *type = rhsType;
 4298         return true;
 4299     }
 4300 
 4301     return f.failName(lhs, "'%s' not found in local or asm.js module scope", name);
 4302 }
 4303 
 4304 static bool
 4305 CheckAssign(FunctionValidator& f, ParseNode* assign, Type* type)
 4306 {
 4307     MOZ_ASSERT(assign->isKind(PNK_ASSIGN));
 4308 
 4309     ParseNode* lhs = BinaryLeft(assign);
 4310     ParseNode* rhs = BinaryRight(assign);
 4311 
 4312     if (lhs->getKind() == PNK_ELEM)
 4313         return CheckStoreArray(f, lhs, rhs, type);
 4314 
 4315     if (lhs->getKind() == PNK_NAME)
 4316         return CheckAssignName(f, lhs, rhs, type);
 4317 
 4318     return f.fail(assign, "left-hand side of assignment must be a variable or array access");
 4319 }
 4320 
 4321 static bool
 4322 CheckMathIMul(FunctionValidator& f, ParseNode* call, Type* type)
 4323 {
 4324     if (CallArgListLength(call) != 2)
 4325         return f.fail(call, "Math.imul must be passed 2 arguments");
 4326 
 4327     ParseNode* lhs = CallArgList(call);
 4328     ParseNode* rhs = NextNode(lhs);
 4329 
 4330     Type lhsType;
 4331     if (!CheckExpr(f, lhs, &lhsType))
 4332         return false;
 4333 
 4334     Type rhsType;
 4335     if (!CheckExpr(f, rhs, &rhsType))
 4336         return false;
 4337 
 4338     if (!lhsType.isIntish())
 4339         return f.failf(lhs, "%s is not a subtype of intish", lhsType.toChars());
 4340     if (!rhsType.isIntish())
 4341         return f.failf(rhs, "%s is not a subtype of intish", rhsType.toChars());
 4342 
 4343     *type = Type::Signed;
 4344     return f.encoder().writeOp(Op::I32Mul);
 4345 }
 4346 
 4347 static bool
 4348 CheckMathClz32(FunctionValidator& f, ParseNode* call, Type* type)
 4349 {
 4350     if (CallArgListLength(call) != 1)
 4351         return f.fail(call, "Math.clz32 must be passed 1 argument");
 4352 
 4353     ParseNode* arg = CallArgList(call);
 4354 
 4355     Type argType;
 4356     if (!CheckExpr(f, arg, &argType))
 4357         return false;
 4358 
 4359     if (!argType.isIntish())
 4360         return f.failf(arg, "%s is not a subtype of intish", argType.toChars());
 4361 
 4362     *type = Type::Fixnum;
 4363     return f.encoder().writeOp(Op::I32Clz);
 4364 }
 4365 
 4366 static bool
 4367 CheckMathAbs(FunctionValidator& f, ParseNode* call, Type* type)
 4368 {
 4369     if (CallArgListLength(call) != 1)
 4370         return f.fail(call, "Math.abs must be passed 1 argument");
 4371 
 4372     ParseNode* arg = CallArgList(call);
 4373 
 4374     Type argType;
 4375     if (!CheckExpr(f, arg, &argType))
 4376         return false;
 4377 
 4378     if (argType.isSigned()) {
 4379         *type = Type::Unsigned;
 4380         return f.encoder().writeOp(Op::I32Abs);
 4381     }
 4382 
 4383     if (argType.isMaybeDouble()) {
 4384         *type = Type::Double;
 4385         return f.encoder().writeOp(Op::F64Abs);
 4386     }
 4387 
 4388     if (argType.isMaybeFloat()) {
 4389         *type = Type::Floatish;
 4390         return f.encoder().writeOp(Op::F32Abs);
 4391     }
 4392 
 4393     return f.failf(call, "%s is not a subtype of signed, float? or double?", argType.toChars());
 4394 }
 4395 
 4396 static bool
 4397 CheckMathSqrt(FunctionValidator& f, ParseNode* call, Type* type)
 4398 {
 4399     if (CallArgListLength(call) != 1)
 4400         return f.fail(call, "Math.sqrt must be passed 1 argument");
 4401 
 4402     ParseNode* arg = CallArgList(call);
 4403 
 4404     Type argType;
 4405     if (!CheckExpr(f, arg, &argType))
 4406         return false;
 4407 
 4408     if (argType.isMaybeDouble()) {
 4409         *type = Type::Double;
 4410         return f.encoder().writeOp(Op::F64Sqrt);
 4411     }
 4412 
 4413     if (argType.isMaybeFloat()) {
 4414         *type = Type::Floatish;
 4415         return f.encoder().writeOp(Op::F32Sqrt);
 4416     }
 4417 
 4418     return f.failf(call, "%s is neither a subtype of double? nor float?", argType.toChars());
 4419 }
 4420 
 4421 static bool
 4422 CheckMathMinMax(FunctionValidator& f, ParseNode* callNode, bool isMax, Type* type)
 4423 {
 4424     if (CallArgListLength(callNode) < 2)
 4425         return f.fail(callNode, "Math.min/max must be passed at least 2 arguments");
 4426 
 4427     ParseNode* firstArg = CallArgList(callNode);
 4428     Type firstType;
 4429     if (!CheckExpr(f, firstArg, &firstType))
 4430         return false;
 4431 
 4432     Op op;
 4433     if (firstType.isMaybeDouble()) {
 4434         *type = Type::Double;
 4435         firstType = Type::MaybeDouble;
 4436         op = isMax ? Op::F64Max : Op::F64Min;
 4437     } else if (firstType.isMaybeFloat()) {
 4438         *type = Type::Float;
 4439         firstType = Type::MaybeFloat;
 4440         op = isMax ? Op::F32Max : Op::F32Min;
 4441     } else if (firstType.isSigned()) {
 4442         *type = Type::Signed;
 4443         firstType = Type::Signed;
 4444         op = isMax ? Op::I32Max : Op::I32Min;
 4445     } else {
 4446         return f.failf(firstArg, "%s is not a subtype of double?, float? or signed",
 4447                        firstType.toChars());
 4448     }
 4449 
 4450     unsigned numArgs = CallArgListLength(callNode);
 4451     ParseNode* nextArg = NextNode(firstArg);
 4452     for (unsigned i = 1; i < numArgs; i++, nextArg = NextNode(nextArg)) {
 4453         Type nextType;
 4454         if (!CheckExpr(f, nextArg, &nextType))
 4455             return false;
 4456         if (!(nextType <= firstType))
 4457             return f.failf(nextArg, "%s is not a subtype of %s", nextType.toChars(), firstType.toChars());
 4458 
 4459         if (!f.encoder().writeOp(op))
 4460             return false;
 4461     }
 4462 
 4463     return true;
 4464 }
 4465 
 4466 static bool
 4467 CheckSharedArrayAtomicAccess(FunctionValidator& f, ParseNode* viewName, ParseNode* indexExpr,
 4468                              Scalar::Type* viewType)
 4469 {
 4470     if (!CheckAndPrepareArrayAccess(f, viewName, indexExpr, NoSimd, viewType))
 4471         return false;
 4472 
 4473     // The global will be sane, CheckArrayAccess checks it.
 4474     const ModuleValidator::Global* global = f.lookupGlobal(viewName->name());
 4475     if (global->which() != ModuleValidator::Global::ArrayView)
 4476         return f.fail(viewName, "base of array access must be a typed array view");
 4477 
 4478     MOZ_ASSERT(f.m().atomicsPresent());
 4479 
 4480     switch (*viewType) {
 4481       case Scalar::Int8:
 4482       case Scalar::Int16:
 4483       case Scalar::Int32:
 4484       case Scalar::Uint8:
 4485       case Scalar::Uint16:
 4486       case Scalar::Uint32:
 4487         return true;
 4488       default:
 4489         return f.failf(viewName, "not an integer array");
 4490     }
 4491 
 4492     return true;
 4493 }
 4494 
 4495 static bool
 4496 WriteAtomicOperator(FunctionValidator& f, Op opcode, Scalar::Type viewType)
 4497 {
 4498     return f.encoder().writeOp(opcode) &&
 4499            f.encoder().writeFixedU8(viewType);
 4500 }
 4501 
 4502 static bool
 4503 CheckAtomicsLoad(FunctionValidator& f, ParseNode* call, Type* type)
 4504 {
 4505     if (CallArgListLength(call) != 2)
 4506         return f.fail(call, "Atomics.load must be passed 2 arguments");
 4507 
 4508     ParseNode* arrayArg = CallArgList(call);
 4509     ParseNode* indexArg = NextNode(arrayArg);
 4510 
 4511     Scalar::Type viewType;
 4512     if (!CheckSharedArrayAtomicAccess(f, arrayArg, indexArg, &viewType))
 4513         return false;
 4514 
 4515     if (!WriteAtomicOperator(f, Op::I32AtomicsLoad, viewType))
 4516         return false;
 4517 
 4518     if (!WriteArrayAccessFlags(f, viewType))
 4519         return false;
 4520 
 4521     *type = Type::Int;
 4522     return true;
 4523 }
 4524 
 4525 static bool
 4526 CheckAtomicsStore(FunctionValidator& f, ParseNode* call, Type* type)
 4527 {
 4528     if (CallArgListLength(call) != 3)
 4529         return f.fail(call, "Atomics.store must be passed 3 arguments");
 4530 
 4531     ParseNode* arrayArg = CallArgList(call);
 4532     ParseNode* indexArg = NextNode(arrayArg);
 4533     ParseNode* valueArg = NextNode(indexArg);
 4534 
 4535     Type rhsType;
 4536     if (!CheckExpr(f, valueArg, &rhsType))
 4537         return false;
 4538 
 4539     if (!rhsType.isIntish())
 4540         return f.failf(arrayArg, "%s is not a subtype of intish", rhsType.toChars());
 4541 
 4542     Scalar::Type viewType;
 4543     if (!CheckSharedArrayAtomicAccess(f, arrayArg, indexArg, &viewType))
 4544         return false;
 4545 
 4546     if (!WriteAtomicOperator(f, Op::I32AtomicsStore, viewType))
 4547         return false;
 4548 
 4549     if (!WriteArrayAccessFlags(f, viewType))
 4550         return false;
 4551 
 4552     *type = rhsType;
 4553     return true;
 4554 }
 4555 
 4556 static bool
 4557 CheckAtomicsBinop(FunctionValidator& f, ParseNode* call, Type* type, AtomicOp op)
 4558 {
 4559     if (CallArgListLength(call) != 3)
 4560         return f.fail(call, "Atomics binary operator must be passed 3 arguments");
 4561 
 4562     ParseNode* arrayArg = CallArgList(call);
 4563     ParseNode* indexArg = NextNode(arrayArg);
 4564     ParseNode* valueArg = NextNode(indexArg);
 4565 
 4566     Type valueArgType;
 4567     if (!CheckExpr(f, valueArg, &valueArgType))
 4568         return false;
 4569 
 4570     if (!valueArgType.isIntish())
 4571         return f.failf(valueArg, "%s is not a subtype of intish", valueArgType.toChars());
 4572 
 4573     Scalar::Type viewType;
 4574     if (!CheckSharedArrayAtomicAccess(f, arrayArg, indexArg, &viewType))
 4575         return false;
 4576 
 4577     if (!WriteAtomicOperator(f, Op::I32AtomicsBinOp, viewType))
 4578         return false;
 4579     if (!f.encoder().writeFixedU8(uint8_t(op)))
 4580         return false;
 4581 
 4582     if (!WriteArrayAccessFlags(f, viewType))
 4583         return false;
 4584 
 4585     *type = Type::Int;
 4586     return true;
 4587 }
 4588 
 4589 static bool
 4590 CheckAtomicsIsLockFree(FunctionValidator& f, ParseNode* call, Type* type)
 4591 {
 4592     if (CallArgListLength(call) != 1)
 4593         return f.fail(call, "Atomics.isLockFree must be passed 1 argument");
 4594 
 4595     ParseNode* sizeArg = CallArgList(call);
 4596 
 4597     uint32_t size;
 4598     if (!IsLiteralInt(f.m(), sizeArg, &size))
 4599         return f.fail(sizeArg, "Atomics.isLockFree requires an integer literal argument");
 4600 
 4601     *type = Type::Int;
 4602     return f.writeInt32Lit(AtomicOperations::isLockfree(size));
 4603 }
 4604 
 4605 static bool
 4606 CheckAtomicsCompareExchange(FunctionValidator& f, ParseNode* call, Type* type)
 4607 {
 4608     if (CallArgListLength(call) != 4)
 4609         return f.fail(call, "Atomics.compareExchange must be passed 4 arguments");
 4610 
 4611     ParseNode* arrayArg = CallArgList(call);
 4612     ParseNode* indexArg = NextNode(arrayArg);
 4613     ParseNode* oldValueArg = NextNode(indexArg);
 4614     ParseNode* newValueArg = NextNode(oldValueArg);
 4615 
 4616     Type oldValueArgType;
 4617     if (!CheckExpr(f, oldValueArg, &oldValueArgType))
 4618         return false;
 4619 
 4620     Type newValueArgType;
 4621     if (!CheckExpr(f, newValueArg, &newValueArgType))
 4622         return false;
 4623 
 4624     if (!oldValueArgType.isIntish())
 4625         return f.failf(oldValueArg, "%s is not a subtype of intish", oldValueArgType.toChars());
 4626 
 4627     if (!newValueArgType.isIntish())
 4628         return f.failf(newValueArg, "%s is not a subtype of intish", newValueArgType.toChars());
 4629 
 4630     Scalar::Type viewType;
 4631     if (!CheckSharedArrayAtomicAccess(f, arrayArg, indexArg, &viewType))
 4632         return false;
 4633 
 4634     if (!WriteAtomicOperator(f, Op::I32AtomicsCompareExchange, viewType))
 4635         return false;
 4636 
 4637     if (!WriteArrayAccessFlags(f, viewType))
 4638         return false;
 4639 
 4640     *type = Type::Int;
 4641     return true;
 4642 }
 4643 
 4644 static bool
 4645 CheckAtomicsExchange(FunctionValidator& f, ParseNode* call, Type* type)
 4646 {
 4647     if (CallArgListLength(call) != 3)
 4648         return f.fail(call, "Atomics.exchange must be passed 3 arguments");
 4649 
 4650     ParseNode* arrayArg = CallArgList(call);
 4651     ParseNode* indexArg = NextNode(arrayArg);
 4652     ParseNode* valueArg = NextNode(indexArg);
 4653 
 4654     Type valueArgType;
 4655     if (!CheckExpr(f, valueArg, &valueArgType))
 4656         return false;
 4657 
 4658     if (!valueArgType.isIntish())
 4659         return f.failf(arrayArg, "%s is not a subtype of intish", valueArgType.toChars());
 4660 
 4661     Scalar::Type viewType;
 4662     if (!CheckSharedArrayAtomicAccess(f, arrayArg, indexArg, &viewType))
 4663         return false;
 4664 
 4665     if (!WriteAtomicOperator(f, Op::I32AtomicsExchange, viewType))
 4666         return false;
 4667 
 4668     if (!WriteArrayAccessFlags(f, viewType))
 4669         return false;
 4670 
 4671     *type = Type::Int;
 4672     return true;
 4673 }
 4674 
 4675 static bool
 4676 CheckAtomicsBuiltinCall(FunctionValidator& f, ParseNode* callNode, AsmJSAtomicsBuiltinFunction func,
 4677                         Type* type)
 4678 {
 4679     f.setUsesAtomics();
 4680 
 4681     switch (func) {
 4682       case AsmJSAtomicsBuiltin_compareExchange:
 4683         return CheckAtomicsCompareExchange(f, callNode, type);
 4684       case AsmJSAtomicsBuiltin_exchange:
 4685         return CheckAtomicsExchange(f, callNode, type);
 4686       case AsmJSAtomicsBuiltin_load:
 4687         return CheckAtomicsLoad(f, callNode, type);
 4688       case AsmJSAtomicsBuiltin_store:
 4689         return CheckAtomicsStore(f, callNode, type);
 4690       case AsmJSAtomicsBuiltin_add:
 4691         return CheckAtomicsBinop(f, callNode, type, AtomicFetchAddOp);
 4692       case AsmJSAtomicsBuiltin_sub:
 4693         return CheckAtomicsBinop(f, callNode, type, AtomicFetchSubOp);
 4694       case AsmJSAtomicsBuiltin_and:
 4695         return CheckAtomicsBinop(f, callNode, type, AtomicFetchAndOp);
 4696       case AsmJSAtomicsBuiltin_or:
 4697         return CheckAtomicsBinop(f, callNode, type, AtomicFetchOrOp);
 4698       case AsmJSAtomicsBuiltin_xor:
 4699         return CheckAtomicsBinop(f, callNode, type, AtomicFetchXorOp);
 4700       case AsmJSAtomicsBuiltin_isLockFree:
 4701         return CheckAtomicsIsLockFree(f, callNode, type);
 4702       default:
 4703         MOZ_CRASH("unexpected atomicsBuiltin function");
 4704     }
 4705 }
 4706 
 4707 typedef bool (*CheckArgType)(FunctionValidator& f, ParseNode* argNode, Type type);
 4708 
 4709 template <CheckArgType checkArg>
 4710 static bool
 4711 CheckCallArgs(FunctionValidator& f, ParseNode* callNode, ValTypeVector* args)
 4712 {
 4713     ParseNode* argNode = CallArgList(callNode);
 4714     for (unsigned i = 0; i < CallArgListLength(callNode); i++, argNode = NextNode(argNode)) {
 4715         Type type;
 4716         if (!CheckExpr(f, argNode, &type))
 4717             return false;
 4718 
 4719         if (!checkArg(f, argNode, type))
 4720             return false;
 4721 
 4722         if (!args->append(Type::canonicalize(type).canonicalToValType()))
 4723             return false;
 4724     }
 4725     return true;
 4726 }
 4727 
 4728 static bool
 4729 CheckSignatureAgainstExisting(ModuleValidator& m, ParseNode* usepn, const Sig& sig, const Sig& existing)
 4730 {
 4731     if (sig.args().length() != existing.args().length()) {
 4732         return m.failf(usepn, "incompatible number of arguments (%" PRIuSIZE
 4733                        " here vs. %" PRIuSIZE " before)",
 4734                        sig.args().length(), existing.args().length());
 4735     }
 4736 
 4737     for (unsigned i = 0; i < sig.args().length(); i++) {
 4738         if (sig.arg(i) != existing.arg(i)) {
 4739             return m.failf(usepn, "incompatible type for argument %u: (%s here vs. %s before)", i,
 4740                            ToCString(sig.arg(i)), ToCString(existing.arg(i)));
 4741         }
 4742     }
 4743 
 4744     if (sig.ret() != existing.ret()) {
 4745         return m.failf(usepn, "%s incompatible with previous return of type %s",
 4746                        ToCString(sig.ret()), ToCString(existing.ret()));
 4747     }
 4748 
 4749     MOZ_ASSERT(sig == existing);
 4750     return true;
 4751 }
 4752 
 4753 static bool
 4754 CheckFunctionSignature(ModuleValidator& m, ParseNode* usepn, Sig&& sig, PropertyName* name,
 4755                        ModuleValidator::Func** func)
 4756 {
 4757     ModuleValidator::Func* existing = m.lookupFunction(name);
 4758     if (!existing) {
 4759         if (!CheckModuleLevelName(m, usepn, name))
 4760             return false;
 4761         return m.addFunction(name, usepn->pn_pos.begin, Move(sig), func);
 4762     }
 4763 
 4764     if (!CheckSignatureAgainstExisting(m, usepn, sig, m.mg().funcSig(existing->index())))
 4765         return false;
 4766 
 4767     *func = existing;
 4768     return true;
 4769 }
 4770 
 4771 static bool
 4772 CheckIsArgType(FunctionValidator& f, ParseNode* argNode, Type type)
 4773 {
 4774     if (!type.isArgType())
 4775         return f.failf(argNode,
 4776                        "%s is not a subtype of int, float, double, or an allowed SIMD type",
 4777                        type.toChars());
 4778 
 4779     return true;
 4780 }
 4781 
 4782 static bool
 4783 CheckInternalCall(FunctionValidator& f, ParseNode* callNode, PropertyName* calleeName,
 4784                   Type ret, Type* type)
 4785 {
 4786     MOZ_ASSERT(ret.isCanonical());
 4787 
 4788     ValTypeVector args;
 4789     if (!CheckCallArgs<CheckIsArgType>(f, callNode, &args))
 4790         return false;
 4791 
 4792     Sig sig(Move(args), ret.canonicalToExprType());
 4793 
 4794     ModuleValidator::Func* callee;
 4795     if (!CheckFunctionSignature(f.m(), callNode, Move(sig), calleeName, &callee))
 4796         return false;
 4797 
 4798     if (!f.writeCall(callNode, Op::Call))
 4799         return false;
 4800 
 4801     if (!f.encoder().writeVarU32(callee->index()))
 4802         return false;
 4803 
 4804     *type = Type::ret(ret);
 4805     return true;
 4806 }
 4807 
 4808 static bool
 4809 CheckFuncPtrTableAgainstExisting(ModuleValidator& m, ParseNode* usepn, PropertyName* name,
 4810                                  Sig&& sig, unsigned mask, uint32_t* funcPtrTableIndex)
 4811 {
 4812     if (const ModuleValidator::Global* existing = m.lookupGlobal(name)) {
 4813         if (existing->which() != ModuleValidator::Global::FuncPtrTable)
 4814             return m.failName(usepn, "'%s' is not a function-pointer table", name);
 4815 
 4816         ModuleValidator::FuncPtrTable& table = m.funcPtrTable(existing->funcPtrTableIndex());
 4817         if (mask != table.mask())
 4818             return m.failf(usepn, "mask does not match previous value (%u)", table.mask());
 4819 
 4820         if (!CheckSignatureAgainstExisting(m, usepn, sig, m.mg().sig(table.sigIndex())))
 4821             return false;
 4822 
 4823         *funcPtrTableIndex = existing->funcPtrTableIndex();
 4824         return true;
 4825     }
 4826 
 4827     if (!CheckModuleLevelName(m, usepn, name))
 4828         return false;
 4829 
 4830     if (!m.declareFuncPtrTable(Move(sig), name, usepn->pn_pos.begin, mask, funcPtrTableIndex))
 4831         return false;
 4832 
 4833     return true;
 4834 }
 4835 
 4836 static bool
 4837 CheckFuncPtrCall(FunctionValidator& f, ParseNode* callNode, Type ret, Type* type)
 4838 {
 4839     MOZ_ASSERT(ret.isCanonical());
 4840 
 4841     ParseNode* callee = CallCallee(callNode);
 4842     ParseNode* tableNode = ElemBase(callee);
 4843     ParseNode* indexExpr = ElemIndex(callee);
 4844 
 4845     if (!tableNode->isKind(PNK_NAME))
 4846         return f.fail(tableNode, "expecting name of function-pointer array");
 4847 
 4848     PropertyName* name = tableNode->name();
 4849     if (const ModuleValidator::Global* existing = f.lookupGlobal(name)) {
 4850         if (existing->which() != ModuleValidator::Global::FuncPtrTable)
 4851             return f.failName(tableNode, "'%s' is not the name of a function-pointer array", name);
 4852     }
 4853 
 4854     if (!indexExpr->isKind(PNK_BITAND))
 4855         return f.fail(indexExpr, "function-pointer table index expression needs & mask");
 4856 
 4857     ParseNode* indexNode = BitwiseLeft(indexExpr);
 4858     ParseNode* maskNode = BitwiseRight(indexExpr);
 4859 
 4860     uint32_t mask;
 4861     if (!IsLiteralInt(f.m(), maskNode, &mask) || mask == UINT32_MAX || !IsPowerOfTwo(mask + 1))
 4862         return f.fail(maskNode, "function-pointer table index mask value must be a power of two minus 1");
 4863 
 4864     Type indexType;
 4865     if (!CheckExpr(f, indexNode, &indexType))
 4866         return false;
 4867 
 4868     if (!indexType.isIntish())
 4869         return f.failf(indexNode, "%s is not a subtype of intish", indexType.toChars());
 4870 
 4871     ValTypeVector args;
 4872     if (!CheckCallArgs<CheckIsArgType>(f, callNode, &args))
 4873         return false;
 4874 
 4875     Sig sig(Move(args), ret.canonicalToExprType());
 4876 
 4877     uint32_t tableIndex;
 4878     if (!CheckFuncPtrTableAgainstExisting(f.m(), tableNode, name, Move(sig), mask, &tableIndex))
 4879         return false;
 4880 
 4881     if (!f.writeCall(callNode, Op::OldCallIndirect))
 4882         return false;
 4883 
 4884     // Call signature
 4885     if (!f.encoder().writeVarU32(f.m().funcPtrTable(tableIndex).sigIndex()))
 4886         return false;
 4887 
 4888     *type = Type::ret(ret);
 4889     return true;
 4890 }
 4891 
 4892 static bool
 4893 CheckIsExternType(FunctionValidator& f, ParseNode* argNode, Type type)
 4894 {
 4895     if (!type.isExtern())
 4896         return f.failf(argNode, "%s is not a subtype of extern", type.toChars());
 4897     return true;
 4898 }
 4899 
 4900 static bool
 4901 CheckFFICall(FunctionValidator& f, ParseNode* callNode, unsigned ffiIndex, Type ret, Type* type)
 4902 {
 4903     MOZ_ASSERT(ret.isCanonical());
 4904 
 4905     PropertyName* calleeName = CallCallee(callNode)->name();
 4906 
 4907     if (ret.isFloat())
 4908         return f.fail(callNode, "FFI calls can't return float");
 4909     if (ret.isSimd())
 4910         return f.fail(callNode, "FFI calls can't return SIMD values");
 4911 
 4912     ValTypeVector args;
 4913     if (!CheckCallArgs<CheckIsExternType>(f, callNode, &args))
 4914         return false;
 4915 
 4916     Sig sig(Move(args), ret.canonicalToExprType());
 4917 
 4918     uint32_t funcIndex;
 4919     if (!f.m().declareImport(calleeName, Move(sig), ffiIndex, &funcIndex))
 4920         return false;
 4921 
 4922     if (!f.writeCall(callNode, Op::Call))
 4923         return false;
 4924 
 4925     if (!f.encoder().writeVarU32(funcIndex))
 4926         return false;
 4927 
 4928     *type = Type::ret(ret);
 4929     return true;
 4930 }
 4931 
 4932 static bool
 4933 CheckFloatCoercionArg(FunctionValidator& f, ParseNode* i