tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

AsmJS.cpp (217705B)


      1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*-
      2 * vim: set ts=8 sts=2 et sw=2 tw=80:
      3 *
      4 * Copyright 2014 Mozilla Foundation
      5 *
      6 * Licensed under the Apache License, Version 2.0 (the "License");
      7 * you may not use this file except in compliance with the License.
      8 * You may obtain a copy of the License at
      9 *
     10 *     http://www.apache.org/licenses/LICENSE-2.0
     11 *
     12 * Unless required by applicable law or agreed to in writing, software
     13 * distributed under the License is distributed on an "AS IS" BASIS,
     14 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     15 * See the License for the specific language governing permissions and
     16 * limitations under the License.
     17 */
     18 
     19 #include "wasm/AsmJS.h"
     20 
     21 #include "mozilla/Attributes.h"
     22 #include "mozilla/Compression.h"
     23 #include "mozilla/MathAlgorithms.h"
     24 #include "mozilla/Maybe.h"
     25 #include "mozilla/ScopeExit.h"
     26 #include "mozilla/Sprintf.h"  // SprintfLiteral
     27 #include "mozilla/Try.h"      // MOZ_TRY*
     28 #include "mozilla/Utf8.h"     // mozilla::Utf8Unit
     29 #include "mozilla/Variant.h"
     30 
     31 #include <algorithm>
     32 #include <new>
     33 
     34 #include "jsmath.h"
     35 
     36 #include "frontend/BytecodeCompiler.h"    // CompileStandaloneFunction
     37 #include "frontend/FrontendContext.h"     // js::FrontendContext
     38 #include "frontend/FunctionSyntaxKind.h"  // FunctionSyntaxKind
     39 #include "frontend/ParseNode.h"
     40 #include "frontend/Parser-macros.h"  // MOZ_TRY_*
     41 #include "frontend/Parser.h"
     42 #include "frontend/ParserAtom.h"     // ParserAtomsTable, TaggedParserAtomIndex
     43 #include "frontend/SharedContext.h"  // TopLevelFunction
     44 #include "frontend/TaggedParserAtomIndexHasher.h"  // TaggedParserAtomIndexHasher
     45 #include "gc/GC.h"
     46 #include "gc/Policy.h"
     47 #include "jit/InlinableNatives.h"
     48 #include "js/BuildId.h"  // JS::BuildIdCharVector
     49 #include "js/experimental/JitInfo.h"
     50 #include "js/friend/ErrorMessages.h"  // JSMSG_*
     51 #include "js/MemoryMetrics.h"
     52 #include "js/Printf.h"
     53 #include "js/ScalarType.h"  // js::Scalar::Type
     54 #include "js/SourceText.h"
     55 #include "js/StableStringChars.h"
     56 #include "js/Wrapper.h"
     57 #include "util/DifferentialTesting.h"
     58 #include "util/StringBuilder.h"
     59 #include "util/Text.h"
     60 #include "vm/ErrorReporting.h"
     61 #include "vm/FunctionFlags.h"          // js::FunctionFlags
     62 #include "vm/GeneratorAndAsyncKind.h"  // js::GeneratorKind, js::FunctionAsyncKind
     63 #include "vm/Interpreter.h"
     64 #include "vm/SelfHosting.h"
     65 #include "vm/Time.h"
     66 #include "vm/TypedArrayObject.h"
     67 #include "vm/Warnings.h"  // js::WarnNumberASCII
     68 #include "wasm/WasmCompile.h"
     69 #include "wasm/WasmFeatures.h"
     70 #include "wasm/WasmGenerator.h"
     71 #include "wasm/WasmInstance.h"
     72 #include "wasm/WasmIonCompile.h"
     73 #include "wasm/WasmJS.h"
     74 #include "wasm/WasmModuleTypes.h"
     75 #include "wasm/WasmSerialize.h"
     76 #include "wasm/WasmSignalHandlers.h"
     77 #include "wasm/WasmValidate.h"
     78 
     79 #include "frontend/SharedContext-inl.h"
     80 #include "vm/ArrayBufferObject-inl.h"
     81 #include "vm/JSObject-inl.h"
     82 #include "wasm/WasmInstance-inl.h"
     83 
     84 using namespace js;
     85 using namespace js::frontend;
     86 using namespace js::jit;
     87 using namespace js::wasm;
     88 
     89 using JS::AsmJSOption;
     90 using JS::AutoStableStringChars;
     91 using JS::GenericNaN;
     92 using JS::SourceText;
     93 using mozilla::Abs;
     94 using mozilla::AsVariant;
     95 using mozilla::CeilingLog2;
     96 using mozilla::HashGeneric;
     97 using mozilla::IsNegativeZero;
     98 using mozilla::IsPositiveZero;
     99 using mozilla::IsPowerOfTwo;
    100 using mozilla::Maybe;
    101 using mozilla::Nothing;
    102 using mozilla::PodZero;
    103 using mozilla::PositiveInfinity;
    104 using mozilla::Some;
    105 using mozilla::Utf8Unit;
    106 using mozilla::Compression::LZ4;
    107 
    108 using FunctionVector = JS::GCVector<JSFunction*>;
    109 
    110 /*****************************************************************************/
    111 
    112 // A wasm module can either use no memory, a unshared memory (ArrayBuffer) or
    113 // shared memory (SharedArrayBuffer).
    114 
    115 enum class MemoryUsage { None = false, Unshared = 1, Shared = 2 };
    116 
    117 // The asm.js valid heap lengths are precisely the WASM valid heap lengths for
    118 // ARM greater or equal to MinHeapLength
    119 static const size_t MinHeapLength = StandardPageSizeBytes;
    120 // An asm.js heap can in principle be up to INT32_MAX bytes but requirements
    121 // on the format restrict it further to the largest pseudo-ARM-immediate.
    122 // See IsValidAsmJSHeapLength().
    123 static const uint64_t MaxHeapLength = 0x7f000000;
    124 
    125 // Because ARM has a fixed-width instruction encoding, ARM can only express a
    126 // limited subset of immediates (in a single instruction).
    127 static const uint64_t HighestValidARMImmediate = 0xff000000;
    128 
    129 //  Heap length on ARM should fit in an ARM immediate. We approximate the set
    130 //  of valid ARM immediates with the predicate:
    131 //    2^n for n in [16, 24)
    132 //  or
    133 //    2^24 * n for n >= 1.
    134 static bool IsValidARMImmediate(uint32_t i) {
    135  bool valid = (IsPowerOfTwo(i) || (i & 0x00ffffff) == 0);
    136 
    137  MOZ_ASSERT_IF(valid, i % StandardPageSizeBytes == 0);
    138 
    139  return valid;
    140 }
    141 
    142 static uint64_t RoundUpToNextValidARMImmediate(uint64_t i) {
    143  MOZ_ASSERT(i <= HighestValidARMImmediate);
    144  static_assert(HighestValidARMImmediate == 0xff000000,
    145                "algorithm relies on specific constant");
    146 
    147  if (i <= 16 * 1024 * 1024) {
    148    i = i ? mozilla::RoundUpPow2(i) : 0;
    149  } else {
    150    i = (i + 0x00ffffff) & ~0x00ffffff;
    151  }
    152 
    153  MOZ_ASSERT(IsValidARMImmediate(i));
    154 
    155  return i;
    156 }
    157 
    158 static uint64_t RoundUpToNextValidAsmJSHeapLength(uint64_t length) {
    159  if (length <= MinHeapLength) {
    160    return MinHeapLength;
    161  }
    162 
    163  return RoundUpToNextValidARMImmediate(length);
    164 }
    165 
    166 static uint64_t DivideRoundingUp(uint64_t a, uint64_t b) {
    167  return (a + (b - 1)) / b;
    168 }
    169 
    170 /*****************************************************************************/
    171 // asm.js module object
    172 
    173 // The asm.js spec recognizes this set of builtin Math functions.
    174 enum AsmJSMathBuiltinFunction {
    175  AsmJSMathBuiltin_sin,
    176  AsmJSMathBuiltin_cos,
    177  AsmJSMathBuiltin_tan,
    178  AsmJSMathBuiltin_asin,
    179  AsmJSMathBuiltin_acos,
    180  AsmJSMathBuiltin_atan,
    181  AsmJSMathBuiltin_ceil,
    182  AsmJSMathBuiltin_floor,
    183  AsmJSMathBuiltin_exp,
    184  AsmJSMathBuiltin_log,
    185  AsmJSMathBuiltin_pow,
    186  AsmJSMathBuiltin_sqrt,
    187  AsmJSMathBuiltin_abs,
    188  AsmJSMathBuiltin_atan2,
    189  AsmJSMathBuiltin_imul,
    190  AsmJSMathBuiltin_fround,
    191  AsmJSMathBuiltin_min,
    192  AsmJSMathBuiltin_max,
    193  AsmJSMathBuiltin_clz32
    194 };
    195 
    196 // LitValPOD is a restricted version of LitVal suitable for asm.js that is
    197 // always POD.
    198 
    199 struct LitValPOD {
    200  PackedTypeCode valType_;
    201  union U {
    202    uint32_t u32_;
    203    uint64_t u64_;
    204    float f32_;
    205    double f64_;
    206  } u;
    207 
    208  LitValPOD() = default;
    209 
    210  explicit LitValPOD(uint32_t u32) : valType_(ValType(ValType::I32).packed()) {
    211    u.u32_ = u32;
    212  }
    213  explicit LitValPOD(uint64_t u64) : valType_(ValType(ValType::I64).packed()) {
    214    u.u64_ = u64;
    215  }
    216 
    217  explicit LitValPOD(float f32) : valType_(ValType(ValType::F32).packed()) {
    218    u.f32_ = f32;
    219  }
    220  explicit LitValPOD(double f64) : valType_(ValType(ValType::F64).packed()) {
    221    u.f64_ = f64;
    222  }
    223 
    224  LitVal asLitVal() const {
    225    switch (valType_.typeCode()) {
    226      case TypeCode::I32:
    227        return LitVal(u.u32_);
    228      case TypeCode::I64:
    229        return LitVal(u.u64_);
    230      case TypeCode::F32:
    231        return LitVal(u.f32_);
    232      case TypeCode::F64:
    233        return LitVal(u.f64_);
    234      default:
    235        MOZ_CRASH("Can't happen");
    236    }
    237  }
    238 };
    239 
    240 static_assert(std::is_trivially_copyable_v<LitValPOD>,
    241              "must be trivially copyable for serialization/deserialization");
    242 
    243 // An AsmJSGlobal represents a JS global variable in the asm.js module function.
    244 class AsmJSGlobal {
    245 public:
    246  enum Which {
    247    Variable,
    248    FFI,
    249    ArrayView,
    250    ArrayViewCtor,
    251    MathBuiltinFunction,
    252    Constant
    253  };
    254  enum VarInitKind { InitConstant, InitImport };
    255  enum ConstantKind { GlobalConstant, MathConstant };
    256 
    257 private:
    258  struct CacheablePod {
    259    Which which_;
    260    union V {
    261      struct {
    262        VarInitKind initKind_;
    263        union U {
    264          PackedTypeCode importValType_;
    265          LitValPOD val_;
    266        } u;
    267      } var;
    268      uint32_t ffiIndex_;
    269      Scalar::Type viewType_;
    270      AsmJSMathBuiltinFunction mathBuiltinFunc_;
    271      struct {
    272        ConstantKind kind_;
    273        double value_;
    274      } constant;
    275    } u;
    276  } pod;
    277  CacheableChars field_;
    278 
    279  friend class ModuleValidatorShared;
    280  template <typename Unit>
    281  friend class ModuleValidator;
    282 
    283 public:
    284  AsmJSGlobal() = default;
    285  AsmJSGlobal(Which which, UniqueChars field) {
    286    mozilla::PodZero(&pod);  // zero padding for Valgrind
    287    pod.which_ = which;
    288    field_ = std::move(field);
    289  }
    290  const char* field() const { return field_.get(); }
    291  Which which() const { return pod.which_; }
    292  VarInitKind varInitKind() const {
    293    MOZ_ASSERT(pod.which_ == Variable);
    294    return pod.u.var.initKind_;
    295  }
    296  LitValPOD varInitVal() const {
    297    MOZ_ASSERT(pod.which_ == Variable);
    298    MOZ_ASSERT(pod.u.var.initKind_ == InitConstant);
    299    return pod.u.var.u.val_;
    300  }
    301  ValType varInitImportType() const {
    302    MOZ_ASSERT(pod.which_ == Variable);
    303    MOZ_ASSERT(pod.u.var.initKind_ == InitImport);
    304    return ValType(pod.u.var.u.importValType_);
    305  }
    306  uint32_t ffiIndex() const {
    307    MOZ_ASSERT(pod.which_ == FFI);
    308    return pod.u.ffiIndex_;
    309  }
    310  // When a view is created from an imported constructor:
    311  //   var I32 = stdlib.Int32Array;
    312  //   var i32 = new I32(buffer);
    313  // the second import has nothing to validate and thus has a null field.
    314  Scalar::Type viewType() const {
    315    MOZ_ASSERT(pod.which_ == ArrayView || pod.which_ == ArrayViewCtor);
    316    return pod.u.viewType_;
    317  }
    318  AsmJSMathBuiltinFunction mathBuiltinFunction() const {
    319    MOZ_ASSERT(pod.which_ == MathBuiltinFunction);
    320    return pod.u.mathBuiltinFunc_;
    321  }
    322  ConstantKind constantKind() const {
    323    MOZ_ASSERT(pod.which_ == Constant);
    324    return pod.u.constant.kind_;
    325  }
    326  double constantValue() const {
    327    MOZ_ASSERT(pod.which_ == Constant);
    328    return pod.u.constant.value_;
    329  }
    330 };
    331 
    332 using AsmJSGlobalVector = Vector<AsmJSGlobal, 0, SystemAllocPolicy>;
    333 
    334 // An AsmJSImport is slightly different than an asm.js FFI function: a single
    335 // asm.js FFI function can be called with many different signatures. When
    336 // compiled to wasm, each unique FFI function paired with signature generates a
    337 // wasm import.
    338 class AsmJSImport {
    339  uint32_t ffiIndex_;
    340 
    341 public:
    342  AsmJSImport() = default;
    343  explicit AsmJSImport(uint32_t ffiIndex) : ffiIndex_(ffiIndex) {}
    344  uint32_t ffiIndex() const { return ffiIndex_; }
    345 };
    346 
    347 using AsmJSImportVector = Vector<AsmJSImport, 0, SystemAllocPolicy>;
    348 
    349 // An AsmJSExport logically extends Export with the extra information needed for
    350 // an asm.js exported function, viz., the offsets in module's source chars in
    351 // case the function is toString()ed.
    352 class AsmJSExport {
    353  uint32_t funcIndex_ = 0;
    354 
    355  // All fields are treated as cacheable POD:
    356  uint32_t startOffsetInModule_ = 0;  // Store module-start-relative offsets
    357  uint32_t endOffsetInModule_ = 0;    // so preserved by serialization.
    358 
    359 public:
    360  AsmJSExport() = default;
    361  AsmJSExport(uint32_t funcIndex, uint32_t startOffsetInModule,
    362              uint32_t endOffsetInModule)
    363      : funcIndex_(funcIndex),
    364        startOffsetInModule_(startOffsetInModule),
    365        endOffsetInModule_(endOffsetInModule) {}
    366  uint32_t funcIndex() const { return funcIndex_; }
    367  uint32_t startOffsetInModule() const { return startOffsetInModule_; }
    368  uint32_t endOffsetInModule() const { return endOffsetInModule_; }
    369 };
    370 
    371 using AsmJSExportVector = Vector<AsmJSExport, 0, SystemAllocPolicy>;
    372 
    373 // Holds the immutable guts of an AsmJSModule.
    374 //
    375 // CodeMetadataForAsmJSImpl is built incrementally by ModuleValidator and then
    376 // shared immutably between AsmJSModules.
    377 
    378 struct js::CodeMetadataForAsmJSImpl : CodeMetadataForAsmJS {
    379  uint32_t numFFIs = 0;
    380  uint32_t srcLength = 0;
    381  uint32_t srcLengthWithRightBrace = 0;
    382  AsmJSGlobalVector asmJSGlobals;
    383  AsmJSImportVector asmJSImports;
    384  AsmJSExportVector asmJSExports;
    385  CacheableCharsVector asmJSFuncNames;
    386  CacheableChars globalArgumentName;
    387  CacheableChars importArgumentName;
    388  CacheableChars bufferArgumentName;
    389 
    390  // These values are not serialized since they are relative to the
    391  // containing script which can be different between serialization and
    392  // deserialization contexts. Thus, they must be set explicitly using the
    393  // ambient Parser/ScriptSource after deserialization.
    394  //
    395  // srcStart refers to the offset in the ScriptSource to the beginning of
    396  // the asm.js module function. If the function has been created with the
    397  // Function constructor, this will be the first character in the function
    398  // source. Otherwise, it will be the opening parenthesis of the arguments
    399  // list.
    400  uint32_t toStringStart;
    401  uint32_t srcStart;
    402  bool strict;
    403  bool alwaysUseFdlibm = false;
    404  RefPtr<ScriptSource> source;
    405 
    406  uint32_t srcEndBeforeCurly() const { return srcStart + srcLength; }
    407  uint32_t srcEndAfterCurly() const {
    408    return srcStart + srcLengthWithRightBrace;
    409  }
    410 
    411  CodeMetadataForAsmJSImpl() : toStringStart(0), srcStart(0), strict(false) {}
    412  ~CodeMetadataForAsmJSImpl() = default;
    413 
    414  const CodeMetadataForAsmJSImpl& asAsmJS() const { return *this; }
    415 
    416  const AsmJSExport& lookupAsmJSExport(uint32_t funcIndex) const {
    417    // The AsmJSExportVector isn't stored in sorted order so do a linear
    418    // search. This is for the super-cold and already-expensive toString()
    419    // path and the number of exports is generally small.
    420    for (const AsmJSExport& exp : asmJSExports) {
    421      if (exp.funcIndex() == funcIndex) {
    422        return exp;
    423      }
    424    }
    425    MOZ_CRASH("missing asm.js func export");
    426  }
    427 
    428  bool mutedErrors() const { return source->mutedErrors(); }
    429  const char16_t* displayURL() const {
    430    return source->hasDisplayURL() ? source->displayURL() : nullptr;
    431  }
    432  ScriptSource* maybeScriptSource() const { return source.get(); }
    433  bool getFuncNameForAsmJS(uint32_t funcIndex, UTF8Bytes* name) const {
    434    const char* p = asmJSFuncNames[funcIndex].get();
    435    if (!p) {
    436      return true;
    437    }
    438    return name->append(p, strlen(p));
    439  }
    440 
    441  size_t sizeOfExcludingThis(mozilla::MallocSizeOf mallocSizeOf) const {
    442    return asmJSGlobals.sizeOfExcludingThis(mallocSizeOf) +
    443           asmJSImports.sizeOfExcludingThis(mallocSizeOf) +
    444           asmJSExports.sizeOfExcludingThis(mallocSizeOf) +
    445           asmJSFuncNames.sizeOfExcludingThis(mallocSizeOf) +
    446           globalArgumentName.sizeOfExcludingThis(mallocSizeOf) +
    447           importArgumentName.sizeOfExcludingThis(mallocSizeOf) +
    448           bufferArgumentName.sizeOfExcludingThis(mallocSizeOf);
    449  }
    450 };
    451 
    452 using MutableCodeMetadataForAsmJSImpl = RefPtr<CodeMetadataForAsmJSImpl>;
    453 
    454 /*****************************************************************************/
    455 // ParseNode utilities
    456 
    457 static inline ParseNode* NextNode(ParseNode* pn) { return pn->pn_next; }
    458 
    459 static inline ParseNode* UnaryKid(ParseNode* pn) {
    460  return pn->as<UnaryNode>().kid();
    461 }
    462 
    463 static inline ParseNode* BinaryRight(ParseNode* pn) {
    464  return pn->as<BinaryNode>().right();
    465 }
    466 
    467 static inline ParseNode* BinaryLeft(ParseNode* pn) {
    468  return pn->as<BinaryNode>().left();
    469 }
    470 
    471 static inline ParseNode* ReturnExpr(ParseNode* pn) {
    472  MOZ_ASSERT(pn->isKind(ParseNodeKind::ReturnStmt));
    473  return UnaryKid(pn);
    474 }
    475 
    476 static inline ParseNode* TernaryKid1(ParseNode* pn) {
    477  return pn->as<TernaryNode>().kid1();
    478 }
    479 
    480 static inline ParseNode* TernaryKid2(ParseNode* pn) {
    481  return pn->as<TernaryNode>().kid2();
    482 }
    483 
    484 static inline ParseNode* TernaryKid3(ParseNode* pn) {
    485  return pn->as<TernaryNode>().kid3();
    486 }
    487 
    488 static inline ParseNode* ListHead(ParseNode* pn) {
    489  return pn->as<ListNode>().head();
    490 }
    491 
    492 static inline unsigned ListLength(ParseNode* pn) {
    493  return pn->as<ListNode>().count();
    494 }
    495 
    496 static inline ParseNode* CallCallee(ParseNode* pn) {
    497  MOZ_ASSERT(pn->isKind(ParseNodeKind::CallExpr));
    498  return BinaryLeft(pn);
    499 }
    500 
    501 static inline unsigned CallArgListLength(ParseNode* pn) {
    502  MOZ_ASSERT(pn->isKind(ParseNodeKind::CallExpr));
    503  return ListLength(BinaryRight(pn));
    504 }
    505 
    506 static inline ParseNode* CallArgList(ParseNode* pn) {
    507  MOZ_ASSERT(pn->isKind(ParseNodeKind::CallExpr));
    508  return ListHead(BinaryRight(pn));
    509 }
    510 
    511 static inline ParseNode* VarListHead(ParseNode* pn) {
    512  MOZ_ASSERT(pn->isKind(ParseNodeKind::VarStmt) ||
    513             pn->isKind(ParseNodeKind::ConstDecl));
    514  return ListHead(pn);
    515 }
    516 
    517 static inline bool IsDefaultCase(ParseNode* pn) {
    518  return pn->as<CaseClause>().isDefault();
    519 }
    520 
    521 static inline ParseNode* CaseExpr(ParseNode* pn) {
    522  return pn->as<CaseClause>().caseExpression();
    523 }
    524 
    525 static inline ParseNode* CaseBody(ParseNode* pn) {
    526  return pn->as<CaseClause>().statementList();
    527 }
    528 
    529 static inline ParseNode* BinaryOpLeft(ParseNode* pn) {
    530  MOZ_ASSERT(pn->isBinaryOperation());
    531  MOZ_ASSERT(pn->as<ListNode>().count() == 2);
    532  return ListHead(pn);
    533 }
    534 
    535 static inline ParseNode* BinaryOpRight(ParseNode* pn) {
    536  MOZ_ASSERT(pn->isBinaryOperation());
    537  MOZ_ASSERT(pn->as<ListNode>().count() == 2);
    538  return NextNode(ListHead(pn));
    539 }
    540 
    541 static inline ParseNode* BitwiseLeft(ParseNode* pn) { return BinaryOpLeft(pn); }
    542 
    543 static inline ParseNode* BitwiseRight(ParseNode* pn) {
    544  return BinaryOpRight(pn);
    545 }
    546 
    547 static inline ParseNode* MultiplyLeft(ParseNode* pn) {
    548  MOZ_ASSERT(pn->isKind(ParseNodeKind::MulExpr));
    549  return BinaryOpLeft(pn);
    550 }
    551 
    552 static inline ParseNode* MultiplyRight(ParseNode* pn) {
    553  MOZ_ASSERT(pn->isKind(ParseNodeKind::MulExpr));
    554  return BinaryOpRight(pn);
    555 }
    556 
    557 static inline ParseNode* AddSubLeft(ParseNode* pn) {
    558  MOZ_ASSERT(pn->isKind(ParseNodeKind::AddExpr) ||
    559             pn->isKind(ParseNodeKind::SubExpr));
    560  return BinaryOpLeft(pn);
    561 }
    562 
    563 static inline ParseNode* AddSubRight(ParseNode* pn) {
    564  MOZ_ASSERT(pn->isKind(ParseNodeKind::AddExpr) ||
    565             pn->isKind(ParseNodeKind::SubExpr));
    566  return BinaryOpRight(pn);
    567 }
    568 
    569 static inline ParseNode* DivOrModLeft(ParseNode* pn) {
    570  MOZ_ASSERT(pn->isKind(ParseNodeKind::DivExpr) ||
    571             pn->isKind(ParseNodeKind::ModExpr));
    572  return BinaryOpLeft(pn);
    573 }
    574 
    575 static inline ParseNode* DivOrModRight(ParseNode* pn) {
    576  MOZ_ASSERT(pn->isKind(ParseNodeKind::DivExpr) ||
    577             pn->isKind(ParseNodeKind::ModExpr));
    578  return BinaryOpRight(pn);
    579 }
    580 
    581 static inline ParseNode* ComparisonLeft(ParseNode* pn) {
    582  return BinaryOpLeft(pn);
    583 }
    584 
    585 static inline ParseNode* ComparisonRight(ParseNode* pn) {
    586  return BinaryOpRight(pn);
    587 }
    588 
    589 static inline bool IsExpressionStatement(ParseNode* pn) {
    590  return pn->isKind(ParseNodeKind::ExpressionStmt);
    591 }
    592 
    593 static inline ParseNode* ExpressionStatementExpr(ParseNode* pn) {
    594  MOZ_ASSERT(pn->isKind(ParseNodeKind::ExpressionStmt));
    595  return UnaryKid(pn);
    596 }
    597 
    598 static inline TaggedParserAtomIndex LoopControlMaybeLabel(ParseNode* pn) {
    599  MOZ_ASSERT(pn->isKind(ParseNodeKind::BreakStmt) ||
    600             pn->isKind(ParseNodeKind::ContinueStmt));
    601  return pn->as<LoopControlStatement>().label();
    602 }
    603 
    604 static inline TaggedParserAtomIndex LabeledStatementLabel(ParseNode* pn) {
    605  return pn->as<LabeledStatement>().label();
    606 }
    607 
    608 static inline ParseNode* LabeledStatementStatement(ParseNode* pn) {
    609  return pn->as<LabeledStatement>().statement();
    610 }
    611 
    612 static double NumberNodeValue(ParseNode* pn) {
    613  return pn->as<NumericLiteral>().value();
    614 }
    615 
    616 static bool NumberNodeHasFrac(ParseNode* pn) {
    617  return pn->as<NumericLiteral>().decimalPoint() == HasDecimal;
    618 }
    619 
    620 static ParseNode* DotBase(ParseNode* pn) {
    621  return &pn->as<PropertyAccess>().expression();
    622 }
    623 
    624 static TaggedParserAtomIndex DotMember(ParseNode* pn) {
    625  return pn->as<PropertyAccess>().name();
    626 }
    627 
    628 static ParseNode* ElemBase(ParseNode* pn) {
    629  return &pn->as<PropertyByValue>().expression();
    630 }
    631 
    632 static ParseNode* ElemIndex(ParseNode* pn) {
    633  return &pn->as<PropertyByValue>().key();
    634 }
    635 
    636 static inline TaggedParserAtomIndex FunctionName(FunctionNode* funNode) {
    637  if (auto name = funNode->funbox()->explicitName()) {
    638    return name;
    639  }
    640  return TaggedParserAtomIndex::null();
    641 }
    642 
    643 static inline ParseNode* FunctionFormalParametersList(FunctionNode* fn,
    644                                                      unsigned* numFormals) {
    645  ParamsBodyNode* argsBody = fn->body();
    646 
    647  // The number of formals is equal to the number of parameters (excluding the
    648  // trailing lexical scope). There are no destructuring or rest parameters for
    649  // asm.js functions.
    650  *numFormals = argsBody->count();
    651 
    652  // If the function has been fully parsed, the trailing function body node is a
    653  // lexical scope. If we've only parsed the function parameters, the last node
    654  // is the last parameter.
    655  if (*numFormals > 0 && argsBody->last()->is<LexicalScopeNode>()) {
    656    MOZ_ASSERT(argsBody->last()->as<LexicalScopeNode>().scopeBody()->isKind(
    657        ParseNodeKind::StatementList));
    658    (*numFormals)--;
    659  }
    660 
    661  return argsBody->head();
    662 }
    663 
    664 static inline ParseNode* FunctionStatementList(FunctionNode* funNode) {
    665  LexicalScopeNode* last = funNode->body()->body();
    666  MOZ_ASSERT(last->isEmptyScope());
    667  ParseNode* body = last->scopeBody();
    668  MOZ_ASSERT(body->isKind(ParseNodeKind::StatementList));
    669  return body;
    670 }
    671 
    672 static inline bool IsNormalObjectField(ParseNode* pn) {
    673  return pn->isKind(ParseNodeKind::PropertyDefinition) &&
    674         pn->as<PropertyDefinition>().accessorType() == AccessorType::None &&
    675         BinaryLeft(pn)->isKind(ParseNodeKind::ObjectPropertyName);
    676 }
    677 
    678 static inline TaggedParserAtomIndex ObjectNormalFieldName(ParseNode* pn) {
    679  MOZ_ASSERT(IsNormalObjectField(pn));
    680  MOZ_ASSERT(BinaryLeft(pn)->isKind(ParseNodeKind::ObjectPropertyName));
    681  return BinaryLeft(pn)->as<NameNode>().atom();
    682 }
    683 
    684 static inline ParseNode* ObjectNormalFieldInitializer(ParseNode* pn) {
    685  MOZ_ASSERT(IsNormalObjectField(pn));
    686  return BinaryRight(pn);
    687 }
    688 
    689 static inline bool IsUseOfName(ParseNode* pn, TaggedParserAtomIndex name) {
    690  return pn->isName(name);
    691 }
    692 
    693 static inline bool IsIgnoredDirectiveName(TaggedParserAtomIndex atom) {
    694  return atom != TaggedParserAtomIndex::WellKnown::use_strict_();
    695 }
    696 
    697 static inline bool IsIgnoredDirective(ParseNode* pn) {
    698  return pn->isKind(ParseNodeKind::ExpressionStmt) &&
    699         UnaryKid(pn)->isKind(ParseNodeKind::StringExpr) &&
    700         IsIgnoredDirectiveName(UnaryKid(pn)->as<NameNode>().atom());
    701 }
    702 
    703 static inline bool IsEmptyStatement(ParseNode* pn) {
    704  return pn->isKind(ParseNodeKind::EmptyStmt);
    705 }
    706 
    707 static inline ParseNode* SkipEmptyStatements(ParseNode* pn) {
    708  while (pn && IsEmptyStatement(pn)) {
    709    pn = pn->pn_next;
    710  }
    711  return pn;
    712 }
    713 
    714 static inline ParseNode* NextNonEmptyStatement(ParseNode* pn) {
    715  return SkipEmptyStatements(pn->pn_next);
    716 }
    717 
    718 template <typename Unit>
    719 static bool GetToken(AsmJSParser<Unit>& parser, TokenKind* tkp) {
    720  auto& ts = parser.tokenStream;
    721  TokenKind tk;
    722  while (true) {
    723    if (!ts.getToken(&tk, TokenStreamShared::SlashIsRegExp)) {
    724      return false;
    725    }
    726    if (tk != TokenKind::Semi) {
    727      break;
    728    }
    729  }
    730  *tkp = tk;
    731  return true;
    732 }
    733 
    734 template <typename Unit>
    735 static bool PeekToken(AsmJSParser<Unit>& parser, TokenKind* tkp) {
    736  auto& ts = parser.tokenStream;
    737  TokenKind tk;
    738  while (true) {
    739    if (!ts.peekToken(&tk, TokenStream::SlashIsRegExp)) {
    740      return false;
    741    }
    742    if (tk != TokenKind::Semi) {
    743      break;
    744    }
    745    ts.consumeKnownToken(TokenKind::Semi, TokenStreamShared::SlashIsRegExp);
    746  }
    747  *tkp = tk;
    748  return true;
    749 }
    750 
    751 template <typename Unit>
    752 static bool ParseVarOrConstStatement(AsmJSParser<Unit>& parser,
    753                                     ParseNode** var) {
    754  TokenKind tk;
    755  if (!PeekToken(parser, &tk)) {
    756    return false;
    757  }
    758  if (tk != TokenKind::Var && tk != TokenKind::Const) {
    759    *var = nullptr;
    760    return true;
    761  }
    762 
    763  MOZ_TRY_VAR_OR_RETURN(*var, parser.statementListItem(YieldIsName), false);
    764 
    765  MOZ_ASSERT((*var)->isKind(ParseNodeKind::VarStmt) ||
    766             (*var)->isKind(ParseNodeKind::ConstDecl));
    767  return true;
    768 }
    769 
    770 /*****************************************************************************/
    771 
    772 // Represents the type and value of an asm.js numeric literal.
    773 //
    774 // A literal is a double iff the literal contains a decimal point (even if the
    775 // fractional part is 0). Otherwise, integers may be classified:
    776 //  fixnum: [0, 2^31)
    777 //  negative int: [-2^31, 0)
    778 //  big unsigned: [2^31, 2^32)
    779 //  out of range: otherwise
    780 // Lastly, a literal may be a float literal which is any double or integer
    781 // literal coerced with Math.fround.
    782 class NumLit {
    783 public:
    784  enum Which {
    785    Fixnum,
    786    NegativeInt,
    787    BigUnsigned,
    788    Double,
    789    Float,
    790    OutOfRangeInt = -1
    791  };
    792 
    793 private:
    794  Which which_;
    795  JS::Value value_;
    796 
    797 public:
    798  NumLit() = default;
    799 
    800  NumLit(Which w, const Value& v) : which_(w), value_(v) {}
    801 
    802  Which which() const { return which_; }
    803 
    804  int32_t toInt32() const {
    805    MOZ_ASSERT(which_ == Fixnum || which_ == NegativeInt ||
    806               which_ == BigUnsigned);
    807    return value_.toInt32();
    808  }
    809 
    810  uint32_t toUint32() const { return (uint32_t)toInt32(); }
    811 
    812  double toDouble() const {
    813    MOZ_ASSERT(which_ == Double);
    814    return value_.toDouble();
    815  }
    816 
    817  float toFloat() const {
    818    MOZ_ASSERT(which_ == Float);
    819    return float(value_.toDouble());
    820  }
    821 
    822  Value scalarValue() const {
    823    MOZ_ASSERT(which_ != OutOfRangeInt);
    824    return value_;
    825  }
    826 
    827  bool valid() const { return which_ != OutOfRangeInt; }
    828 
    829  bool isZeroBits() const {
    830    MOZ_ASSERT(valid());
    831    switch (which()) {
    832      case NumLit::Fixnum:
    833      case NumLit::NegativeInt:
    834      case NumLit::BigUnsigned:
    835        return toInt32() == 0;
    836      case NumLit::Double:
    837        return IsPositiveZero(toDouble());
    838      case NumLit::Float:
    839        return IsPositiveZero(toFloat());
    840      case NumLit::OutOfRangeInt:
    841        MOZ_CRASH("can't be here because of valid() check above");
    842    }
    843    return false;
    844  }
    845 
    846  LitValPOD value() const {
    847    switch (which_) {
    848      case NumLit::Fixnum:
    849      case NumLit::NegativeInt:
    850      case NumLit::BigUnsigned:
    851        return LitValPOD(toUint32());
    852      case NumLit::Float:
    853        return LitValPOD(toFloat());
    854      case NumLit::Double:
    855        return LitValPOD(toDouble());
    856      case NumLit::OutOfRangeInt:;
    857    }
    858    MOZ_CRASH("bad literal");
    859  }
    860 };
    861 
    862 // Represents the type of a general asm.js expression.
    863 //
    864 // A canonical subset of types representing the coercion targets: Int, Float,
    865 // Double.
    866 //
    867 // Void is also part of the canonical subset.
    868 
    869 class Type {
    870 public:
    871  enum Which {
    872    Fixnum = NumLit::Fixnum,
    873    Signed = NumLit::NegativeInt,
    874    Unsigned = NumLit::BigUnsigned,
    875    DoubleLit = NumLit::Double,
    876    Float = NumLit::Float,
    877    Double,
    878    MaybeDouble,
    879    MaybeFloat,
    880    Floatish,
    881    Int,
    882    Intish,
    883    Void
    884  };
    885 
    886 private:
    887  Which which_;
    888 
    889 public:
    890  Type() = default;
    891  MOZ_IMPLICIT Type(Which w) : which_(w) {}
    892 
    893  // Map an already canonicalized Type to the return type of a function call.
    894  static Type ret(Type t) {
    895    MOZ_ASSERT(t.isCanonical());
    896    // The 32-bit external type is Signed, not Int.
    897    return t.isInt() ? Signed : t;
    898  }
    899 
    900  static Type lit(const NumLit& lit) {
    901    MOZ_ASSERT(lit.valid());
    902    Which which = Type::Which(lit.which());
    903    MOZ_ASSERT(which >= Fixnum && which <= Float);
    904    Type t;
    905    t.which_ = which;
    906    return t;
    907  }
    908 
    909  // Map |t| to one of the canonical vartype representations of a
    910  // wasm::ValType.
    911  static Type canonicalize(Type t) {
    912    switch (t.which()) {
    913      case Fixnum:
    914      case Signed:
    915      case Unsigned:
    916      case Int:
    917        return Int;
    918 
    919      case Float:
    920        return Float;
    921 
    922      case DoubleLit:
    923      case Double:
    924        return Double;
    925 
    926      case Void:
    927        return Void;
    928 
    929      case MaybeDouble:
    930      case MaybeFloat:
    931      case Floatish:
    932      case Intish:
    933        // These types need some kind of coercion, they can't be mapped
    934        // to an VarType.
    935        break;
    936    }
    937    MOZ_CRASH("Invalid vartype");
    938  }
    939 
    940  Which which() const { return which_; }
    941 
    942  bool operator==(Type rhs) const { return which_ == rhs.which_; }
    943  bool operator!=(Type rhs) const { return which_ != rhs.which_; }
    944 
    945  bool operator<=(Type rhs) const {
    946    switch (rhs.which_) {
    947      case Signed:
    948        return isSigned();
    949      case Unsigned:
    950        return isUnsigned();
    951      case DoubleLit:
    952        return isDoubleLit();
    953      case Double:
    954        return isDouble();
    955      case Float:
    956        return isFloat();
    957      case MaybeDouble:
    958        return isMaybeDouble();
    959      case MaybeFloat:
    960        return isMaybeFloat();
    961      case Floatish:
    962        return isFloatish();
    963      case Int:
    964        return isInt();
    965      case Intish:
    966        return isIntish();
    967      case Fixnum:
    968        return isFixnum();
    969      case Void:
    970        return isVoid();
    971    }
    972    MOZ_CRASH("unexpected rhs type");
    973  }
    974 
    975  bool isFixnum() const { return which_ == Fixnum; }
    976 
    977  bool isSigned() const { return which_ == Signed || which_ == Fixnum; }
    978 
    979  bool isUnsigned() const { return which_ == Unsigned || which_ == Fixnum; }
    980 
    981  bool isInt() const { return isSigned() || isUnsigned() || which_ == Int; }
    982 
    983  bool isIntish() const { return isInt() || which_ == Intish; }
    984 
    985  bool isDoubleLit() const { return which_ == DoubleLit; }
    986 
    987  bool isDouble() const { return isDoubleLit() || which_ == Double; }
    988 
    989  bool isMaybeDouble() const { return isDouble() || which_ == MaybeDouble; }
    990 
    991  bool isFloat() const { return which_ == Float; }
    992 
    993  bool isMaybeFloat() const { return isFloat() || which_ == MaybeFloat; }
    994 
    995  bool isFloatish() const { return isMaybeFloat() || which_ == Floatish; }
    996 
    997  bool isVoid() const { return which_ == Void; }
    998 
    999  bool isExtern() const { return isDouble() || isSigned(); }
   1000 
   1001  // Check if this is one of the valid types for a function argument.
   1002  bool isArgType() const { return isInt() || isFloat() || isDouble(); }
   1003 
   1004  // Check if this is one of the valid types for a function return value.
   1005  bool isReturnType() const {
   1006    return isSigned() || isFloat() || isDouble() || isVoid();
   1007  }
   1008 
   1009  // Check if this is one of the valid types for a global variable.
   1010  bool isGlobalVarType() const { return isArgType(); }
   1011 
   1012  // Check if this is one of the canonical vartype representations of a
   1013  // wasm::ValType, or is void. See Type::canonicalize().
   1014  bool isCanonical() const {
   1015    switch (which()) {
   1016      case Int:
   1017      case Float:
   1018      case Double:
   1019      case Void:
   1020        return true;
   1021      default:
   1022        return false;
   1023    }
   1024  }
   1025 
   1026  // Check if this is a canonical representation of a wasm::ValType.
   1027  bool isCanonicalValType() const { return !isVoid() && isCanonical(); }
   1028 
   1029  // Convert this canonical type to a wasm::ValType.
   1030  ValType canonicalToValType() const {
   1031    switch (which()) {
   1032      case Int:
   1033        return ValType::I32;
   1034      case Float:
   1035        return ValType::F32;
   1036      case Double:
   1037        return ValType::F64;
   1038      default:
   1039        MOZ_CRASH("Need canonical type");
   1040    }
   1041  }
   1042 
   1043  Maybe<ValType> canonicalToReturnType() const {
   1044    return isVoid() ? Nothing() : Some(canonicalToValType());
   1045  }
   1046 
   1047  // Convert this type to a wasm::TypeCode for use in a wasm
   1048  // block signature. This works for all types, including non-canonical
   1049  // ones. Consequently, the type isn't valid for subsequent asm.js
   1050  // validation; it's only valid for use in producing wasm.
   1051  TypeCode toWasmBlockSignatureType() const {
   1052    switch (which()) {
   1053      case Fixnum:
   1054      case Signed:
   1055      case Unsigned:
   1056      case Int:
   1057      case Intish:
   1058        return TypeCode::I32;
   1059 
   1060      case Float:
   1061      case MaybeFloat:
   1062      case Floatish:
   1063        return TypeCode::F32;
   1064 
   1065      case DoubleLit:
   1066      case Double:
   1067      case MaybeDouble:
   1068        return TypeCode::F64;
   1069 
   1070      case Void:
   1071        return TypeCode::BlockVoid;
   1072    }
   1073    MOZ_CRASH("Invalid Type");
   1074  }
   1075 
   1076  const char* toChars() const {
   1077    switch (which_) {
   1078      case Double:
   1079        return "double";
   1080      case DoubleLit:
   1081        return "doublelit";
   1082      case MaybeDouble:
   1083        return "double?";
   1084      case Float:
   1085        return "float";
   1086      case Floatish:
   1087        return "floatish";
   1088      case MaybeFloat:
   1089        return "float?";
   1090      case Fixnum:
   1091        return "fixnum";
   1092      case Int:
   1093        return "int";
   1094      case Signed:
   1095        return "signed";
   1096      case Unsigned:
   1097        return "unsigned";
   1098      case Intish:
   1099        return "intish";
   1100      case Void:
   1101        return "void";
   1102    }
   1103    MOZ_CRASH("Invalid Type");
   1104  }
   1105 };
   1106 
   1107 static const unsigned VALIDATION_LIFO_DEFAULT_CHUNK_SIZE = 4 * 1024;
   1108 
   1109 class MOZ_STACK_CLASS ModuleValidatorShared {
   1110 public:
   1111  struct Memory {
   1112    MemoryUsage usage;
   1113    uint64_t minLength;
   1114 
   1115    uint64_t minPages() const {
   1116      return DivideRoundingUp(minLength, StandardPageSizeBytes);
   1117    }
   1118 
   1119    Memory() = default;
   1120  };
   1121 
   1122  class Func {
   1123    TaggedParserAtomIndex name_;
   1124    uint32_t sigIndex_;
   1125    uint32_t firstUse_;
   1126    uint32_t funcDefIndex_;
   1127 
   1128    bool defined_;
   1129 
   1130    // Available when defined:
   1131    uint32_t srcBegin_;
   1132    uint32_t srcEnd_;
   1133    uint32_t line_;
   1134    Bytes bytes_;
   1135    Uint32Vector callSiteLineNums_;
   1136 
   1137   public:
   1138    Func(TaggedParserAtomIndex name, uint32_t sigIndex, uint32_t firstUse,
   1139         uint32_t funcDefIndex)
   1140        : name_(name),
   1141          sigIndex_(sigIndex),
   1142          firstUse_(firstUse),
   1143          funcDefIndex_(funcDefIndex),
   1144          defined_(false),
   1145          srcBegin_(0),
   1146          srcEnd_(0),
   1147          line_(0) {}
   1148 
   1149    TaggedParserAtomIndex name() const { return name_; }
   1150    uint32_t sigIndex() const { return sigIndex_; }
   1151    uint32_t firstUse() const { return firstUse_; }
   1152    bool defined() const { return defined_; }
   1153    uint32_t funcDefIndex() const { return funcDefIndex_; }
   1154 
   1155    void define(ParseNode* fn, uint32_t line, Bytes&& bytes,
   1156                Uint32Vector&& callSiteLineNums) {
   1157      MOZ_ASSERT(!defined_);
   1158      defined_ = true;
   1159      srcBegin_ = fn->pn_pos.begin;
   1160      srcEnd_ = fn->pn_pos.end;
   1161      line_ = line;
   1162      bytes_ = std::move(bytes);
   1163      callSiteLineNums_ = std::move(callSiteLineNums);
   1164    }
   1165 
   1166    uint32_t srcBegin() const {
   1167      MOZ_ASSERT(defined_);
   1168      return srcBegin_;
   1169    }
   1170    uint32_t srcEnd() const {
   1171      MOZ_ASSERT(defined_);
   1172      return srcEnd_;
   1173    }
   1174    uint32_t line() const {
   1175      MOZ_ASSERT(defined_);
   1176      return line_;
   1177    }
   1178    const Bytes& bytes() const {
   1179      MOZ_ASSERT(defined_);
   1180      return bytes_;
   1181    }
   1182    Uint32Vector& callSiteLineNums() {
   1183      MOZ_ASSERT(defined_);
   1184      return callSiteLineNums_;
   1185    }
   1186  };
   1187 
   1188  using ConstFuncVector = Vector<const Func*>;
   1189  using FuncVector = Vector<Func>;
   1190 
   1191  class Table {
   1192    uint32_t sigIndex_;
   1193    TaggedParserAtomIndex name_;
   1194    uint32_t firstUse_;
   1195    uint32_t mask_;
   1196    bool defined_;
   1197 
   1198   public:
   1199    Table(uint32_t sigIndex, TaggedParserAtomIndex name, uint32_t firstUse,
   1200          uint32_t mask)
   1201        : sigIndex_(sigIndex),
   1202          name_(name),
   1203          firstUse_(firstUse),
   1204          mask_(mask),
   1205          defined_(false) {}
   1206 
   1207    Table(Table&& rhs) = delete;
   1208 
   1209    uint32_t sigIndex() const { return sigIndex_; }
   1210    TaggedParserAtomIndex name() const { return name_; }
   1211    uint32_t firstUse() const { return firstUse_; }
   1212    unsigned mask() const { return mask_; }
   1213    bool defined() const { return defined_; }
   1214    void define() {
   1215      MOZ_ASSERT(!defined_);
   1216      defined_ = true;
   1217    }
   1218  };
   1219 
   1220  using TableVector = Vector<Table*>;
   1221 
   1222  class Global {
   1223   public:
   1224    enum Which {
   1225      Variable,
   1226      ConstantLiteral,
   1227      ConstantImport,
   1228      Function,
   1229      Table,
   1230      FFI,
   1231      ArrayView,
   1232      ArrayViewCtor,
   1233      MathBuiltinFunction
   1234    };
   1235 
   1236   private:
   1237    Which which_;
   1238    union U {
   1239      struct VarOrConst {
   1240        Type::Which type_;
   1241        unsigned index_;
   1242        NumLit literalValue_;
   1243 
   1244        VarOrConst(unsigned index, const NumLit& lit)
   1245            : type_(Type::lit(lit).which()),
   1246              index_(index),
   1247              literalValue_(lit)  // copies |lit|
   1248        {}
   1249 
   1250        VarOrConst(unsigned index, Type::Which which)
   1251            : type_(which), index_(index) {
   1252          // The |literalValue_| field remains unused and
   1253          // uninitialized for non-constant variables.
   1254        }
   1255 
   1256        explicit VarOrConst(double constant)
   1257            : type_(Type::Double),
   1258              literalValue_(NumLit::Double, DoubleValue(constant)) {
   1259          // The index_ field is unused and uninitialized for
   1260          // constant doubles.
   1261        }
   1262      } varOrConst;
   1263      uint32_t funcDefIndex_;
   1264      uint32_t tableIndex_;
   1265      uint32_t ffiIndex_;
   1266      Scalar::Type viewType_;
   1267      AsmJSMathBuiltinFunction mathBuiltinFunc_;
   1268 
   1269      // |varOrConst|, through |varOrConst.literalValue_|, has a
   1270      // non-trivial constructor and therefore MUST be placement-new'd
   1271      // into existence.
   1272      MOZ_PUSH_DISABLE_NONTRIVIAL_UNION_WARNINGS
   1273      U() : funcDefIndex_(0) {}
   1274      MOZ_POP_DISABLE_NONTRIVIAL_UNION_WARNINGS
   1275    } u;
   1276 
   1277    friend class ModuleValidatorShared;
   1278    template <typename Unit>
   1279    friend class ModuleValidator;
   1280    friend class js::LifoAlloc;
   1281 
   1282    explicit Global(Which which) : which_(which) {}
   1283 
   1284   public:
   1285    Which which() const { return which_; }
   1286    Type varOrConstType() const {
   1287      MOZ_ASSERT(which_ == Variable || which_ == ConstantLiteral ||
   1288                 which_ == ConstantImport);
   1289      return u.varOrConst.type_;
   1290    }
   1291    unsigned varOrConstIndex() const {
   1292      MOZ_ASSERT(which_ == Variable || which_ == ConstantImport);
   1293      return u.varOrConst.index_;
   1294    }
   1295    bool isConst() const {
   1296      return which_ == ConstantLiteral || which_ == ConstantImport;
   1297    }
   1298    NumLit constLiteralValue() const {
   1299      MOZ_ASSERT(which_ == ConstantLiteral);
   1300      return u.varOrConst.literalValue_;
   1301    }
   1302    uint32_t funcDefIndex() const {
   1303      MOZ_ASSERT(which_ == Function);
   1304      return u.funcDefIndex_;
   1305    }
   1306    uint32_t tableIndex() const {
   1307      MOZ_ASSERT(which_ == Table);
   1308      return u.tableIndex_;
   1309    }
   1310    unsigned ffiIndex() const {
   1311      MOZ_ASSERT(which_ == FFI);
   1312      return u.ffiIndex_;
   1313    }
   1314    Scalar::Type viewType() const {
   1315      MOZ_ASSERT(which_ == ArrayView || which_ == ArrayViewCtor);
   1316      return u.viewType_;
   1317    }
   1318    bool isMathFunction() const { return which_ == MathBuiltinFunction; }
   1319    AsmJSMathBuiltinFunction mathBuiltinFunction() const {
   1320      MOZ_ASSERT(which_ == MathBuiltinFunction);
   1321      return u.mathBuiltinFunc_;
   1322    }
   1323  };
   1324 
   1325  struct MathBuiltin {
   1326    enum Kind { Function, Constant };
   1327    Kind kind;
   1328 
   1329    union {
   1330      double cst;
   1331      AsmJSMathBuiltinFunction func;
   1332    } u;
   1333 
   1334    MathBuiltin() : kind(Kind(-1)), u{} {}
   1335    explicit MathBuiltin(double cst) : kind(Constant) { u.cst = cst; }
   1336    explicit MathBuiltin(AsmJSMathBuiltinFunction func) : kind(Function) {
   1337      u.func = func;
   1338    }
   1339  };
   1340 
   1341  struct ArrayView {
   1342    ArrayView(TaggedParserAtomIndex name, Scalar::Type type)
   1343        : name(name), type(type) {}
   1344 
   1345    TaggedParserAtomIndex name;
   1346    Scalar::Type type;
   1347  };
   1348 
   1349 protected:
   1350  class HashableSig {
   1351    uint32_t sigIndex_;
   1352    const TypeContext& types_;
   1353 
   1354   public:
   1355    HashableSig(uint32_t sigIndex, const TypeContext& types)
   1356        : sigIndex_(sigIndex), types_(types) {}
   1357    uint32_t sigIndex() const { return sigIndex_; }
   1358    const FuncType& funcType() const { return types_[sigIndex_].funcType(); }
   1359 
   1360    // Implement HashPolicy:
   1361    using Lookup = const FuncType&;
   1362    static HashNumber hash(Lookup l) { return l.hash(nullptr); }
   1363    static bool match(HashableSig lhs, Lookup rhs) {
   1364      return FuncType::strictlyEquals(lhs.funcType(), rhs);
   1365    }
   1366  };
   1367 
   1368  class NamedSig : public HashableSig {
   1369    TaggedParserAtomIndex name_;
   1370 
   1371   public:
   1372    NamedSig(TaggedParserAtomIndex name, uint32_t sigIndex,
   1373             const TypeContext& types)
   1374        : HashableSig(sigIndex, types), name_(name) {}
   1375    TaggedParserAtomIndex name() const { return name_; }
   1376 
   1377    // Implement HashPolicy:
   1378    struct Lookup {
   1379      TaggedParserAtomIndex name;
   1380      const FuncType& funcType;
   1381      Lookup(TaggedParserAtomIndex name, const FuncType& funcType)
   1382          : name(name), funcType(funcType) {}
   1383    };
   1384    static HashNumber hash(Lookup l) {
   1385      return HashGeneric(TaggedParserAtomIndexHasher::hash(l.name),
   1386                         l.funcType.hash(nullptr));
   1387    }
   1388    static bool match(NamedSig lhs, Lookup rhs) {
   1389      return lhs.name() == rhs.name &&
   1390             FuncType::strictlyEquals(lhs.funcType(), rhs.funcType);
   1391    }
   1392  };
   1393 
   1394  using SigSet = HashSet<HashableSig, HashableSig>;
   1395  using FuncImportMap = HashMap<NamedSig, uint32_t, NamedSig>;
   1396  using GlobalMap =
   1397      HashMap<TaggedParserAtomIndex, Global*, TaggedParserAtomIndexHasher>;
   1398  using MathNameMap =
   1399      HashMap<TaggedParserAtomIndex, MathBuiltin, TaggedParserAtomIndexHasher>;
   1400  using ArrayViewVector = Vector<ArrayView>;
   1401 
   1402 protected:
   1403  FrontendContext* fc_;
   1404  ParserAtomsTable& parserAtoms_;
   1405  FunctionNode* moduleFunctionNode_;
   1406  TaggedParserAtomIndex moduleFunctionName_;
   1407  TaggedParserAtomIndex globalArgumentName_;
   1408  TaggedParserAtomIndex importArgumentName_;
   1409  TaggedParserAtomIndex bufferArgumentName_;
   1410  MathNameMap standardLibraryMathNames_;
   1411 
   1412  // Validation-internal state:
   1413  LifoAlloc validationLifo_;
   1414  Memory memory_;
   1415  FuncVector funcDefs_;
   1416  TableVector tables_;
   1417  GlobalMap globalMap_;
   1418  SigSet sigSet_;
   1419  FuncImportMap funcImportMap_;
   1420  ArrayViewVector arrayViews_;
   1421 
   1422  // State used to build the AsmJSModule in finish():
   1423  CompilerEnvironment compilerEnv_;
   1424  MutableModuleMetadata moduleMeta_;
   1425  MutableCodeMetadata codeMeta_;
   1426  MutableCodeMetadataForAsmJSImpl codeMetaForAsmJS_;
   1427 
   1428  // Error reporting:
   1429  UniqueChars errorString_ = nullptr;
   1430  uint32_t errorOffset_ = UINT32_MAX;
   1431  bool errorOverRecursed_ = false;
   1432 
   1433 protected:
   1434  ModuleValidatorShared(FrontendContext* fc, ParserAtomsTable& parserAtoms,
   1435                        MutableModuleMetadata moduleMeta,
   1436                        MutableCodeMetadata codeMeta,
   1437                        FunctionNode* moduleFunctionNode)
   1438      : fc_(fc),
   1439        parserAtoms_(parserAtoms),
   1440        moduleFunctionNode_(moduleFunctionNode),
   1441        moduleFunctionName_(FunctionName(moduleFunctionNode)),
   1442        standardLibraryMathNames_(fc),
   1443        validationLifo_(VALIDATION_LIFO_DEFAULT_CHUNK_SIZE, js::MallocArena),
   1444        funcDefs_(fc),
   1445        tables_(fc),
   1446        globalMap_(fc),
   1447        sigSet_(fc),
   1448        funcImportMap_(fc),
   1449        arrayViews_(fc),
   1450        compilerEnv_(CompileMode::Once, Tier::Optimized, DebugEnabled::False),
   1451        moduleMeta_(moduleMeta),
   1452        codeMeta_(codeMeta) {
   1453    compilerEnv_.computeParameters();
   1454    memory_.minLength = RoundUpToNextValidAsmJSHeapLength(0);
   1455  }
   1456 
   1457 protected:
   1458  [[nodiscard]] bool addStandardLibraryMathInfo() {
   1459    static constexpr struct {
   1460      const char* name;
   1461      AsmJSMathBuiltinFunction func;
   1462    } functions[] = {
   1463        {"sin", AsmJSMathBuiltin_sin},       {"cos", AsmJSMathBuiltin_cos},
   1464        {"tan", AsmJSMathBuiltin_tan},       {"asin", AsmJSMathBuiltin_asin},
   1465        {"acos", AsmJSMathBuiltin_acos},     {"atan", AsmJSMathBuiltin_atan},
   1466        {"ceil", AsmJSMathBuiltin_ceil},     {"floor", AsmJSMathBuiltin_floor},
   1467        {"exp", AsmJSMathBuiltin_exp},       {"log", AsmJSMathBuiltin_log},
   1468        {"pow", AsmJSMathBuiltin_pow},       {"sqrt", AsmJSMathBuiltin_sqrt},
   1469        {"abs", AsmJSMathBuiltin_abs},       {"atan2", AsmJSMathBuiltin_atan2},
   1470        {"imul", AsmJSMathBuiltin_imul},     {"clz32", AsmJSMathBuiltin_clz32},
   1471        {"fround", AsmJSMathBuiltin_fround}, {"min", AsmJSMathBuiltin_min},
   1472        {"max", AsmJSMathBuiltin_max},
   1473    };
   1474 
   1475    auto AddMathFunction = [this](const char* name,
   1476                                  AsmJSMathBuiltinFunction func) {
   1477      auto atom = parserAtoms_.internAscii(fc_, name, strlen(name));
   1478      if (!atom) {
   1479        return false;
   1480      }
   1481      MathBuiltin builtin(func);
   1482      return this->standardLibraryMathNames_.putNew(atom, builtin);
   1483    };
   1484 
   1485    for (const auto& info : functions) {
   1486      if (!AddMathFunction(info.name, info.func)) {
   1487        return false;
   1488      }
   1489    }
   1490 
   1491    static constexpr struct {
   1492      const char* name;
   1493      double value;
   1494    } constants[] = {
   1495        {"E", M_E},
   1496        {"LN10", M_LN10},
   1497        {"LN2", M_LN2},
   1498        {"LOG2E", M_LOG2E},
   1499        {"LOG10E", M_LOG10E},
   1500        {"PI", M_PI},
   1501        {"SQRT1_2", M_SQRT1_2},
   1502        {"SQRT2", M_SQRT2},
   1503    };
   1504 
   1505    auto AddMathConstant = [this](const char* name, double cst) {
   1506      auto atom = parserAtoms_.internAscii(fc_, name, strlen(name));
   1507      if (!atom) {
   1508        return false;
   1509      }
   1510      MathBuiltin builtin(cst);
   1511      return this->standardLibraryMathNames_.putNew(atom, builtin);
   1512    };
   1513 
   1514    for (const auto& info : constants) {
   1515      if (!AddMathConstant(info.name, info.value)) {
   1516        return false;
   1517      }
   1518    }
   1519 
   1520    return true;
   1521  }
   1522 
   1523 public:
   1524  FrontendContext* fc() const { return fc_; }
   1525  TaggedParserAtomIndex moduleFunctionName() const {
   1526    return moduleFunctionName_;
   1527  }
   1528  TaggedParserAtomIndex globalArgumentName() const {
   1529    return globalArgumentName_;
   1530  }
   1531  TaggedParserAtomIndex importArgumentName() const {
   1532    return importArgumentName_;
   1533  }
   1534  TaggedParserAtomIndex bufferArgumentName() const {
   1535    return bufferArgumentName_;
   1536  }
   1537  const CodeMetadata* codeMeta() { return codeMeta_; }
   1538  const ModuleMetadata* moduleMeta() { return moduleMeta_; }
   1539 
   1540  void initModuleFunctionName(TaggedParserAtomIndex name) {
   1541    MOZ_ASSERT(!moduleFunctionName_);
   1542    moduleFunctionName_ = name;
   1543  }
   1544  [[nodiscard]] bool initGlobalArgumentName(TaggedParserAtomIndex n) {
   1545    globalArgumentName_ = n;
   1546    if (n) {
   1547      codeMetaForAsmJS_->globalArgumentName =
   1548          parserAtoms_.toNewUTF8CharsZ(fc_, n);
   1549      if (!codeMetaForAsmJS_->globalArgumentName) {
   1550        return false;
   1551      }
   1552    }
   1553    return true;
   1554  }
   1555  [[nodiscard]] bool initImportArgumentName(TaggedParserAtomIndex n) {
   1556    importArgumentName_ = n;
   1557    if (n) {
   1558      codeMetaForAsmJS_->importArgumentName =
   1559          parserAtoms_.toNewUTF8CharsZ(fc_, n);
   1560      if (!codeMetaForAsmJS_->importArgumentName) {
   1561        return false;
   1562      }
   1563    }
   1564    return true;
   1565  }
   1566  [[nodiscard]] bool initBufferArgumentName(TaggedParserAtomIndex n) {
   1567    bufferArgumentName_ = n;
   1568    if (n) {
   1569      codeMetaForAsmJS_->bufferArgumentName =
   1570          parserAtoms_.toNewUTF8CharsZ(fc_, n);
   1571      if (!codeMetaForAsmJS_->bufferArgumentName) {
   1572        return false;
   1573      }
   1574    }
   1575    return true;
   1576  }
   1577  bool addGlobalVarInit(TaggedParserAtomIndex var, const NumLit& lit, Type type,
   1578                        bool isConst) {
   1579    MOZ_ASSERT(type.isGlobalVarType());
   1580    MOZ_ASSERT(type == Type::canonicalize(Type::lit(lit)));
   1581 
   1582    uint32_t index = codeMeta_->globals.length();
   1583    if (!codeMeta_->globals.emplaceBack(type.canonicalToValType(), !isConst,
   1584                                        index, ModuleKind::AsmJS)) {
   1585      return false;
   1586    }
   1587 
   1588    Global::Which which = isConst ? Global::ConstantLiteral : Global::Variable;
   1589    Global* global = validationLifo_.new_<Global>(which);
   1590    if (!global) {
   1591      return false;
   1592    }
   1593    if (isConst) {
   1594      new (&global->u.varOrConst) Global::U::VarOrConst(index, lit);
   1595    } else {
   1596      new (&global->u.varOrConst) Global::U::VarOrConst(index, type.which());
   1597    }
   1598    if (!globalMap_.putNew(var, global)) {
   1599      return false;
   1600    }
   1601 
   1602    AsmJSGlobal g(AsmJSGlobal::Variable, nullptr);
   1603    g.pod.u.var.initKind_ = AsmJSGlobal::InitConstant;
   1604    g.pod.u.var.u.val_ = lit.value();
   1605    return codeMetaForAsmJS_->asmJSGlobals.append(std::move(g));
   1606  }
   1607  bool addGlobalVarImport(TaggedParserAtomIndex var,
   1608                          TaggedParserAtomIndex field, Type type,
   1609                          bool isConst) {
   1610    MOZ_ASSERT(type.isGlobalVarType());
   1611 
   1612    UniqueChars fieldChars = parserAtoms_.toNewUTF8CharsZ(fc_, field);
   1613    if (!fieldChars) {
   1614      return false;
   1615    }
   1616 
   1617    uint32_t index = codeMeta_->globals.length();
   1618    ValType valType = type.canonicalToValType();
   1619    if (!codeMeta_->globals.emplaceBack(valType, !isConst, index,
   1620                                        ModuleKind::AsmJS)) {
   1621      return false;
   1622    }
   1623 
   1624    Global::Which which = isConst ? Global::ConstantImport : Global::Variable;
   1625    Global* global = validationLifo_.new_<Global>(which);
   1626    if (!global) {
   1627      return false;
   1628    }
   1629    new (&global->u.varOrConst) Global::U::VarOrConst(index, type.which());
   1630    if (!globalMap_.putNew(var, global)) {
   1631      return false;
   1632    }
   1633 
   1634    AsmJSGlobal g(AsmJSGlobal::Variable, std::move(fieldChars));
   1635    g.pod.u.var.initKind_ = AsmJSGlobal::InitImport;
   1636    g.pod.u.var.u.importValType_ = valType.packed();
   1637    return codeMetaForAsmJS_->asmJSGlobals.append(std::move(g));
   1638  }
   1639  bool addArrayView(TaggedParserAtomIndex var, Scalar::Type vt,
   1640                    TaggedParserAtomIndex maybeField) {
   1641    UniqueChars fieldChars;
   1642    if (maybeField) {
   1643      fieldChars = parserAtoms_.toNewUTF8CharsZ(fc_, maybeField);
   1644      if (!fieldChars) {
   1645        return false;
   1646      }
   1647    }
   1648 
   1649    if (!arrayViews_.append(ArrayView(var, vt))) {
   1650      return false;
   1651    }
   1652 
   1653    Global* global = validationLifo_.new_<Global>(Global::ArrayView);
   1654    if (!global) {
   1655      return false;
   1656    }
   1657    new (&global->u.viewType_) Scalar::Type(vt);
   1658    if (!globalMap_.putNew(var, global)) {
   1659      return false;
   1660    }
   1661 
   1662    AsmJSGlobal g(AsmJSGlobal::ArrayView, std::move(fieldChars));
   1663    g.pod.u.viewType_ = vt;
   1664    return codeMetaForAsmJS_->asmJSGlobals.append(std::move(g));
   1665  }
   1666  bool addMathBuiltinFunction(TaggedParserAtomIndex var,
   1667                              AsmJSMathBuiltinFunction func,
   1668                              TaggedParserAtomIndex field) {
   1669    UniqueChars fieldChars = parserAtoms_.toNewUTF8CharsZ(fc_, field);
   1670    if (!fieldChars) {
   1671      return false;
   1672    }
   1673 
   1674    Global* global = validationLifo_.new_<Global>(Global::MathBuiltinFunction);
   1675    if (!global) {
   1676      return false;
   1677    }
   1678    new (&global->u.mathBuiltinFunc_) AsmJSMathBuiltinFunction(func);
   1679    if (!globalMap_.putNew(var, global)) {
   1680      return false;
   1681    }
   1682 
   1683    AsmJSGlobal g(AsmJSGlobal::MathBuiltinFunction, std::move(fieldChars));
   1684    g.pod.u.mathBuiltinFunc_ = func;
   1685    return codeMetaForAsmJS_->asmJSGlobals.append(std::move(g));
   1686  }
   1687 
   1688 private:
   1689  bool addGlobalDoubleConstant(TaggedParserAtomIndex var, double constant) {
   1690    Global* global = validationLifo_.new_<Global>(Global::ConstantLiteral);
   1691    if (!global) {
   1692      return false;
   1693    }
   1694    new (&global->u.varOrConst) Global::U::VarOrConst(constant);
   1695    return globalMap_.putNew(var, global);
   1696  }
   1697 
   1698 public:
   1699  bool addMathBuiltinConstant(TaggedParserAtomIndex var, double constant,
   1700                              TaggedParserAtomIndex field) {
   1701    UniqueChars fieldChars = parserAtoms_.toNewUTF8CharsZ(fc_, field);
   1702    if (!fieldChars) {
   1703      return false;
   1704    }
   1705 
   1706    if (!addGlobalDoubleConstant(var, constant)) {
   1707      return false;
   1708    }
   1709 
   1710    AsmJSGlobal g(AsmJSGlobal::Constant, std::move(fieldChars));
   1711    g.pod.u.constant.value_ = constant;
   1712    g.pod.u.constant.kind_ = AsmJSGlobal::MathConstant;
   1713    return codeMetaForAsmJS_->asmJSGlobals.append(std::move(g));
   1714  }
   1715  bool addGlobalConstant(TaggedParserAtomIndex var, double constant,
   1716                         TaggedParserAtomIndex field) {
   1717    UniqueChars fieldChars = parserAtoms_.toNewUTF8CharsZ(fc_, field);
   1718    if (!fieldChars) {
   1719      return false;
   1720    }
   1721 
   1722    if (!addGlobalDoubleConstant(var, constant)) {
   1723      return false;
   1724    }
   1725 
   1726    AsmJSGlobal g(AsmJSGlobal::Constant, std::move(fieldChars));
   1727    g.pod.u.constant.value_ = constant;
   1728    g.pod.u.constant.kind_ = AsmJSGlobal::GlobalConstant;
   1729    return codeMetaForAsmJS_->asmJSGlobals.append(std::move(g));
   1730  }
   1731  bool addArrayViewCtor(TaggedParserAtomIndex var, Scalar::Type vt,
   1732                        TaggedParserAtomIndex field) {
   1733    UniqueChars fieldChars = parserAtoms_.toNewUTF8CharsZ(fc_, field);
   1734    if (!fieldChars) {
   1735      return false;
   1736    }
   1737 
   1738    Global* global = validationLifo_.new_<Global>(Global::ArrayViewCtor);
   1739    if (!global) {
   1740      return false;
   1741    }
   1742    new (&global->u.viewType_) Scalar::Type(vt);
   1743    if (!globalMap_.putNew(var, global)) {
   1744      return false;
   1745    }
   1746 
   1747    AsmJSGlobal g(AsmJSGlobal::ArrayViewCtor, std::move(fieldChars));
   1748    g.pod.u.viewType_ = vt;
   1749    return codeMetaForAsmJS_->asmJSGlobals.append(std::move(g));
   1750  }
   1751  bool addFFI(TaggedParserAtomIndex var, TaggedParserAtomIndex field) {
   1752    UniqueChars fieldChars = parserAtoms_.toNewUTF8CharsZ(fc_, field);
   1753    if (!fieldChars) {
   1754      return false;
   1755    }
   1756 
   1757    if (codeMetaForAsmJS_->numFFIs == UINT32_MAX) {
   1758      return false;
   1759    }
   1760    uint32_t ffiIndex = codeMetaForAsmJS_->numFFIs++;
   1761 
   1762    Global* global = validationLifo_.new_<Global>(Global::FFI);
   1763    if (!global) {
   1764      return false;
   1765    }
   1766    new (&global->u.ffiIndex_) uint32_t(ffiIndex);
   1767    if (!globalMap_.putNew(var, global)) {
   1768      return false;
   1769    }
   1770 
   1771    AsmJSGlobal g(AsmJSGlobal::FFI, std::move(fieldChars));
   1772    g.pod.u.ffiIndex_ = ffiIndex;
   1773    return codeMetaForAsmJS_->asmJSGlobals.append(std::move(g));
   1774  }
   1775  bool addExportField(const Func& func, TaggedParserAtomIndex maybeField) {
   1776    // Record the field name of this export.
   1777    CacheableName fieldName;
   1778    if (maybeField) {
   1779      UniqueChars fieldChars = parserAtoms_.toNewUTF8CharsZ(fc_, maybeField);
   1780      if (!fieldChars) {
   1781        return false;
   1782      }
   1783      fieldName = CacheableName::fromUTF8Chars(std::move(fieldChars));
   1784    }
   1785 
   1786    // Declare which function is exported which gives us an index into the
   1787    // module ExportVector.
   1788    uint32_t funcIndex = funcImportMap_.count() + func.funcDefIndex();
   1789    if (!moduleMeta_->exports.emplaceBack(std::move(fieldName), funcIndex,
   1790                                          DefinitionKind::Function)) {
   1791      return false;
   1792    }
   1793 
   1794    // The exported function might have already been exported in which case
   1795    // the index will refer into the range of AsmJSExports.
   1796    return codeMetaForAsmJS_->asmJSExports.emplaceBack(
   1797        funcIndex, func.srcBegin() - codeMetaForAsmJS_->srcStart,
   1798        func.srcEnd() - codeMetaForAsmJS_->srcStart);
   1799  }
   1800 
   1801  bool defineFuncPtrTable(uint32_t tableIndex, Uint32Vector&& elems) {
   1802    Table& table = *tables_[tableIndex];
   1803    if (table.defined()) {
   1804      return false;
   1805    }
   1806 
   1807    table.define();
   1808 
   1809    for (uint32_t& index : elems) {
   1810      index += funcImportMap_.count();
   1811    }
   1812 
   1813    ModuleElemSegment seg = ModuleElemSegment();
   1814    seg.elemType = RefType::func();
   1815    seg.tableIndex = tableIndex;
   1816    seg.offsetIfActive = Some(InitExpr(LitVal(uint32_t(0))));
   1817    seg.encoding = ModuleElemSegment::Encoding::Indices;
   1818    seg.elemIndices = std::move(elems);
   1819    bool ok = codeMeta_->elemSegmentTypes.append(seg.elemType) &&
   1820              moduleMeta_->elemSegments.append(std::move(seg));
   1821    MOZ_ASSERT_IF(ok, codeMeta_->elemSegmentTypes.length() ==
   1822                          moduleMeta_->elemSegments.length());
   1823    return ok;
   1824  }
   1825 
   1826  bool tryConstantAccess(uint64_t start, uint64_t width) {
   1827    MOZ_ASSERT(UINT64_MAX - start > width);
   1828    uint64_t len = start + width;
   1829    if (len > uint64_t(INT32_MAX) + 1) {
   1830      return false;
   1831    }
   1832    len = RoundUpToNextValidAsmJSHeapLength(len);
   1833    if (len > memory_.minLength) {
   1834      memory_.minLength = len;
   1835    }
   1836    return true;
   1837  }
   1838 
   1839  // Error handling.
   1840  bool hasAlreadyFailed() const { return !!errorString_; }
   1841 
   1842  bool failOffset(uint32_t offset, const char* str) {
   1843    MOZ_ASSERT(!hasAlreadyFailed());
   1844    MOZ_ASSERT(errorOffset_ == UINT32_MAX);
   1845    MOZ_ASSERT(str);
   1846    errorOffset_ = offset;
   1847    errorString_ = DuplicateString(str);
   1848    return false;
   1849  }
   1850 
   1851  bool fail(ParseNode* pn, const char* str) {
   1852    return failOffset(pn->pn_pos.begin, str);
   1853  }
   1854 
   1855  bool failfVAOffset(uint32_t offset, const char* fmt, va_list ap)
   1856      MOZ_FORMAT_PRINTF(3, 0) {
   1857    MOZ_ASSERT(!hasAlreadyFailed());
   1858    MOZ_ASSERT(errorOffset_ == UINT32_MAX);
   1859    MOZ_ASSERT(fmt);
   1860    errorOffset_ = offset;
   1861    errorString_ = JS_vsmprintf(fmt, ap);
   1862    return false;
   1863  }
   1864 
   1865  bool failfOffset(uint32_t offset, const char* fmt, ...)
   1866      MOZ_FORMAT_PRINTF(3, 4) {
   1867    va_list ap;
   1868    va_start(ap, fmt);
   1869    failfVAOffset(offset, fmt, ap);
   1870    va_end(ap);
   1871    return false;
   1872  }
   1873 
   1874  bool failf(ParseNode* pn, const char* fmt, ...) MOZ_FORMAT_PRINTF(3, 4) {
   1875    va_list ap;
   1876    va_start(ap, fmt);
   1877    failfVAOffset(pn->pn_pos.begin, fmt, ap);
   1878    va_end(ap);
   1879    return false;
   1880  }
   1881 
   1882  bool failNameOffset(uint32_t offset, const char* fmt,
   1883                      TaggedParserAtomIndex name) {
   1884    // This function is invoked without the caller properly rooting its locals.
   1885    if (UniqueChars bytes = parserAtoms_.toPrintableString(name)) {
   1886      failfOffset(offset, fmt, bytes.get());
   1887    } else {
   1888      ReportOutOfMemory(fc_);
   1889    }
   1890    return false;
   1891  }
   1892 
   1893  bool failName(ParseNode* pn, const char* fmt, TaggedParserAtomIndex name) {
   1894    return failNameOffset(pn->pn_pos.begin, fmt, name);
   1895  }
   1896 
   1897  bool failOverRecursed() {
   1898    errorOverRecursed_ = true;
   1899    return false;
   1900  }
   1901 
   1902  unsigned numArrayViews() const { return arrayViews_.length(); }
   1903  const ArrayView& arrayView(unsigned i) const { return arrayViews_[i]; }
   1904  unsigned numFuncDefs() const { return funcDefs_.length(); }
   1905  const Func& funcDef(unsigned i) const { return funcDefs_[i]; }
   1906  unsigned numFuncPtrTables() const { return tables_.length(); }
   1907  Table& table(unsigned i) const { return *tables_[i]; }
   1908 
   1909  const Global* lookupGlobal(TaggedParserAtomIndex name) const {
   1910    if (GlobalMap::Ptr p = globalMap_.lookup(name)) {
   1911      return p->value();
   1912    }
   1913    return nullptr;
   1914  }
   1915 
   1916  Func* lookupFuncDef(TaggedParserAtomIndex name) {
   1917    if (GlobalMap::Ptr p = globalMap_.lookup(name)) {
   1918      Global* value = p->value();
   1919      if (value->which() == Global::Function) {
   1920        return &funcDefs_[value->funcDefIndex()];
   1921      }
   1922    }
   1923    return nullptr;
   1924  }
   1925 
   1926  bool lookupStandardLibraryMathName(TaggedParserAtomIndex name,
   1927                                     MathBuiltin* mathBuiltin) const {
   1928    if (MathNameMap::Ptr p = standardLibraryMathNames_.lookup(name)) {
   1929      *mathBuiltin = p->value();
   1930      return true;
   1931    }
   1932    return false;
   1933  }
   1934 
   1935  bool startFunctionBodies() {
   1936    if (!arrayViews_.empty()) {
   1937      memory_.usage = MemoryUsage::Unshared;
   1938    } else {
   1939      memory_.usage = MemoryUsage::None;
   1940    }
   1941    return true;
   1942  }
   1943 };
   1944 
   1945 // The ModuleValidator encapsulates the entire validation of an asm.js module.
   1946 // Its lifetime goes from the validation of the top components of an asm.js
   1947 // module (all the globals), the emission of bytecode for all the functions in
   1948 // the module and the validation of function's pointer tables. It also finishes
   1949 // the compilation of all the module's stubs.
   1950 template <typename Unit>
   1951 class MOZ_STACK_CLASS ModuleValidator : public ModuleValidatorShared {
   1952 private:
   1953  AsmJSParser<Unit>& parser_;
   1954 
   1955 public:
   1956  ModuleValidator(FrontendContext* fc, ParserAtomsTable& parserAtoms,
   1957                  MutableModuleMetadata moduleMeta,
   1958                  MutableCodeMetadata codeMeta, AsmJSParser<Unit>& parser,
   1959                  FunctionNode* moduleFunctionNode)
   1960      : ModuleValidatorShared(fc, parserAtoms, moduleMeta, codeMeta,
   1961                              moduleFunctionNode),
   1962        parser_(parser) {}
   1963 
   1964  ~ModuleValidator() {
   1965    if (errorString_) {
   1966      MOZ_ASSERT(errorOffset_ != UINT32_MAX);
   1967      typeFailure(errorOffset_, errorString_.get());
   1968    }
   1969    if (errorOverRecursed_) {
   1970      ReportOverRecursed(fc_);
   1971    }
   1972  }
   1973 
   1974 private:
   1975  // Helpers:
   1976  bool newSig(FuncType&& sig, uint32_t* sigIndex) {
   1977    if (codeMeta_->types->length() >= MaxTypes) {
   1978      return failCurrentOffset("too many signatures");
   1979    }
   1980 
   1981    *sigIndex = codeMeta_->types->length();
   1982    return codeMeta_->types->addType(std::move(sig));
   1983  }
   1984  bool declareSig(FuncType&& sig, uint32_t* sigIndex) {
   1985    SigSet::AddPtr p = sigSet_.lookupForAdd(sig);
   1986    if (p) {
   1987      *sigIndex = p->sigIndex();
   1988      MOZ_ASSERT(FuncType::strictlyEquals(
   1989          codeMeta_->types->type(*sigIndex).funcType(), sig));
   1990      return true;
   1991    }
   1992 
   1993    return newSig(std::move(sig), sigIndex) &&
   1994           sigSet_.add(p, HashableSig(*sigIndex, *codeMeta_->types));
   1995  }
   1996 
   1997 private:
   1998  void typeFailure(uint32_t offset, ...) {
   1999    va_list args;
   2000    va_start(args, offset);
   2001 
   2002    auto& ts = tokenStream();
   2003    ErrorMetadata metadata;
   2004    if (ts.computeErrorMetadata(&metadata, AsVariant(offset))) {
   2005      if (ts.anyCharsAccess().options().throwOnAsmJSValidationFailure()) {
   2006        ReportCompileErrorLatin1VA(fc_, std::move(metadata), nullptr,
   2007                                   JSMSG_USE_ASM_TYPE_FAIL, &args);
   2008      } else {
   2009        // asm.js type failure is indicated by calling one of the fail*
   2010        // functions below.  These functions always return false to
   2011        // halt asm.js parsing.  Whether normal parsing is attempted as
   2012        // fallback, depends whether an exception is also set.
   2013        //
   2014        // If warning succeeds, no exception is set.  If warning fails,
   2015        // an exception is set and execution will halt.  Thus it's safe
   2016        // and correct to ignore the return value here.
   2017        (void)ts.compileWarning(std::move(metadata), nullptr,
   2018                                JSMSG_USE_ASM_TYPE_FAIL, &args);
   2019      }
   2020    }
   2021 
   2022    va_end(args);
   2023  }
   2024 
   2025 public:
   2026  bool init() {
   2027    codeMetaForAsmJS_ = js_new<CodeMetadataForAsmJSImpl>();
   2028    if (!codeMetaForAsmJS_) {
   2029      ReportOutOfMemory(fc_);
   2030      return false;
   2031    }
   2032 
   2033    codeMetaForAsmJS_->toStringStart =
   2034        moduleFunctionNode_->funbox()->extent().toStringStart;
   2035    codeMetaForAsmJS_->srcStart = moduleFunctionNode_->body()->pn_pos.begin;
   2036    codeMetaForAsmJS_->strict = parser_.pc_->sc()->strict() &&
   2037                                !parser_.pc_->sc()->hasExplicitUseStrict();
   2038    codeMetaForAsmJS_->alwaysUseFdlibm = parser_.options().alwaysUseFdlibm();
   2039    codeMetaForAsmJS_->source = do_AddRef(parser_.ss);
   2040 
   2041    return addStandardLibraryMathInfo();
   2042  }
   2043 
   2044  AsmJSParser<Unit>& parser() const { return parser_; }
   2045 
   2046  auto& tokenStream() const { return parser_.tokenStream; }
   2047 
   2048  bool alwaysUseFdlibm() const { return codeMetaForAsmJS_->alwaysUseFdlibm; }
   2049 
   2050 public:
   2051  bool addFuncDef(TaggedParserAtomIndex name, uint32_t firstUse, FuncType&& sig,
   2052                  Func** func) {
   2053    uint32_t sigIndex;
   2054    if (!declareSig(std::move(sig), &sigIndex)) {
   2055      return false;
   2056    }
   2057 
   2058    uint32_t funcDefIndex = funcDefs_.length();
   2059    if (funcDefIndex >= MaxFuncs) {
   2060      return failCurrentOffset("too many functions");
   2061    }
   2062 
   2063    Global* global = validationLifo_.new_<Global>(Global::Function);
   2064    if (!global) {
   2065      return false;
   2066    }
   2067    new (&global->u.funcDefIndex_) uint32_t(funcDefIndex);
   2068    if (!globalMap_.putNew(name, global)) {
   2069      return false;
   2070    }
   2071    if (!funcDefs_.emplaceBack(name, sigIndex, firstUse, funcDefIndex)) {
   2072      return false;
   2073    }
   2074    *func = &funcDefs_.back();
   2075    return true;
   2076  }
   2077  bool declareFuncPtrTable(FuncType&& sig, TaggedParserAtomIndex name,
   2078                           uint32_t firstUse, uint32_t mask,
   2079                           uint32_t* tableIndex) {
   2080    if (mask > MaxTableElemsRuntime) {
   2081      return failCurrentOffset("function pointer table too big");
   2082    }
   2083 
   2084    MOZ_ASSERT(codeMeta_->tables.length() == tables_.length());
   2085    *tableIndex = codeMeta_->tables.length();
   2086 
   2087    uint32_t sigIndex;
   2088    if (!newSig(std::move(sig), &sigIndex)) {
   2089      return false;
   2090    }
   2091 
   2092    MOZ_ASSERT(sigIndex >= codeMeta_->asmJSSigToTableIndex.length());
   2093    if (!codeMeta_->asmJSSigToTableIndex.resize(sigIndex + 1)) {
   2094      return false;
   2095    }
   2096 
   2097    Limits limits =
   2098        Limits(mask + 1, Nothing(), Shareable::False, PageSize::Standard);
   2099    codeMeta_->asmJSSigToTableIndex[sigIndex] = codeMeta_->tables.length();
   2100    if (!codeMeta_->tables.emplaceBack(limits, RefType::func(),
   2101                                       /* initExpr */ Nothing(),
   2102                                       /*isAsmJS*/ true)) {
   2103      return false;
   2104    }
   2105 
   2106    Global* global = validationLifo_.new_<Global>(Global::Table);
   2107    if (!global) {
   2108      return false;
   2109    }
   2110 
   2111    new (&global->u.tableIndex_) uint32_t(*tableIndex);
   2112    if (!globalMap_.putNew(name, global)) {
   2113      return false;
   2114    }
   2115 
   2116    Table* t = validationLifo_.new_<Table>(sigIndex, name, firstUse, mask);
   2117    return t && tables_.append(t);
   2118  }
   2119  bool declareImport(TaggedParserAtomIndex name, FuncType&& sig,
   2120                     unsigned ffiIndex, uint32_t* importIndex) {
   2121    FuncImportMap::AddPtr p =
   2122        funcImportMap_.lookupForAdd(NamedSig::Lookup(name, sig));
   2123    if (p) {
   2124      *importIndex = p->value();
   2125      return true;
   2126    }
   2127 
   2128    *importIndex = funcImportMap_.count();
   2129    MOZ_ASSERT(*importIndex == codeMetaForAsmJS_->asmJSImports.length());
   2130 
   2131    if (*importIndex >= MaxImports) {
   2132      return failCurrentOffset("too many imports");
   2133    }
   2134 
   2135    if (!codeMetaForAsmJS_->asmJSImports.emplaceBack(ffiIndex)) {
   2136      return false;
   2137    }
   2138 
   2139    uint32_t sigIndex;
   2140    if (!declareSig(std::move(sig), &sigIndex)) {
   2141      return false;
   2142    }
   2143 
   2144    return funcImportMap_.add(p, NamedSig(name, sigIndex, *codeMeta_->types),
   2145                              *importIndex);
   2146  }
   2147 
   2148  // Error handling.
   2149  bool failCurrentOffset(const char* str) {
   2150    return failOffset(tokenStream().anyCharsAccess().currentToken().pos.begin,
   2151                      str);
   2152  }
   2153 
   2154  SharedModule finish() {
   2155    MOZ_ASSERT(codeMeta_->numMemories() == 0);
   2156    if (memory_.usage != MemoryUsage::None) {
   2157      Limits limits;
   2158      limits.shared = memory_.usage == MemoryUsage::Shared ? Shareable::True
   2159                                                           : Shareable::False;
   2160      limits.initial = memory_.minPages();
   2161      limits.maximum = Nothing();
   2162      limits.addressType = AddressType::I32;
   2163      limits.pageSize = PageSize::Standard;
   2164      if (!codeMeta_->memories.append(MemoryDesc(limits))) {
   2165        return nullptr;
   2166      }
   2167    }
   2168    MOZ_ASSERT(codeMeta_->funcs.empty());
   2169    if (!codeMeta_->funcs.resize(funcImportMap_.count() + funcDefs_.length())) {
   2170      return nullptr;
   2171    }
   2172    for (FuncImportMap::Range r = funcImportMap_.all(); !r.empty();
   2173         r.popFront()) {
   2174      uint32_t funcIndex = r.front().value();
   2175      uint32_t funcTypeIndex = r.front().key().sigIndex();
   2176      codeMeta_->funcs[funcIndex] = FuncDesc(funcTypeIndex);
   2177    }
   2178    for (const Func& func : funcDefs_) {
   2179      uint32_t funcIndex = funcImportMap_.count() + func.funcDefIndex();
   2180      uint32_t funcTypeIndex = func.sigIndex();
   2181      codeMeta_->funcs[funcIndex] = FuncDesc(funcTypeIndex);
   2182    }
   2183    for (const Export& exp : moduleMeta_->exports) {
   2184      if (exp.kind() != DefinitionKind::Function) {
   2185        continue;
   2186      }
   2187      uint32_t funcIndex = exp.funcIndex();
   2188      codeMeta_->funcs[funcIndex].declareFuncExported(/* eager */ true,
   2189                                                      /* canRefFunc */ false);
   2190    }
   2191 
   2192    codeMeta_->numFuncImports = funcImportMap_.count();
   2193 
   2194    // All globals (inits and imports) are imports from Wasm point of view.
   2195    codeMeta_->numGlobalImports = codeMeta_->globals.length();
   2196 
   2197    MOZ_ASSERT(codeMetaForAsmJS_->asmJSFuncNames.empty());
   2198    if (!codeMetaForAsmJS_->asmJSFuncNames.resize(funcImportMap_.count())) {
   2199      return nullptr;
   2200    }
   2201    for (const Func& func : funcDefs_) {
   2202      CacheableChars funcName = parserAtoms_.toNewUTF8CharsZ(fc_, func.name());
   2203      if (!funcName ||
   2204          !codeMetaForAsmJS_->asmJSFuncNames.emplaceBack(std::move(funcName))) {
   2205        return nullptr;
   2206      }
   2207    }
   2208 
   2209    uint32_t endBeforeCurly =
   2210        tokenStream().anyCharsAccess().currentToken().pos.end;
   2211    codeMetaForAsmJS_->srcLength = endBeforeCurly - codeMetaForAsmJS_->srcStart;
   2212 
   2213    TokenPos pos;
   2214    MOZ_ALWAYS_TRUE(
   2215        tokenStream().peekTokenPos(&pos, TokenStreamShared::SlashIsRegExp));
   2216    uint32_t endAfterCurly = pos.end;
   2217    codeMetaForAsmJS_->srcLengthWithRightBrace =
   2218        endAfterCurly - codeMetaForAsmJS_->srcStart;
   2219 
   2220    uint32_t codeSectionSize = 0;
   2221    for (const Func& func : funcDefs_) {
   2222      codeSectionSize += func.bytes().length();
   2223    }
   2224 
   2225    codeMeta_->codeSectionRange = Some(BytecodeRange(0, codeSectionSize));
   2226 
   2227    // asm.js does not have any wasm bytecode to save; view-source is
   2228    // provided through the ScriptSource.
   2229    BytecodeBufferOrSource bytecode;
   2230 
   2231    if (!moduleMeta_->prepareForCompile(compilerEnv_.mode())) {
   2232      return nullptr;
   2233    }
   2234 
   2235    // We must give the generator a reference to an error to fill in. We don't
   2236    // use it ourselves though because the only error we should get is for
   2237    // implementation limits like 'stack frame too big' which we couldn't guard
   2238    // against ahead of time. Returning nullptr is the right thing to do in
   2239    // these cases.
   2240    UniqueChars error;
   2241    ModuleGenerator mg(*codeMeta_, compilerEnv_, compilerEnv_.initialState(),
   2242                       nullptr, &error, nullptr);
   2243    if (!mg.initializeCompleteTier(codeMetaForAsmJS_.get())) {
   2244      return nullptr;
   2245    }
   2246 
   2247    for (Func& func : funcDefs_) {
   2248      if (!mg.compileFuncDef(funcImportMap_.count() + func.funcDefIndex(),
   2249                             func.line(), func.bytes().begin(),
   2250                             func.bytes().end(),
   2251                             std::move(func.callSiteLineNums()))) {
   2252        return nullptr;
   2253      }
   2254    }
   2255 
   2256    if (!mg.finishFuncDefs()) {
   2257      return nullptr;
   2258    }
   2259 
   2260    return mg.finishModule(bytecode, *moduleMeta_,
   2261                           /*maybeCompleteTier2Listener=*/nullptr);
   2262  }
   2263 };
   2264 
   2265 /*****************************************************************************/
   2266 // Numeric literal utilities
   2267 
   2268 static bool IsNumericNonFloatLiteral(ParseNode* pn) {
   2269  // Note: '-' is never rolled into the number; numbers are always positive
   2270  // and negations must be applied manually.
   2271  return pn->isKind(ParseNodeKind::NumberExpr) ||
   2272         (pn->isKind(ParseNodeKind::NegExpr) &&
   2273          UnaryKid(pn)->isKind(ParseNodeKind::NumberExpr));
   2274 }
   2275 
   2276 static bool IsCallToGlobal(ModuleValidatorShared& m, ParseNode* pn,
   2277                           const ModuleValidatorShared::Global** global) {
   2278  if (!pn->isKind(ParseNodeKind::CallExpr)) {
   2279    return false;
   2280  }
   2281 
   2282  ParseNode* callee = CallCallee(pn);
   2283  if (!callee->isKind(ParseNodeKind::Name)) {
   2284    return false;
   2285  }
   2286 
   2287  *global = m.lookupGlobal(callee->as<NameNode>().name());
   2288  return !!*global;
   2289 }
   2290 
   2291 static bool IsCoercionCall(ModuleValidatorShared& m, ParseNode* pn,
   2292                           Type* coerceTo, ParseNode** coercedExpr) {
   2293  const ModuleValidatorShared::Global* global;
   2294  if (!IsCallToGlobal(m, pn, &global)) {
   2295    return false;
   2296  }
   2297 
   2298  if (CallArgListLength(pn) != 1) {
   2299    return false;
   2300  }
   2301 
   2302  if (coercedExpr) {
   2303    *coercedExpr = CallArgList(pn);
   2304  }
   2305 
   2306  if (global->isMathFunction() &&
   2307      global->mathBuiltinFunction() == AsmJSMathBuiltin_fround) {
   2308    *coerceTo = Type::Float;
   2309    return true;
   2310  }
   2311 
   2312  return false;
   2313 }
   2314 
   2315 static bool IsFloatLiteral(ModuleValidatorShared& m, ParseNode* pn) {
   2316  ParseNode* coercedExpr;
   2317  Type coerceTo;
   2318  if (!IsCoercionCall(m, pn, &coerceTo, &coercedExpr)) {
   2319    return false;
   2320  }
   2321  // Don't fold into || to avoid clang/memcheck bug (bug 1077031).
   2322  if (!coerceTo.isFloat()) {
   2323    return false;
   2324  }
   2325  return IsNumericNonFloatLiteral(coercedExpr);
   2326 }
   2327 
   2328 static bool IsNumericLiteral(ModuleValidatorShared& m, ParseNode* pn) {
   2329  return IsNumericNonFloatLiteral(pn) || IsFloatLiteral(m, pn);
   2330 }
   2331 
   2332 // The JS grammar treats -42 as -(42) (i.e., with separate grammar
   2333 // productions) for the unary - and literal 42). However, the asm.js spec
   2334 // recognizes -42 (modulo parens, so -(42) and -((42))) as a single literal
   2335 // so fold the two potential parse nodes into a single double value.
   2336 static double ExtractNumericNonFloatValue(ParseNode* pn,
   2337                                          ParseNode** out = nullptr) {
   2338  MOZ_ASSERT(IsNumericNonFloatLiteral(pn));
   2339 
   2340  if (pn->isKind(ParseNodeKind::NegExpr)) {
   2341    pn = UnaryKid(pn);
   2342    if (out) {
   2343      *out = pn;
   2344    }
   2345    return -NumberNodeValue(pn);
   2346  }
   2347 
   2348  return NumberNodeValue(pn);
   2349 }
   2350 
   2351 static NumLit ExtractNumericLiteral(ModuleValidatorShared& m, ParseNode* pn) {
   2352  MOZ_ASSERT(IsNumericLiteral(m, pn));
   2353 
   2354  if (pn->isKind(ParseNodeKind::CallExpr)) {
   2355    // Float literals are explicitly coerced and thus the coerced literal may be
   2356    // any valid (non-float) numeric literal.
   2357    MOZ_ASSERT(CallArgListLength(pn) == 1);
   2358    pn = CallArgList(pn);
   2359    double d = ExtractNumericNonFloatValue(pn);
   2360    return NumLit(NumLit::Float, DoubleValue(d));
   2361  }
   2362 
   2363  double d = ExtractNumericNonFloatValue(pn, &pn);
   2364 
   2365  // The asm.js spec syntactically distinguishes any literal containing a
   2366  // decimal point or the literal -0 as having double type.
   2367  if (NumberNodeHasFrac(pn) || IsNegativeZero(d)) {
   2368    return NumLit(NumLit::Double, DoubleValue(d));
   2369  }
   2370 
   2371  // The syntactic checks above rule out these double values.
   2372  MOZ_ASSERT(!IsNegativeZero(d));
   2373  MOZ_ASSERT(!std::isnan(d));
   2374 
   2375  // Although doubles can only *precisely* represent 53-bit integers, they
   2376  // can *imprecisely* represent integers much bigger than an int64_t.
   2377  // Furthermore, d may be inf or -inf. In both cases, casting to an int64_t
   2378  // is undefined, so test against the integer bounds using doubles.
   2379  if (d < double(INT32_MIN) || d > double(UINT32_MAX)) {
   2380    return NumLit(NumLit::OutOfRangeInt, UndefinedValue());
   2381  }
   2382 
   2383  // With the above syntactic and range limitations, d is definitely an
   2384  // integer in the range [INT32_MIN, UINT32_MAX] range.
   2385  int64_t i64 = int64_t(d);
   2386  if (i64 >= 0) {
   2387    if (i64 <= INT32_MAX) {
   2388      return NumLit(NumLit::Fixnum, Int32Value(i64));
   2389    }
   2390    MOZ_ASSERT(i64 <= UINT32_MAX);
   2391    return NumLit(NumLit::BigUnsigned, Int32Value(uint32_t(i64)));
   2392  }
   2393  MOZ_ASSERT(i64 >= INT32_MIN);
   2394  return NumLit(NumLit::NegativeInt, Int32Value(i64));
   2395 }
   2396 
   2397 static inline bool IsLiteralInt(const NumLit& lit, uint32_t* u32) {
   2398  switch (lit.which()) {
   2399    case NumLit::Fixnum:
   2400    case NumLit::BigUnsigned:
   2401    case NumLit::NegativeInt:
   2402      *u32 = lit.toUint32();
   2403      return true;
   2404    case NumLit::Double:
   2405    case NumLit::Float:
   2406    case NumLit::OutOfRangeInt:
   2407      return false;
   2408  }
   2409  MOZ_CRASH("Bad literal type");
   2410 }
   2411 
   2412 static inline bool IsLiteralInt(ModuleValidatorShared& m, ParseNode* pn,
   2413                                uint32_t* u32) {
   2414  return IsNumericLiteral(m, pn) &&
   2415         IsLiteralInt(ExtractNumericLiteral(m, pn), u32);
   2416 }
   2417 
   2418 /*****************************************************************************/
   2419 
   2420 namespace {
   2421 
   2422 using LabelVector = Vector<TaggedParserAtomIndex, 4, SystemAllocPolicy>;
   2423 
   2424 class MOZ_STACK_CLASS FunctionValidatorShared {
   2425 public:
   2426  struct Local {
   2427    Type type;
   2428    unsigned slot;
   2429    Local(Type t, unsigned slot) : type(t), slot(slot) {
   2430      MOZ_ASSERT(type.isCanonicalValType());
   2431    }
   2432  };
   2433 
   2434 protected:
   2435  using LocalMap =
   2436      HashMap<TaggedParserAtomIndex, Local, TaggedParserAtomIndexHasher>;
   2437  using LabelMap =
   2438      HashMap<TaggedParserAtomIndex, uint32_t, TaggedParserAtomIndexHasher>;
   2439 
   2440  // This is also a ModuleValidator<Unit>& after the appropriate static_cast<>.
   2441  ModuleValidatorShared& m_;
   2442 
   2443  FunctionNode* fn_;
   2444  Bytes bytes_;
   2445  Encoder encoder_;
   2446  Uint32Vector callSiteLineNums_;
   2447  LocalMap locals_;
   2448 
   2449  // Labels
   2450  LabelMap breakLabels_;
   2451  LabelMap continueLabels_;
   2452  Uint32Vector breakableStack_;
   2453  Uint32Vector continuableStack_;
   2454  uint32_t blockDepth_;
   2455 
   2456  bool hasAlreadyReturned_;
   2457  Maybe<ValType> ret_;
   2458 
   2459 private:
   2460  FunctionValidatorShared(ModuleValidatorShared& m, FunctionNode* fn,
   2461                          FrontendContext* fc)
   2462      : m_(m),
   2463        fn_(fn),
   2464        encoder_(bytes_),
   2465        locals_(fc),
   2466        breakLabels_(fc),
   2467        continueLabels_(fc),
   2468        blockDepth_(0),
   2469        hasAlreadyReturned_(false) {}
   2470 
   2471 protected:
   2472  template <typename Unit>
   2473  FunctionValidatorShared(ModuleValidator<Unit>& m, FunctionNode* fn,
   2474                          FrontendContext* fc)
   2475      : FunctionValidatorShared(static_cast<ModuleValidatorShared&>(m), fn,
   2476                                fc) {}
   2477 
   2478 public:
   2479  ModuleValidatorShared& m() const { return m_; }
   2480 
   2481  FrontendContext* fc() const { return m_.fc(); }
   2482  FunctionNode* fn() const { return fn_; }
   2483 
   2484  void define(ModuleValidatorShared::Func* func, unsigned line) {
   2485    MOZ_ASSERT(!blockDepth_);
   2486    MOZ_ASSERT(breakableStack_.empty());
   2487    MOZ_ASSERT(continuableStack_.empty());
   2488    MOZ_ASSERT(breakLabels_.empty());
   2489    MOZ_ASSERT(continueLabels_.empty());
   2490    func->define(fn_, line, std::move(bytes_), std::move(callSiteLineNums_));
   2491  }
   2492 
   2493  bool fail(ParseNode* pn, const char* str) { return m_.fail(pn, str); }
   2494 
   2495  bool failf(ParseNode* pn, const char* fmt, ...) MOZ_FORMAT_PRINTF(3, 4) {
   2496    va_list ap;
   2497    va_start(ap, fmt);
   2498    m_.failfVAOffset(pn->pn_pos.begin, fmt, ap);
   2499    va_end(ap);
   2500    return false;
   2501  }
   2502 
   2503  bool failName(ParseNode* pn, const char* fmt, TaggedParserAtomIndex name) {
   2504    return m_.failName(pn, fmt, name);
   2505  }
   2506 
   2507  /***************************************************** Local scope setup */
   2508 
   2509  bool addLocal(ParseNode* pn, TaggedParserAtomIndex name, Type type) {
   2510    LocalMap::AddPtr p = locals_.lookupForAdd(name);
   2511    if (p) {
   2512      return failName(pn, "duplicate local name '%s' not allowed", name);
   2513    }
   2514    return locals_.add(p, name, Local(type, locals_.count()));
   2515  }
   2516 
   2517  /****************************** For consistency of returns in a function */
   2518 
   2519  bool hasAlreadyReturned() const { return hasAlreadyReturned_; }
   2520 
   2521  Maybe<ValType> returnedType() const { return ret_; }
   2522 
   2523  void setReturnedType(const Maybe<ValType>& ret) {
   2524    MOZ_ASSERT(!hasAlreadyReturned_);
   2525    ret_ = ret;
   2526    hasAlreadyReturned_ = true;
   2527  }
   2528 
   2529  /**************************************************************** Labels */
   2530 private:
   2531  bool writeBr(uint32_t absolute, Op op = Op::Br) {
   2532    MOZ_ASSERT(op == Op::Br || op == Op::BrIf);
   2533    MOZ_ASSERT(absolute < blockDepth_);
   2534    return encoder().writeOp(op) &&
   2535           encoder().writeVarU32(blockDepth_ - 1 - absolute);
   2536  }
   2537  void removeLabel(TaggedParserAtomIndex label, LabelMap* map) {
   2538    LabelMap::Ptr p = map->lookup(label);
   2539    MOZ_ASSERT(p);
   2540    map->remove(p);
   2541  }
   2542 
   2543 public:
   2544  bool pushBreakableBlock() {
   2545    return encoder().writeOp(Op::Block) &&
   2546           encoder().writeFixedU8(uint8_t(TypeCode::BlockVoid)) &&
   2547           breakableStack_.append(blockDepth_++);
   2548  }
   2549  bool popBreakableBlock() {
   2550    MOZ_ALWAYS_TRUE(breakableStack_.popCopy() == --blockDepth_);
   2551    return encoder().writeOp(Op::End);
   2552  }
   2553 
   2554  bool pushUnbreakableBlock(const LabelVector* labels = nullptr) {
   2555    if (labels) {
   2556      for (TaggedParserAtomIndex label : *labels) {
   2557        if (!breakLabels_.putNew(label, blockDepth_)) {
   2558          return false;
   2559        }
   2560      }
   2561    }
   2562    blockDepth_++;
   2563    return encoder().writeOp(Op::Block) &&
   2564           encoder().writeFixedU8(uint8_t(TypeCode::BlockVoid));
   2565  }
   2566  bool popUnbreakableBlock(const LabelVector* labels = nullptr) {
   2567    if (labels) {
   2568      for (TaggedParserAtomIndex label : *labels) {
   2569        removeLabel(label, &breakLabels_);
   2570      }
   2571    }
   2572    --blockDepth_;
   2573    return encoder().writeOp(Op::End);
   2574  }
   2575 
   2576  bool pushContinuableBlock() {
   2577    return encoder().writeOp(Op::Block) &&
   2578           encoder().writeFixedU8(uint8_t(TypeCode::BlockVoid)) &&
   2579           continuableStack_.append(blockDepth_++);
   2580  }
   2581  bool popContinuableBlock() {
   2582    MOZ_ALWAYS_TRUE(continuableStack_.popCopy() == --blockDepth_);
   2583    return encoder().writeOp(Op::End);
   2584  }
   2585 
   2586  bool pushLoop() {
   2587    return encoder().writeOp(Op::Block) &&
   2588           encoder().writeFixedU8(uint8_t(TypeCode::BlockVoid)) &&
   2589           encoder().writeOp(Op::Loop) &&
   2590           encoder().writeFixedU8(uint8_t(TypeCode::BlockVoid)) &&
   2591           breakableStack_.append(blockDepth_++) &&
   2592           continuableStack_.append(blockDepth_++);
   2593  }
   2594  bool popLoop() {
   2595    MOZ_ALWAYS_TRUE(continuableStack_.popCopy() == --blockDepth_);
   2596    MOZ_ALWAYS_TRUE(breakableStack_.popCopy() == --blockDepth_);
   2597    return encoder().writeOp(Op::End) && encoder().writeOp(Op::End);
   2598  }
   2599 
   2600  bool pushIf(size_t* typeAt) {
   2601    ++blockDepth_;
   2602    return encoder().writeOp(Op::If) && encoder().writePatchableFixedU7(typeAt);
   2603  }
   2604  bool switchToElse() {
   2605    MOZ_ASSERT(blockDepth_ > 0);
   2606    return encoder().writeOp(Op::Else);
   2607  }
   2608  void setIfType(size_t typeAt, TypeCode type) {
   2609    encoder().patchFixedU7(typeAt, uint8_t(type));
   2610  }
   2611  bool popIf() {
   2612    MOZ_ASSERT(blockDepth_ > 0);
   2613    --blockDepth_;
   2614    return encoder().writeOp(Op::End);
   2615  }
   2616  bool popIf(size_t typeAt, TypeCode type) {
   2617    MOZ_ASSERT(blockDepth_ > 0);
   2618    --blockDepth_;
   2619    if (!encoder().writeOp(Op::End)) {
   2620      return false;
   2621    }
   2622 
   2623    setIfType(typeAt, type);
   2624    return true;
   2625  }
   2626 
   2627  bool writeBreakIf() { return writeBr(breakableStack_.back(), Op::BrIf); }
   2628  bool writeContinueIf() { return writeBr(continuableStack_.back(), Op::BrIf); }
   2629  bool writeUnlabeledBreakOrContinue(bool isBreak) {
   2630    return writeBr(isBreak ? breakableStack_.back() : continuableStack_.back());
   2631  }
   2632  bool writeContinue() { return writeBr(continuableStack_.back()); }
   2633 
   2634  bool addLabels(const LabelVector& labels, uint32_t relativeBreakDepth,
   2635                 uint32_t relativeContinueDepth) {
   2636    for (TaggedParserAtomIndex label : labels) {
   2637      if (!breakLabels_.putNew(label, blockDepth_ + relativeBreakDepth)) {
   2638        return false;
   2639      }
   2640      if (!continueLabels_.putNew(label, blockDepth_ + relativeContinueDepth)) {
   2641        return false;
   2642      }
   2643    }
   2644    return true;
   2645  }
   2646  void removeLabels(const LabelVector& labels) {
   2647    for (TaggedParserAtomIndex label : labels) {
   2648      removeLabel(label, &breakLabels_);
   2649      removeLabel(label, &continueLabels_);
   2650    }
   2651  }
   2652  bool writeLabeledBreakOrContinue(TaggedParserAtomIndex label, bool isBreak) {
   2653    LabelMap& map = isBreak ? breakLabels_ : continueLabels_;
   2654    if (LabelMap::Ptr p = map.lookup(label)) {
   2655      return writeBr(p->value());
   2656    }
   2657    MOZ_CRASH("nonexistent label");
   2658  }
   2659 
   2660  /*************************************************** Read-only interface */
   2661 
   2662  const Local* lookupLocal(TaggedParserAtomIndex name) const {
   2663    if (auto p = locals_.lookup(name)) {
   2664      return &p->value();
   2665    }
   2666    return nullptr;
   2667  }
   2668 
   2669  const ModuleValidatorShared::Global* lookupGlobal(
   2670      TaggedParserAtomIndex name) const {
   2671    if (locals_.has(name)) {
   2672      return nullptr;
   2673    }
   2674    return m_.lookupGlobal(name);
   2675  }
   2676 
   2677  size_t numLocals() const { return locals_.count(); }
   2678 
   2679  /**************************************************** Encoding interface */
   2680 
   2681  Encoder& encoder() { return encoder_; }
   2682 
   2683  [[nodiscard]] bool writeInt32Lit(int32_t i32) {
   2684    return encoder().writeOp(Op::I32Const) && encoder().writeVarS32(i32);
   2685  }
   2686  [[nodiscard]] bool writeConstExpr(const NumLit& lit) {
   2687    switch (lit.which()) {
   2688      case NumLit::Fixnum:
   2689      case NumLit::NegativeInt:
   2690      case NumLit::BigUnsigned:
   2691        return writeInt32Lit(lit.toInt32());
   2692      case NumLit::Float:
   2693        return encoder().writeOp(Op::F32Const) &&
   2694               encoder().writeFixedF32(lit.toFloat());
   2695      case NumLit::Double:
   2696        return encoder().writeOp(Op::F64Const) &&
   2697               encoder().writeFixedF64(lit.toDouble());
   2698      case NumLit::OutOfRangeInt:
   2699        break;
   2700    }
   2701    MOZ_CRASH("unexpected literal type");
   2702  }
   2703 };
   2704 
   2705 // Encapsulates the building of an asm bytecode function from an asm.js function
   2706 // source code, packing the asm.js code into the asm bytecode form that can
   2707 // be decoded and compiled with a FunctionCompiler.
   2708 template <typename Unit>
   2709 class MOZ_STACK_CLASS FunctionValidator : public FunctionValidatorShared {
   2710 public:
   2711  FunctionValidator(ModuleValidator<Unit>& m, FunctionNode* fn)
   2712      : FunctionValidatorShared(m, fn, m.fc()) {}
   2713 
   2714 public:
   2715  ModuleValidator<Unit>& m() const {
   2716    return static_cast<ModuleValidator<Unit>&>(FunctionValidatorShared::m());
   2717  }
   2718 
   2719  [[nodiscard]] bool writeCall(ParseNode* pn, Op op) {
   2720    MOZ_ASSERT(op == Op::Call);
   2721    if (!encoder().writeOp(op)) {
   2722      return false;
   2723    }
   2724 
   2725    return appendCallSiteLineNumber(pn);
   2726  }
   2727  [[nodiscard]] bool writeCall(ParseNode* pn, MozOp op) {
   2728    MOZ_ASSERT(op == MozOp::OldCallDirect || op == MozOp::OldCallIndirect);
   2729    if (!encoder().writeOp(op)) {
   2730      return false;
   2731    }
   2732 
   2733    return appendCallSiteLineNumber(pn);
   2734  }
   2735  [[nodiscard]] bool prepareCall(ParseNode* pn) {
   2736    return appendCallSiteLineNumber(pn);
   2737  }
   2738 
   2739 private:
   2740  [[nodiscard]] bool appendCallSiteLineNumber(ParseNode* node) {
   2741    const TokenStreamAnyChars& anyChars = m().tokenStream().anyCharsAccess();
   2742    auto lineToken = anyChars.lineToken(node->pn_pos.begin);
   2743    uint32_t lineNumber = anyChars.lineNumber(lineToken);
   2744    if (lineNumber > CallSiteDesc::MAX_LINE_OR_BYTECODE_VALUE) {
   2745      return fail(node, "line number exceeding implementation limits");
   2746    }
   2747    return callSiteLineNums_.append(lineNumber);
   2748  }
   2749 };
   2750 
   2751 } /* anonymous namespace */
   2752 
   2753 /*****************************************************************************/
   2754 // asm.js type-checking and code-generation algorithm
   2755 
   2756 static bool CheckIdentifier(ModuleValidatorShared& m, ParseNode* usepn,
   2757                            TaggedParserAtomIndex name) {
   2758  if (name == TaggedParserAtomIndex::WellKnown::arguments() ||
   2759      name == TaggedParserAtomIndex::WellKnown::eval()) {
   2760    return m.failName(usepn, "'%s' is not an allowed identifier", name);
   2761  }
   2762  return true;
   2763 }
   2764 
   2765 static bool CheckModuleLevelName(ModuleValidatorShared& m, ParseNode* usepn,
   2766                                 TaggedParserAtomIndex name) {
   2767  if (!CheckIdentifier(m, usepn, name)) {
   2768    return false;
   2769  }
   2770 
   2771  if (name == m.moduleFunctionName() || name == m.globalArgumentName() ||
   2772      name == m.importArgumentName() || name == m.bufferArgumentName() ||
   2773      m.lookupGlobal(name)) {
   2774    return m.failName(usepn, "duplicate name '%s' not allowed", name);
   2775  }
   2776 
   2777  return true;
   2778 }
   2779 
   2780 static bool CheckFunctionHead(ModuleValidatorShared& m, FunctionNode* funNode) {
   2781  FunctionBox* funbox = funNode->funbox();
   2782  MOZ_ASSERT(!funbox->hasExprBody());
   2783 
   2784  if (funbox->hasRest()) {
   2785    return m.fail(funNode, "rest args not allowed");
   2786  }
   2787  if (funbox->hasDestructuringArgs) {
   2788    return m.fail(funNode, "destructuring args not allowed");
   2789  }
   2790  return true;
   2791 }
   2792 
   2793 static bool CheckArgument(ModuleValidatorShared& m, ParseNode* arg,
   2794                          TaggedParserAtomIndex* name) {
   2795  *name = TaggedParserAtomIndex::null();
   2796 
   2797  if (!arg->isKind(ParseNodeKind::Name)) {
   2798    return m.fail(arg, "argument is not a plain name");
   2799  }
   2800 
   2801  TaggedParserAtomIndex argName = arg->as<NameNode>().name();
   2802  if (!CheckIdentifier(m, arg, argName)) {
   2803    return false;
   2804  }
   2805 
   2806  *name = argName;
   2807  return true;
   2808 }
   2809 
   2810 static bool CheckModuleArgument(ModuleValidatorShared& m, ParseNode* arg,
   2811                                TaggedParserAtomIndex* name) {
   2812  if (!CheckArgument(m, arg, name)) {
   2813    return false;
   2814  }
   2815 
   2816  return CheckModuleLevelName(m, arg, *name);
   2817 }
   2818 
   2819 static bool CheckModuleArguments(ModuleValidatorShared& m,
   2820                                 FunctionNode* funNode) {
   2821  unsigned numFormals;
   2822  ParseNode* arg1 = FunctionFormalParametersList(funNode, &numFormals);
   2823  ParseNode* arg2 = arg1 ? NextNode(arg1) : nullptr;
   2824  ParseNode* arg3 = arg2 ? NextNode(arg2) : nullptr;
   2825 
   2826  if (numFormals > 3) {
   2827    return m.fail(funNode, "asm.js modules takes at most 3 argument");
   2828  }
   2829 
   2830  TaggedParserAtomIndex arg1Name;
   2831  if (arg1 && !CheckModuleArgument(m, arg1, &arg1Name)) {
   2832    return false;
   2833  }
   2834  if (!m.initGlobalArgumentName(arg1Name)) {
   2835    return false;
   2836  }
   2837 
   2838  TaggedParserAtomIndex arg2Name;
   2839  if (arg2 && !CheckModuleArgument(m, arg2, &arg2Name)) {
   2840    return false;
   2841  }
   2842  if (!m.initImportArgumentName(arg2Name)) {
   2843    return false;
   2844  }
   2845 
   2846  TaggedParserAtomIndex arg3Name;
   2847  if (arg3 && !CheckModuleArgument(m, arg3, &arg3Name)) {
   2848    return false;
   2849  }
   2850  return m.initBufferArgumentName(arg3Name);
   2851 }
   2852 
   2853 static bool CheckPrecedingStatements(ModuleValidatorShared& m,
   2854                                     ParseNode* stmtList) {
   2855  MOZ_ASSERT(stmtList->isKind(ParseNodeKind::StatementList));
   2856 
   2857  ParseNode* stmt = ListHead(stmtList);
   2858  for (unsigned i = 0, n = ListLength(stmtList); i < n; i++) {
   2859    if (!IsIgnoredDirective(stmt)) {
   2860      return m.fail(stmt, "invalid asm.js statement");
   2861    }
   2862  }
   2863 
   2864  return true;
   2865 }
   2866 
   2867 static bool CheckGlobalVariableInitConstant(ModuleValidatorShared& m,
   2868                                            TaggedParserAtomIndex varName,
   2869                                            ParseNode* initNode, bool isConst) {
   2870  NumLit lit = ExtractNumericLiteral(m, initNode);
   2871  if (!lit.valid()) {
   2872    return m.fail(initNode,
   2873                  "global initializer is out of representable integer range");
   2874  }
   2875 
   2876  Type canonicalType = Type::canonicalize(Type::lit(lit));
   2877  if (!canonicalType.isGlobalVarType()) {
   2878    return m.fail(initNode, "global variable type not allowed");
   2879  }
   2880 
   2881  return m.addGlobalVarInit(varName, lit, canonicalType, isConst);
   2882 }
   2883 
   2884 static bool CheckTypeAnnotation(ModuleValidatorShared& m,
   2885                                ParseNode* coercionNode, Type* coerceTo,
   2886                                ParseNode** coercedExpr = nullptr) {
   2887  switch (coercionNode->getKind()) {
   2888    case ParseNodeKind::BitOrExpr: {
   2889      ParseNode* rhs = BitwiseRight(coercionNode);
   2890      uint32_t i;
   2891      if (!IsLiteralInt(m, rhs, &i) || i != 0) {
   2892        return m.fail(rhs, "must use |0 for argument/return coercion");
   2893      }
   2894      *coerceTo = Type::Int;
   2895      if (coercedExpr) {
   2896        *coercedExpr = BitwiseLeft(coercionNode);
   2897      }
   2898      return true;
   2899    }
   2900    case ParseNodeKind::PosExpr: {
   2901      *coerceTo = Type::Double;
   2902      if (coercedExpr) {
   2903        *coercedExpr = UnaryKid(coercionNode);
   2904      }
   2905      return true;
   2906    }
   2907    case ParseNodeKind::CallExpr: {
   2908      if (IsCoercionCall(m, coercionNode, coerceTo, coercedExpr)) {
   2909        return true;
   2910      }
   2911      break;
   2912    }
   2913    default:;
   2914  }
   2915 
   2916  return m.fail(coercionNode, "must be of the form +x, x|0 or fround(x)");
   2917 }
   2918 
   2919 static bool CheckGlobalVariableInitImport(ModuleValidatorShared& m,
   2920                                          TaggedParserAtomIndex varName,
   2921                                          ParseNode* initNode, bool isConst) {
   2922  Type coerceTo;
   2923  ParseNode* coercedExpr;
   2924  if (!CheckTypeAnnotation(m, initNode, &coerceTo, &coercedExpr)) {
   2925    return false;
   2926  }
   2927 
   2928  if (!coercedExpr->isKind(ParseNodeKind::DotExpr)) {
   2929    return m.failName(coercedExpr, "invalid import expression for global '%s'",
   2930                      varName);
   2931  }
   2932 
   2933  if (!coerceTo.isGlobalVarType()) {
   2934    return m.fail(initNode, "global variable type not allowed");
   2935  }
   2936 
   2937  ParseNode* base = DotBase(coercedExpr);
   2938  TaggedParserAtomIndex field = DotMember(coercedExpr);
   2939 
   2940  TaggedParserAtomIndex importName = m.importArgumentName();
   2941  if (!importName) {
   2942    return m.fail(coercedExpr,
   2943                  "cannot import without an asm.js foreign parameter");
   2944  }
   2945  if (!IsUseOfName(base, importName)) {
   2946    return m.failName(coercedExpr, "base of import expression must be '%s'",
   2947                      importName);
   2948  }
   2949 
   2950  return m.addGlobalVarImport(varName, field, coerceTo, isConst);
   2951 }
   2952 
   2953 static bool IsArrayViewCtorName(ModuleValidatorShared& m,
   2954                                TaggedParserAtomIndex name,
   2955                                Scalar::Type* type) {
   2956  if (name == TaggedParserAtomIndex::WellKnown::Int8Array()) {
   2957    *type = Scalar::Int8;
   2958  } else if (name == TaggedParserAtomIndex::WellKnown::Uint8Array()) {
   2959    *type = Scalar::Uint8;
   2960  } else if (name == TaggedParserAtomIndex::WellKnown::Int16Array()) {
   2961    *type = Scalar::Int16;
   2962  } else if (name == TaggedParserAtomIndex::WellKnown::Uint16Array()) {
   2963    *type = Scalar::Uint16;
   2964  } else if (name == TaggedParserAtomIndex::WellKnown::Int32Array()) {
   2965    *type = Scalar::Int32;
   2966  } else if (name == TaggedParserAtomIndex::WellKnown::Uint32Array()) {
   2967    *type = Scalar::Uint32;
   2968  } else if (name == TaggedParserAtomIndex::WellKnown::Float32Array()) {
   2969    *type = Scalar::Float32;
   2970  } else if (name == TaggedParserAtomIndex::WellKnown::Float64Array()) {
   2971    *type = Scalar::Float64;
   2972  } else {
   2973    return false;
   2974  }
   2975  return true;
   2976 }
   2977 
   2978 static bool CheckNewArrayViewArgs(ModuleValidatorShared& m, ParseNode* newExpr,
   2979                                  TaggedParserAtomIndex bufferName) {
   2980  ParseNode* ctorExpr = BinaryLeft(newExpr);
   2981  ParseNode* ctorArgs = BinaryRight(newExpr);
   2982  ParseNode* bufArg = ListHead(ctorArgs);
   2983  if (!bufArg || NextNode(bufArg) != nullptr) {
   2984    return m.fail(ctorExpr,
   2985                  "array view constructor takes exactly one argument");
   2986  }
   2987 
   2988  if (!IsUseOfName(bufArg, bufferName)) {
   2989    return m.failName(bufArg, "argument to array view constructor must be '%s'",
   2990                      bufferName);
   2991  }
   2992 
   2993  return true;
   2994 }
   2995 
   2996 static bool CheckNewArrayView(ModuleValidatorShared& m,
   2997                              TaggedParserAtomIndex varName,
   2998                              ParseNode* newExpr) {
   2999  TaggedParserAtomIndex globalName = m.globalArgumentName();
   3000  if (!globalName) {
   3001    return m.fail(
   3002        newExpr, "cannot create array view without an asm.js global parameter");
   3003  }
   3004 
   3005  TaggedParserAtomIndex bufferName = m.bufferArgumentName();
   3006  if (!bufferName) {
   3007    return m.fail(newExpr,
   3008                  "cannot create array view without an asm.js heap parameter");
   3009  }
   3010 
   3011  ParseNode* ctorExpr = BinaryLeft(newExpr);
   3012 
   3013  TaggedParserAtomIndex field;
   3014  Scalar::Type type;
   3015  if (ctorExpr->isKind(ParseNodeKind::DotExpr)) {
   3016    ParseNode* base = DotBase(ctorExpr);
   3017 
   3018    if (!IsUseOfName(base, globalName)) {
   3019      return m.failName(base, "expecting '%s.*Array", globalName);
   3020    }
   3021 
   3022    field = DotMember(ctorExpr);
   3023    if (!IsArrayViewCtorName(m, field, &type)) {
   3024      return m.fail(ctorExpr, "could not match typed array name");
   3025    }
   3026  } else {
   3027    if (!ctorExpr->isKind(ParseNodeKind::Name)) {
   3028      return m.fail(ctorExpr,
   3029                    "expecting name of imported array view constructor");
   3030    }
   3031 
   3032    TaggedParserAtomIndex globalName = ctorExpr->as<NameNode>().name();
   3033    const ModuleValidatorShared::Global* global = m.lookupGlobal(globalName);
   3034    if (!global) {
   3035      return m.failName(ctorExpr, "%s not found in module global scope",
   3036                        globalName);
   3037    }
   3038 
   3039    if (global->which() != ModuleValidatorShared::Global::ArrayViewCtor) {
   3040      return m.failName(ctorExpr,
   3041                        "%s must be an imported array view constructor",
   3042                        globalName);
   3043    }
   3044 
   3045    type = global->viewType();
   3046  }
   3047 
   3048  if (!CheckNewArrayViewArgs(m, newExpr, bufferName)) {
   3049    return false;
   3050  }
   3051 
   3052  return m.addArrayView(varName, type, field);
   3053 }
   3054 
   3055 static bool CheckGlobalMathImport(ModuleValidatorShared& m, ParseNode* initNode,
   3056                                  TaggedParserAtomIndex varName,
   3057                                  TaggedParserAtomIndex field) {
   3058  // Math builtin, with the form glob.Math.[[builtin]]
   3059  ModuleValidatorShared::MathBuiltin mathBuiltin;
   3060  if (!m.lookupStandardLibraryMathName(field, &mathBuiltin)) {
   3061    return m.failName(initNode, "'%s' is not a standard Math builtin", field);
   3062  }
   3063 
   3064  switch (mathBuiltin.kind) {
   3065    case ModuleValidatorShared::MathBuiltin::Function:
   3066      return m.addMathBuiltinFunction(varName, mathBuiltin.u.func, field);
   3067    case ModuleValidatorShared::MathBuiltin::Constant:
   3068      return m.addMathBuiltinConstant(varName, mathBuiltin.u.cst, field);
   3069    default:
   3070      break;
   3071  }
   3072  MOZ_CRASH("unexpected or uninitialized math builtin type");
   3073 }
   3074 
   3075 static bool CheckGlobalDotImport(ModuleValidatorShared& m,
   3076                                 TaggedParserAtomIndex varName,
   3077                                 ParseNode* initNode) {
   3078  ParseNode* base = DotBase(initNode);
   3079  TaggedParserAtomIndex field = DotMember(initNode);
   3080 
   3081  if (base->isKind(ParseNodeKind::DotExpr)) {
   3082    ParseNode* global = DotBase(base);
   3083    TaggedParserAtomIndex math = DotMember(base);
   3084 
   3085    TaggedParserAtomIndex globalName = m.globalArgumentName();
   3086    if (!globalName) {
   3087      return m.fail(
   3088          base, "import statement requires the module have a stdlib parameter");
   3089    }
   3090 
   3091    if (!IsUseOfName(global, globalName)) {
   3092      if (global->isKind(ParseNodeKind::DotExpr)) {
   3093        return m.failName(base,
   3094                          "imports can have at most two dot accesses "
   3095                          "(e.g. %s.Math.sin)",
   3096                          globalName);
   3097      }
   3098      return m.failName(base, "expecting %s.*", globalName);
   3099    }
   3100 
   3101    if (math == TaggedParserAtomIndex::WellKnown::Math()) {
   3102      return CheckGlobalMathImport(m, initNode, varName, field);
   3103    }
   3104    return m.failName(base, "expecting %s.Math", globalName);
   3105  }
   3106 
   3107  if (!base->isKind(ParseNodeKind::Name)) {
   3108    return m.fail(base, "expected name of variable or parameter");
   3109  }
   3110 
   3111  auto baseName = base->as<NameNode>().name();
   3112  if (baseName == m.globalArgumentName()) {
   3113    if (field == TaggedParserAtomIndex::WellKnown::NaN()) {
   3114      return m.addGlobalConstant(varName, GenericNaN(), field);
   3115    }
   3116    if (field == TaggedParserAtomIndex::WellKnown::Infinity()) {
   3117      return m.addGlobalConstant(varName, PositiveInfinity<double>(), field);
   3118    }
   3119 
   3120    Scalar::Type type;
   3121    if (IsArrayViewCtorName(m, field, &type)) {
   3122      return m.addArrayViewCtor(varName, type, field);
   3123    }
   3124 
   3125    return m.failName(
   3126        initNode, "'%s' is not a standard constant or typed array name", field);
   3127  }
   3128 
   3129  if (baseName != m.importArgumentName()) {
   3130    return m.fail(base, "expected global or import name");
   3131  }
   3132 
   3133  return m.addFFI(varName, field);
   3134 }
   3135 
   3136 static bool CheckModuleGlobal(ModuleValidatorShared& m, ParseNode* decl,
   3137                              bool isConst) {
   3138  if (!decl->isKind(ParseNodeKind::AssignExpr)) {
   3139    return m.fail(decl, "module import needs initializer");
   3140  }
   3141  AssignmentNode* assignNode = &decl->as<AssignmentNode>();
   3142 
   3143  ParseNode* var = assignNode->left();
   3144 
   3145  if (!var->isKind(ParseNodeKind::Name)) {
   3146    return m.fail(var, "import variable is not a plain name");
   3147  }
   3148 
   3149  TaggedParserAtomIndex varName = var->as<NameNode>().name();
   3150  if (!CheckModuleLevelName(m, var, varName)) {
   3151    return false;
   3152  }
   3153 
   3154  ParseNode* initNode = assignNode->right();
   3155 
   3156  if (IsNumericLiteral(m, initNode)) {
   3157    return CheckGlobalVariableInitConstant(m, varName, initNode, isConst);
   3158  }
   3159 
   3160  if (initNode->isKind(ParseNodeKind::BitOrExpr) ||
   3161      initNode->isKind(ParseNodeKind::PosExpr) ||
   3162      initNode->isKind(ParseNodeKind::CallExpr)) {
   3163    return CheckGlobalVariableInitImport(m, varName, initNode, isConst);
   3164  }
   3165 
   3166  if (initNode->isKind(ParseNodeKind::NewExpr)) {
   3167    return CheckNewArrayView(m, varName, initNode);
   3168  }
   3169 
   3170  if (initNode->isKind(ParseNodeKind::DotExpr)) {
   3171    return CheckGlobalDotImport(m, varName, initNode);
   3172  }
   3173 
   3174  return m.fail(initNode, "unsupported import expression");
   3175 }
   3176 
   3177 template <typename Unit>
   3178 static bool CheckModuleProcessingDirectives(ModuleValidator<Unit>& m) {
   3179  auto& ts = m.parser().tokenStream;
   3180  while (true) {
   3181    bool matched;
   3182    if (!ts.matchToken(&matched, TokenKind::String,
   3183                       TokenStreamShared::SlashIsRegExp)) {
   3184      return false;
   3185    }
   3186    if (!matched) {
   3187      return true;
   3188    }
   3189 
   3190    if (!IsIgnoredDirectiveName(ts.anyCharsAccess().currentToken().atom())) {
   3191      return m.failCurrentOffset("unsupported processing directive");
   3192    }
   3193 
   3194    TokenKind tt;
   3195    if (!ts.getToken(&tt)) {
   3196      return false;
   3197    }
   3198    if (tt != TokenKind::Semi) {
   3199      return m.failCurrentOffset("expected semicolon after string literal");
   3200    }
   3201  }
   3202 }
   3203 
   3204 template <typename Unit>
   3205 static bool CheckModuleGlobals(ModuleValidator<Unit>& m) {
   3206  while (true) {
   3207    ParseNode* varStmt;
   3208    if (!ParseVarOrConstStatement(m.parser(), &varStmt)) {
   3209      return false;
   3210    }
   3211    if (!varStmt) {
   3212      break;
   3213    }
   3214    for (ParseNode* var = VarListHead(varStmt); var; var = NextNode(var)) {
   3215      if (!CheckModuleGlobal(m, var,
   3216                             varStmt->isKind(ParseNodeKind::ConstDecl))) {
   3217        return false;
   3218      }
   3219    }
   3220  }
   3221 
   3222  return true;
   3223 }
   3224 
   3225 static bool ArgFail(FunctionValidatorShared& f, TaggedParserAtomIndex argName,
   3226                    ParseNode* stmt) {
   3227  return f.failName(stmt,
   3228                    "expecting argument type declaration for '%s' of the "
   3229                    "form 'arg = arg|0' or 'arg = +arg' or 'arg = fround(arg)'",
   3230                    argName);
   3231 }
   3232 
   3233 static bool CheckArgumentType(FunctionValidatorShared& f, ParseNode* stmt,
   3234                              TaggedParserAtomIndex name, Type* type) {
   3235  if (!stmt || !IsExpressionStatement(stmt)) {
   3236    return ArgFail(f, name, stmt ? stmt : f.fn());
   3237  }
   3238 
   3239  ParseNode* initNode = ExpressionStatementExpr(stmt);
   3240  if (!initNode->isKind(ParseNodeKind::AssignExpr)) {
   3241    return ArgFail(f, name, stmt);
   3242  }
   3243 
   3244  ParseNode* argNode = BinaryLeft(initNode);
   3245  ParseNode* coercionNode = BinaryRight(initNode);
   3246 
   3247  if (!IsUseOfName(argNode, name)) {
   3248    return ArgFail(f, name, stmt);
   3249  }
   3250 
   3251  ParseNode* coercedExpr;
   3252  if (!CheckTypeAnnotation(f.m(), coercionNode, type, &coercedExpr)) {
   3253    return false;
   3254  }
   3255 
   3256  if (!type->isArgType()) {
   3257    return f.failName(stmt, "invalid type for argument '%s'", name);
   3258  }
   3259 
   3260  if (!IsUseOfName(coercedExpr, name)) {
   3261    return ArgFail(f, name, stmt);
   3262  }
   3263 
   3264  return true;
   3265 }
   3266 
   3267 static bool CheckProcessingDirectives(ModuleValidatorShared& m,
   3268                                      ParseNode** stmtIter) {
   3269  ParseNode* stmt = *stmtIter;
   3270 
   3271  while (stmt && IsIgnoredDirective(stmt)) {
   3272    stmt = NextNode(stmt);
   3273  }
   3274 
   3275  *stmtIter = stmt;
   3276  return true;
   3277 }
   3278 
   3279 static bool CheckArguments(FunctionValidatorShared& f, ParseNode** stmtIter,
   3280                           ValTypeVector* argTypes) {
   3281  ParseNode* stmt = *stmtIter;
   3282 
   3283  unsigned numFormals;
   3284  ParseNode* argpn = FunctionFormalParametersList(f.fn(), &numFormals);
   3285 
   3286  for (unsigned i = 0; i < numFormals;
   3287       i++, argpn = NextNode(argpn), stmt = NextNode(stmt)) {
   3288    TaggedParserAtomIndex name;
   3289    if (!CheckArgument(f.m(), argpn, &name)) {
   3290      return false;
   3291    }
   3292 
   3293    Type type;
   3294    if (!CheckArgumentType(f, stmt, name, &type)) {
   3295      return false;
   3296    }
   3297 
   3298    if (!argTypes->append(type.canonicalToValType())) {
   3299      return false;
   3300    }
   3301 
   3302    if (argTypes->length() > MaxParams) {
   3303      return f.fail(stmt, "too many parameters");
   3304    }
   3305 
   3306    if (!f.addLocal(argpn, name, type)) {
   3307      return false;
   3308    }
   3309  }
   3310 
   3311  *stmtIter = stmt;
   3312  return true;
   3313 }
   3314 
   3315 static bool IsLiteralOrConst(FunctionValidatorShared& f, ParseNode* pn,
   3316                             NumLit* lit) {
   3317  if (pn->isKind(ParseNodeKind::Name)) {
   3318    const ModuleValidatorShared::Global* global =
   3319        f.lookupGlobal(pn->as<NameNode>().name());
   3320    if (!global ||
   3321        global->which() != ModuleValidatorShared::Global::ConstantLiteral) {
   3322      return false;
   3323    }
   3324 
   3325    *lit = global->constLiteralValue();
   3326    return true;
   3327  }
   3328 
   3329  if (!IsNumericLiteral(f.m(), pn)) {
   3330    return false;
   3331  }
   3332 
   3333  *lit = ExtractNumericLiteral(f.m(), pn);
   3334  return true;
   3335 }
   3336 
   3337 static bool CheckFinalReturn(FunctionValidatorShared& f,
   3338                             ParseNode* lastNonEmptyStmt) {
   3339  if (!f.encoder().writeOp(Op::End)) {
   3340    return false;
   3341  }
   3342 
   3343  if (!f.hasAlreadyReturned()) {
   3344    f.setReturnedType(Nothing());
   3345    return true;
   3346  }
   3347 
   3348  if (!lastNonEmptyStmt->isKind(ParseNodeKind::ReturnStmt) &&
   3349      f.returnedType()) {
   3350    return f.fail(lastNonEmptyStmt,
   3351                  "void incompatible with previous return type");
   3352  }
   3353 
   3354  return true;
   3355 }
   3356 
   3357 static bool CheckVariable(FunctionValidatorShared& f, ParseNode* decl,
   3358                          ValTypeVector* types, Vector<NumLit>* inits) {
   3359  if (!decl->isKind(ParseNodeKind::AssignExpr)) {
   3360    return f.failName(
   3361        decl, "var '%s' needs explicit type declaration via an initial value",
   3362        decl->as<NameNode>().name());
   3363  }
   3364  AssignmentNode* assignNode = &decl->as<AssignmentNode>();
   3365 
   3366  ParseNode* var = assignNode->left();
   3367 
   3368  if (!var->isKind(ParseNodeKind::Name)) {
   3369    return f.fail(var, "local variable is not a plain name");
   3370  }
   3371 
   3372  TaggedParserAtomIndex name = var->as<NameNode>().name();
   3373 
   3374  if (!CheckIdentifier(f.m(), var, name)) {
   3375    return false;
   3376  }
   3377 
   3378  ParseNode* initNode = assignNode->right();
   3379 
   3380  NumLit lit;
   3381  if (!IsLiteralOrConst(f, initNode, &lit)) {
   3382    return f.failName(
   3383        var, "var '%s' initializer must be literal or const literal", name);
   3384  }
   3385 
   3386  if (!lit.valid()) {
   3387    return f.failName(var, "var '%s' initializer out of range", name);
   3388  }
   3389 
   3390  Type type = Type::canonicalize(Type::lit(lit));
   3391 
   3392  return f.addLocal(var, name, type) &&
   3393         types->append(type.canonicalToValType()) && inits->append(lit);
   3394 }
   3395 
   3396 static bool CheckVariables(FunctionValidatorShared& f, ParseNode** stmtIter) {
   3397  ParseNode* stmt = *stmtIter;
   3398 
   3399  uint32_t firstVar = f.numLocals();
   3400 
   3401  ValTypeVector types;
   3402  Vector<NumLit> inits(f.fc());
   3403 
   3404  for (; stmt && stmt->isKind(ParseNodeKind::VarStmt);
   3405       stmt = NextNonEmptyStatement(stmt)) {
   3406    for (ParseNode* var = VarListHead(stmt); var; var = NextNode(var)) {
   3407      if (!CheckVariable(f, var, &types, &inits)) {
   3408        return false;
   3409      }
   3410    }
   3411  }
   3412 
   3413  MOZ_ASSERT(f.encoder().empty());
   3414 
   3415  if (!EncodeLocalEntries(f.encoder(), types)) {
   3416    return false;
   3417  }
   3418 
   3419  for (uint32_t i = 0; i < inits.length(); i++) {
   3420    NumLit lit = inits[i];
   3421    if (lit.isZeroBits()) {
   3422      continue;
   3423    }
   3424    if (!f.writeConstExpr(lit)) {
   3425      return false;
   3426    }
   3427    if (!f.encoder().writeOp(Op::LocalSet)) {
   3428      return false;
   3429    }
   3430    if (!f.encoder().writeVarU32(firstVar + i)) {
   3431      return false;
   3432    }
   3433  }
   3434 
   3435  *stmtIter = stmt;
   3436  return true;
   3437 }
   3438 
   3439 template <typename Unit>
   3440 static bool CheckExpr(FunctionValidator<Unit>& f, ParseNode* expr, Type* type);
   3441 
   3442 template <typename Unit>
   3443 static bool CheckNumericLiteral(FunctionValidator<Unit>& f, ParseNode* num,
   3444                                Type* type) {
   3445  NumLit lit = ExtractNumericLiteral(f.m(), num);
   3446  if (!lit.valid()) {
   3447    return f.fail(num, "numeric literal out of representable integer range");
   3448  }
   3449  *type = Type::lit(lit);
   3450  return f.writeConstExpr(lit);
   3451 }
   3452 
   3453 static bool CheckVarRef(FunctionValidatorShared& f, ParseNode* varRef,
   3454                        Type* type) {
   3455  TaggedParserAtomIndex name = varRef->as<NameNode>().name();
   3456 
   3457  if (const FunctionValidatorShared::Local* local = f.lookupLocal(name)) {
   3458    if (!f.encoder().writeOp(Op::LocalGet)) {
   3459      return false;
   3460    }
   3461    if (!f.encoder().writeVarU32(local->slot)) {
   3462      return false;
   3463    }
   3464    *type = local->type;
   3465    return true;
   3466  }
   3467 
   3468  if (const ModuleValidatorShared::Global* global = f.lookupGlobal(name)) {
   3469    switch (global->which()) {
   3470      case ModuleValidatorShared::Global::ConstantLiteral:
   3471        *type = global->varOrConstType();
   3472        return f.writeConstExpr(global->constLiteralValue());
   3473      case ModuleValidatorShared::Global::ConstantImport:
   3474      case ModuleValidatorShared::Global::Variable: {
   3475        *type = global->varOrConstType();
   3476        return f.encoder().writeOp(Op::GlobalGet) &&
   3477               f.encoder().writeVarU32(global->varOrConstIndex());
   3478      }
   3479      case ModuleValidatorShared::Global::Function:
   3480      case ModuleValidatorShared::Global::FFI:
   3481      case ModuleValidatorShared::Global::MathBuiltinFunction:
   3482      case ModuleValidatorShared::Global::Table:
   3483      case ModuleValidatorShared::Global::ArrayView:
   3484      case ModuleValidatorShared::Global::ArrayViewCtor:
   3485        break;
   3486    }
   3487    return f.failName(varRef,
   3488                      "'%s' may not be accessed by ordinary expressions", name);
   3489  }
   3490 
   3491  return f.failName(varRef, "'%s' not found in local or asm.js module scope",
   3492                    name);
   3493 }
   3494 
   3495 static inline bool IsLiteralOrConstInt(FunctionValidatorShared& f,
   3496                                       ParseNode* pn, uint32_t* u32) {
   3497  NumLit lit;
   3498  if (!IsLiteralOrConst(f, pn, &lit)) {
   3499    return false;
   3500  }
   3501 
   3502  return IsLiteralInt(lit, u32);
   3503 }
   3504 
   3505 static const int32_t NoMask = -1;
   3506 
   3507 template <typename Unit>
   3508 static bool CheckArrayAccess(FunctionValidator<Unit>& f, ParseNode* viewName,
   3509                             ParseNode* indexExpr, Scalar::Type* viewType) {
   3510  if (!viewName->isKind(ParseNodeKind::Name)) {
   3511    return f.fail(viewName,
   3512                  "base of array access must be a typed array view name");
   3513  }
   3514 
   3515  const ModuleValidatorShared::Global* global =
   3516      f.lookupGlobal(viewName->as<NameNode>().name());
   3517  if (!global || global->which() != ModuleValidatorShared::Global::ArrayView) {
   3518    return f.fail(viewName,
   3519                  "base of array access must be a typed array view name");
   3520  }
   3521 
   3522  *viewType = global->viewType();
   3523 
   3524  uint32_t index;
   3525  if (IsLiteralOrConstInt(f, indexExpr, &index)) {
   3526    uint64_t byteOffset = uint64_t(index) << TypedArrayShift(*viewType);
   3527    uint64_t width = TypedArrayElemSize(*viewType);
   3528    if (!f.m().tryConstantAccess(byteOffset, width)) {
   3529      return f.fail(indexExpr, "constant index out of range");
   3530    }
   3531 
   3532    return f.writeInt32Lit(byteOffset);
   3533  }
   3534 
   3535  // Mask off the low bits to account for the clearing effect of a right shift
   3536  // followed by the left shift implicit in the array access. E.g., H32[i>>2]
   3537  // loses the low two bits.
   3538  int32_t mask = ~(TypedArrayElemSize(*viewType) - 1);
   3539 
   3540  if (indexExpr->isKind(ParseNodeKind::RshExpr)) {
   3541    ParseNode* shiftAmountNode = BitwiseRight(indexExpr);
   3542 
   3543    uint32_t shift;
   3544    if (!IsLiteralInt(f.m(), shiftAmountNode, &shift)) {
   3545      return f.failf(shiftAmountNode, "shift amount must be constant");
   3546    }
   3547 
   3548    unsigned requiredShift = TypedArrayShift(*viewType);
   3549    if (shift != requiredShift) {
   3550      return f.failf(shiftAmountNode, "shift amount must be %u", requiredShift);
   3551    }
   3552 
   3553    ParseNode* pointerNode = BitwiseLeft(indexExpr);
   3554 
   3555    Type pointerType;
   3556    if (!CheckExpr(f, pointerNode, &pointerType)) {
   3557      return false;
   3558    }
   3559 
   3560    if (!pointerType.isIntish()) {
   3561      return f.failf(pointerNode, "%s is not a subtype of int",
   3562                     pointerType.toChars());
   3563    }
   3564  } else {
   3565    // For legacy scalar access compatibility, accept Int8/Uint8 accesses
   3566    // with no shift.
   3567    if (TypedArrayShift(*viewType) != 0) {
   3568      return f.fail(
   3569          indexExpr,
   3570          "index expression isn't shifted; must be an Int8/Uint8 access");
   3571    }
   3572 
   3573    MOZ_ASSERT(mask == NoMask);
   3574 
   3575    ParseNode* pointerNode = indexExpr;
   3576 
   3577    Type pointerType;
   3578    if (!CheckExpr(f, pointerNode, &pointerType)) {
   3579      return false;
   3580    }
   3581    if (!pointerType.isInt()) {
   3582      return f.failf(pointerNode, "%s is not a subtype of int",
   3583                     pointerType.toChars());
   3584    }
   3585  }
   3586 
   3587  // Don't generate the mask op if there is no need for it which could happen
   3588  // for a shift of zero.
   3589  if (mask != NoMask) {
   3590    return f.writeInt32Lit(mask) && f.encoder().writeOp(Op::I32And);
   3591  }
   3592 
   3593  return true;
   3594 }
   3595 
   3596 static bool WriteArrayAccessFlags(FunctionValidatorShared& f,
   3597                                  Scalar::Type viewType) {
   3598  // asm.js only has naturally-aligned accesses.
   3599  size_t align = TypedArrayElemSize(viewType);
   3600  MOZ_ASSERT(IsPowerOfTwo(align));
   3601  if (!f.encoder().writeFixedU8(CeilingLog2(align))) {
   3602    return false;
   3603  }
   3604 
   3605  // asm.js doesn't have constant offsets, so just encode a 0.
   3606  return f.encoder().writeVarU32(0);
   3607 }
   3608 
   3609 template <typename Unit>
   3610 static bool CheckLoadArray(FunctionValidator<Unit>& f, ParseNode* elem,
   3611                           Type* type) {
   3612  Scalar::Type viewType;
   3613 
   3614  if (!CheckArrayAccess(f, ElemBase(elem), ElemIndex(elem), &viewType)) {
   3615    return false;
   3616  }
   3617 
   3618  switch (viewType) {
   3619    case Scalar::Int8:
   3620      if (!f.encoder().writeOp(Op::I32Load8S)) return false;
   3621      break;
   3622    case Scalar::Uint8:
   3623      if (!f.encoder().writeOp(Op::I32Load8U)) return false;
   3624      break;
   3625    case Scalar::Int16:
   3626      if (!f.encoder().writeOp(Op::I32Load16S)) return false;
   3627      break;
   3628    case Scalar::Uint16:
   3629      if (!f.encoder().writeOp(Op::I32Load16U)) return false;
   3630      break;
   3631    case Scalar::Uint32:
   3632    case Scalar::Int32:
   3633      if (!f.encoder().writeOp(Op::I32Load)) return false;
   3634      break;
   3635    case Scalar::Float32:
   3636      if (!f.encoder().writeOp(Op::F32Load)) return false;
   3637      break;
   3638    case Scalar::Float64:
   3639      if (!f.encoder().writeOp(Op::F64Load)) return false;
   3640      break;
   3641    default:
   3642      MOZ_CRASH("unexpected scalar type");
   3643  }
   3644 
   3645  switch (viewType) {
   3646    case Scalar::Int8:
   3647    case Scalar::Int16:
   3648    case Scalar::Int32:
   3649    case Scalar::Uint8:
   3650    case Scalar::Uint16:
   3651    case Scalar::Uint32:
   3652      *type = Type::Intish;
   3653      break;
   3654    case Scalar::Float32:
   3655      *type = Type::MaybeFloat;
   3656      break;
   3657    case Scalar::Float64:
   3658      *type = Type::MaybeDouble;
   3659      break;
   3660    default:
   3661      MOZ_CRASH("Unexpected array type");
   3662  }
   3663 
   3664  return WriteArrayAccessFlags(f, viewType);
   3665 }
   3666 
   3667 template <typename Unit>
   3668 static bool CheckStoreArray(FunctionValidator<Unit>& f, ParseNode* lhs,
   3669                            ParseNode* rhs, Type* type) {
   3670  Scalar::Type viewType;
   3671  if (!CheckArrayAccess(f, ElemBase(lhs), ElemIndex(lhs), &viewType)) {
   3672    return false;
   3673  }
   3674 
   3675  Type rhsType;
   3676  if (!CheckExpr(f, rhs, &rhsType)) {
   3677    return false;
   3678  }
   3679 
   3680  switch (viewType) {
   3681    case Scalar::Int8:
   3682    case Scalar::Int16:
   3683    case Scalar::Int32:
   3684    case Scalar::Uint8:
   3685    case Scalar::Uint16:
   3686    case Scalar::Uint32:
   3687      if (!rhsType.isIntish()) {
   3688        return f.failf(lhs, "%s is not a subtype of intish", rhsType.toChars());
   3689      }
   3690      break;
   3691    case Scalar::Float32:
   3692      if (!rhsType.isMaybeDouble() && !rhsType.isFloatish()) {
   3693        return f.failf(lhs, "%s is not a subtype of double? or floatish",
   3694                       rhsType.toChars());
   3695      }
   3696      break;
   3697    case Scalar::Float64:
   3698      if (!rhsType.isMaybeFloat() && !rhsType.isMaybeDouble()) {
   3699        return f.failf(lhs, "%s is not a subtype of float? or double?",
   3700                       rhsType.toChars());
   3701      }
   3702      break;
   3703    default:
   3704      MOZ_CRASH("Unexpected view type");
   3705  }
   3706 
   3707  switch (viewType) {
   3708    case Scalar::Int8:
   3709    case Scalar::Uint8:
   3710      if (!f.encoder().writeOp(MozOp::I32TeeStore8)) {
   3711        return false;
   3712      }
   3713      break;
   3714    case Scalar::Int16:
   3715    case Scalar::Uint16:
   3716      if (!f.encoder().writeOp(MozOp::I32TeeStore16)) {
   3717        return false;
   3718      }
   3719      break;
   3720    case Scalar::Int32:
   3721    case Scalar::Uint32:
   3722      if (!f.encoder().writeOp(MozOp::I32TeeStore)) {
   3723        return false;
   3724      }
   3725      break;
   3726    case Scalar::Float32:
   3727      if (rhsType.isFloatish()) {
   3728        if (!f.encoder().writeOp(MozOp::F32TeeStore)) {
   3729          return false;
   3730        }
   3731      } else {
   3732        if (!f.encoder().writeOp(MozOp::F64TeeStoreF32)) {
   3733          return false;
   3734        }
   3735      }
   3736      break;
   3737    case Scalar::Float64:
   3738      if (rhsType.isFloatish()) {
   3739        if (!f.encoder().writeOp(MozOp::F32TeeStoreF64)) {
   3740          return false;
   3741        }
   3742      } else {
   3743        if (!f.encoder().writeOp(MozOp::F64TeeStore)) {
   3744          return false;
   3745        }
   3746      }
   3747      break;
   3748    default:
   3749      MOZ_CRASH("unexpected scalar type");
   3750  }
   3751 
   3752  if (!WriteArrayAccessFlags(f, viewType)) {
   3753    return false;
   3754  }
   3755 
   3756  *type = rhsType;
   3757  return true;
   3758 }
   3759 
   3760 template <typename Unit>
   3761 static bool CheckAssignName(FunctionValidator<Unit>& f, ParseNode* lhs,
   3762                            ParseNode* rhs, Type* type) {
   3763  TaggedParserAtomIndex name = lhs->as<NameNode>().name();
   3764 
   3765  if (const FunctionValidatorShared::Local* lhsVar = f.lookupLocal(name)) {
   3766    Type rhsType;
   3767    if (!CheckExpr(f, rhs, &rhsType)) {
   3768      return false;
   3769    }
   3770 
   3771    if (!f.encoder().writeOp(Op::LocalTee)) {
   3772      return false;
   3773    }
   3774    if (!f.encoder().writeVarU32(lhsVar->slot)) {
   3775      return false;
   3776    }
   3777 
   3778    if (!(rhsType <= lhsVar->type)) {
   3779      return f.failf(lhs, "%s is not a subtype of %s", rhsType.toChars(),
   3780                     lhsVar->type.toChars());
   3781    }
   3782    *type = rhsType;
   3783    return true;
   3784  }
   3785 
   3786  if (const ModuleValidatorShared::Global* global = f.lookupGlobal(name)) {
   3787    if (global->which() != ModuleValidatorShared::Global::Variable) {
   3788      return f.failName(lhs, "'%s' is not a mutable variable", name);
   3789    }
   3790 
   3791    Type rhsType;
   3792    if (!CheckExpr(f, rhs, &rhsType)) {
   3793      return false;
   3794    }
   3795 
   3796    Type globType = global->varOrConstType();
   3797    if (!(rhsType <= globType)) {
   3798      return f.failf(lhs, "%s is not a subtype of %s", rhsType.toChars(),
   3799                     globType.toChars());
   3800    }
   3801    if (!f.encoder().writeOp(MozOp::TeeGlobal)) {
   3802      return false;
   3803    }
   3804    if (!f.encoder().writeVarU32(global->varOrConstIndex())) {
   3805      return false;
   3806    }
   3807 
   3808    *type = rhsType;
   3809    return true;
   3810  }
   3811 
   3812  return f.failName(lhs, "'%s' not found in local or asm.js module scope",
   3813                    name);
   3814 }
   3815 
   3816 template <typename Unit>
   3817 static bool CheckAssign(FunctionValidator<Unit>& f, ParseNode* assign,
   3818                        Type* type) {
   3819  MOZ_ASSERT(assign->isKind(ParseNodeKind::AssignExpr));
   3820 
   3821  ParseNode* lhs = BinaryLeft(assign);
   3822  ParseNode* rhs = BinaryRight(assign);
   3823 
   3824  if (lhs->getKind() == ParseNodeKind::ElemExpr) {
   3825    return CheckStoreArray(f, lhs, rhs, type);
   3826  }
   3827 
   3828  if (lhs->getKind() == ParseNodeKind::Name) {
   3829    return CheckAssignName(f, lhs, rhs, type);
   3830  }
   3831 
   3832  return f.fail(
   3833      assign,
   3834      "left-hand side of assignment must be a variable or array access");
   3835 }
   3836 
   3837 template <typename Unit>
   3838 static bool CheckMathIMul(FunctionValidator<Unit>& f, ParseNode* call,
   3839                          Type* type) {
   3840  if (CallArgListLength(call) != 2) {
   3841    return f.fail(call, "Math.imul must be passed 2 arguments");
   3842  }
   3843 
   3844  ParseNode* lhs = CallArgList(call);
   3845  ParseNode* rhs = NextNode(lhs);
   3846 
   3847  Type lhsType;
   3848  if (!CheckExpr(f, lhs, &lhsType)) {
   3849    return false;
   3850  }
   3851 
   3852  Type rhsType;
   3853  if (!CheckExpr(f, rhs, &rhsType)) {
   3854    return false;
   3855  }
   3856 
   3857  if (!lhsType.isIntish()) {
   3858    return f.failf(lhs, "%s is not a subtype of intish", lhsType.toChars());
   3859  }
   3860  if (!rhsType.isIntish()) {
   3861    return f.failf(rhs, "%s is not a subtype of intish", rhsType.toChars());
   3862  }
   3863 
   3864  *type = Type::Signed;
   3865  return f.encoder().writeOp(Op::I32Mul);
   3866 }
   3867 
   3868 template <typename Unit>
   3869 static bool CheckMathClz32(FunctionValidator<Unit>& f, ParseNode* call,
   3870                           Type* type) {
   3871  if (CallArgListLength(call) != 1) {
   3872    return f.fail(call, "Math.clz32 must be passed 1 argument");
   3873  }
   3874 
   3875  ParseNode* arg = CallArgList(call);
   3876 
   3877  Type argType;
   3878  if (!CheckExpr(f, arg, &argType)) {
   3879    return false;
   3880  }
   3881 
   3882  if (!argType.isIntish()) {
   3883    return f.failf(arg, "%s is not a subtype of intish", argType.toChars());
   3884  }
   3885 
   3886  *type = Type::Fixnum;
   3887  return f.encoder().writeOp(Op::I32Clz);
   3888 }
   3889 
   3890 template <typename Unit>
   3891 static bool CheckMathAbs(FunctionValidator<Unit>& f, ParseNode* call,
   3892                         Type* type) {
   3893  if (CallArgListLength(call) != 1) {
   3894    return f.fail(call, "Math.abs must be passed 1 argument");
   3895  }
   3896 
   3897  ParseNode* arg = CallArgList(call);
   3898 
   3899  Type argType;
   3900  if (!CheckExpr(f, arg, &argType)) {
   3901    return false;
   3902  }
   3903 
   3904  if (argType.isSigned()) {
   3905    *type = Type::Unsigned;
   3906    return f.encoder().writeOp(MozOp::I32Abs);
   3907  }
   3908 
   3909  if (argType.isMaybeDouble()) {
   3910    *type = Type::Double;
   3911    return f.encoder().writeOp(Op::F64Abs);
   3912  }
   3913 
   3914  if (argType.isMaybeFloat()) {
   3915    *type = Type::Floatish;
   3916    return f.encoder().writeOp(Op::F32Abs);
   3917  }
   3918 
   3919  return f.failf(call, "%s is not a subtype of signed, float? or double?",
   3920                 argType.toChars());
   3921 }
   3922 
   3923 template <typename Unit>
   3924 static bool CheckMathSqrt(FunctionValidator<Unit>& f, ParseNode* call,
   3925                          Type* type) {
   3926  if (CallArgListLength(call) != 1) {
   3927    return f.fail(call, "Math.sqrt must be passed 1 argument");
   3928  }
   3929 
   3930  ParseNode* arg = CallArgList(call);
   3931 
   3932  Type argType;
   3933  if (!CheckExpr(f, arg, &argType)) {
   3934    return false;
   3935  }
   3936 
   3937  if (argType.isMaybeDouble()) {
   3938    *type = Type::Double;
   3939    return f.encoder().writeOp(Op::F64Sqrt);
   3940  }
   3941 
   3942  if (argType.isMaybeFloat()) {
   3943    *type = Type::Floatish;
   3944    return f.encoder().writeOp(Op::F32Sqrt);
   3945  }
   3946 
   3947  return f.failf(call, "%s is neither a subtype of double? nor float?",
   3948                 argType.toChars());
   3949 }
   3950 
   3951 template <typename Unit>
   3952 static bool CheckMathMinMax(FunctionValidator<Unit>& f, ParseNode* callNode,
   3953                            bool isMax, Type* type) {
   3954  if (CallArgListLength(callNode) < 2) {
   3955    return f.fail(callNode, "Math.min/max must be passed at least 2 arguments");
   3956  }
   3957 
   3958  ParseNode* firstArg = CallArgList(callNode);
   3959  Type firstType;
   3960  if (!CheckExpr(f, firstArg, &firstType)) {
   3961    return false;
   3962  }
   3963 
   3964  Op op = Op::Limit;
   3965  MozOp mozOp = MozOp::Limit;
   3966  if (firstType.isMaybeDouble()) {
   3967    *type = Type::Double;
   3968    firstType = Type::MaybeDouble;
   3969    op = isMax ? Op::F64Max : Op::F64Min;
   3970  } else if (firstType.isMaybeFloat()) {
   3971    *type = Type::Float;
   3972    firstType = Type::MaybeFloat;
   3973    op = isMax ? Op::F32Max : Op::F32Min;
   3974  } else if (firstType.isSigned()) {
   3975    *type = Type::Signed;
   3976    firstType = Type::Signed;
   3977    mozOp = isMax ? MozOp::I32Max : MozOp::I32Min;
   3978  } else {
   3979    return f.failf(firstArg, "%s is not a subtype of double?, float? or signed",
   3980                   firstType.toChars());
   3981  }
   3982 
   3983  unsigned numArgs = CallArgListLength(callNode);
   3984  ParseNode* nextArg = NextNode(firstArg);
   3985  for (unsigned i = 1; i < numArgs; i++, nextArg = NextNode(nextArg)) {
   3986    Type nextType;
   3987    if (!CheckExpr(f, nextArg, &nextType)) {
   3988      return false;
   3989    }
   3990    if (!(nextType <= firstType)) {
   3991      return f.failf(nextArg, "%s is not a subtype of %s", nextType.toChars(),
   3992                     firstType.toChars());
   3993    }
   3994 
   3995    if (op != Op::Limit) {
   3996      if (!f.encoder().writeOp(op)) {
   3997        return false;
   3998      }
   3999    } else {
   4000      if (!f.encoder().writeOp(mozOp)) {
   4001        return false;
   4002      }
   4003    }
   4004  }
   4005 
   4006  return true;
   4007 }
   4008 
   4009 using CheckArgType = bool (*)(FunctionValidatorShared& f, ParseNode* argNode,
   4010                              Type type);
   4011 
   4012 template <CheckArgType checkArg, typename Unit>
   4013 static bool CheckCallArgs(FunctionValidator<Unit>& f, ParseNode* callNode,
   4014                          ValTypeVector* args) {
   4015  ParseNode* argNode = CallArgList(callNode);
   4016  for (unsigned i = 0; i < CallArgListLength(callNode);
   4017       i++, argNode = NextNode(argNode)) {
   4018    Type type;
   4019    if (!CheckExpr(f, argNode, &type)) {
   4020      return false;
   4021    }
   4022 
   4023    if (!checkArg(f, argNode, type)) {
   4024      return false;
   4025    }
   4026 
   4027    if (!args->append(Type::canonicalize(type).canonicalToValType())) {
   4028      return false;
   4029    }
   4030  }
   4031  if (args->length() > MaxParams) {
   4032    return f.fail(callNode, "too many parameters");
   4033  }
   4034  return true;
   4035 }
   4036 
   4037 static bool CheckSignatureAgainstExisting(ModuleValidatorShared& m,
   4038                                          ParseNode* usepn, const FuncType& sig,
   4039                                          const FuncType& existing) {
   4040  if (!FuncType::strictlyEquals(sig, existing)) {
   4041    return m.failf(usepn, "incompatible argument types to function");
   4042  }
   4043  return true;
   4044 }
   4045 
   4046 template <typename Unit>
   4047 static bool CheckFunctionSignature(ModuleValidator<Unit>& m, ParseNode* usepn,
   4048                                   FuncType&& sig, TaggedParserAtomIndex name,
   4049                                   ModuleValidatorShared::Func** func) {
   4050  ModuleValidatorShared::Func* existing = m.lookupFuncDef(name);
   4051  if (!existing) {
   4052    if (!CheckModuleLevelName(m, usepn, name)) {
   4053      return false;
   4054    }
   4055    return m.addFuncDef(name, usepn->pn_pos.begin, std::move(sig), func);
   4056  }
   4057 
   4058  const FuncType& existingSig =
   4059      m.codeMeta()->types->type(existing->sigIndex()).funcType();
   4060 
   4061  if (!CheckSignatureAgainstExisting(m, usepn, sig, existingSig)) {
   4062    return false;
   4063  }
   4064 
   4065  *func = existing;
   4066  return true;
   4067 }
   4068 
   4069 static bool CheckIsArgType(FunctionValidatorShared& f, ParseNode* argNode,
   4070                           Type type) {
   4071  if (!type.isArgType()) {
   4072    return f.failf(argNode, "%s is not a subtype of int, float, or double",
   4073                   type.toChars());
   4074  }
   4075  return true;
   4076 }
   4077 
   4078 template <typename Unit>
   4079 static bool CheckInternalCall(FunctionValidator<Unit>& f, ParseNode* callNode,
   4080                              TaggedParserAtomIndex calleeName, Type ret,
   4081                              Type* type) {
   4082  MOZ_ASSERT(ret.isCanonical());
   4083 
   4084  ValTypeVector args;
   4085  if (!CheckCallArgs<CheckIsArgType>(f, callNode, &args)) {
   4086    return false;
   4087  }
   4088 
   4089  ValTypeVector results;
   4090  Maybe<ValType> retType = ret.canonicalToReturnType();
   4091  if (retType && !results.append(retType.ref())) {
   4092    return false;
   4093  }
   4094 
   4095  FuncType sig(std::move(args), std::move(results));
   4096 
   4097  ModuleValidatorShared::Func* callee;
   4098  if (!CheckFunctionSignature(f.m(), callNode, std::move(sig), calleeName,
   4099                              &callee)) {
   4100    return false;
   4101  }
   4102 
   4103  if (!f.writeCall(callNode, MozOp::OldCallDirect)) {
   4104    return false;
   4105  }
   4106 
   4107  if (!f.encoder().writeVarU32(callee->funcDefIndex())) {
   4108    return false;
   4109  }
   4110 
   4111  *type = Type::ret(ret);
   4112  return true;
   4113 }
   4114 
   4115 template <typename Unit>
   4116 static bool CheckFuncPtrTableAgainstExisting(ModuleValidator<Unit>& m,
   4117                                             ParseNode* usepn,
   4118                                             TaggedParserAtomIndex name,
   4119                                             FuncType&& sig, unsigned mask,
   4120                                             uint32_t* tableIndex) {
   4121  if (const ModuleValidatorShared::Global* existing = m.lookupGlobal(name)) {
   4122    if (existing->which() != ModuleValidatorShared::Global::Table) {
   4123      return m.failName(usepn, "'%s' is not a function-pointer table", name);
   4124    }
   4125 
   4126    ModuleValidatorShared::Table& table = m.table(existing->tableIndex());
   4127    if (mask != table.mask()) {
   4128      return m.failf(usepn, "mask does not match previous value (%u)",
   4129                     table.mask());
   4130    }
   4131 
   4132    if (!CheckSignatureAgainstExisting(
   4133            m, usepn, sig,
   4134            m.codeMeta()->types->type(table.sigIndex()).funcType())) {
   4135      return false;
   4136    }
   4137 
   4138    *tableIndex = existing->tableIndex();
   4139    return true;
   4140  }
   4141 
   4142  if (!CheckModuleLevelName(m, usepn, name)) {
   4143    return false;
   4144  }
   4145 
   4146  return m.declareFuncPtrTable(std::move(sig), name, usepn->pn_pos.begin, mask,
   4147                               tableIndex);
   4148 }
   4149 
   4150 template <typename Unit>
   4151 static bool CheckFuncPtrCall(FunctionValidator<Unit>& f, ParseNode* callNode,
   4152                             Type ret, Type* type) {
   4153  MOZ_ASSERT(ret.isCanonical());
   4154 
   4155  ParseNode* callee = CallCallee(callNode);
   4156  ParseNode* tableNode = ElemBase(callee);
   4157  ParseNode* indexExpr = ElemIndex(callee);
   4158 
   4159  if (!tableNode->isKind(ParseNodeKind::Name)) {
   4160    return f.fail(tableNode, "expecting name of function-pointer array");
   4161  }
   4162 
   4163  TaggedParserAtomIndex name = tableNode->as<NameNode>().name();
   4164  if (const ModuleValidatorShared::Global* existing = f.lookupGlobal(name)) {
   4165    if (existing->which() != ModuleValidatorShared::Global::Table) {
   4166      return f.failName(
   4167          tableNode, "'%s' is not the name of a function-pointer array", name);
   4168    }
   4169  }
   4170 
   4171  if (!indexExpr->isKind(ParseNodeKind::BitAndExpr)) {
   4172    return f.fail(indexExpr,
   4173                  "function-pointer table index expression needs & mask");
   4174  }
   4175 
   4176  ParseNode* indexNode = BitwiseLeft(indexExpr);
   4177  ParseNode* maskNode = BitwiseRight(indexExpr);
   4178 
   4179  uint32_t mask;
   4180  if (!IsLiteralInt(f.m(), maskNode, &mask) || mask == UINT32_MAX ||
   4181      !IsPowerOfTwo(mask + 1)) {
   4182    return f.fail(maskNode,
   4183                  "function-pointer table index mask value must be a power of "
   4184                  "two minus 1");
   4185  }
   4186 
   4187  Type indexType;
   4188  if (!CheckExpr(f, indexNode, &indexType)) {
   4189    return false;
   4190  }
   4191 
   4192  if (!indexType.isIntish()) {
   4193    return f.failf(indexNode, "%s is not a subtype of intish",
   4194                   indexType.toChars());
   4195  }
   4196 
   4197  ValTypeVector args;
   4198  if (!CheckCallArgs<CheckIsArgType>(f, callNode, &args)) {
   4199    return false;
   4200  }
   4201 
   4202  ValTypeVector results;
   4203  Maybe<ValType> retType = ret.canonicalToReturnType();
   4204  if (retType && !results.append(retType.ref())) {
   4205    return false;
   4206  }
   4207 
   4208  FuncType sig(std::move(args), std::move(results));
   4209 
   4210  uint32_t tableIndex;
   4211  if (!CheckFuncPtrTableAgainstExisting(f.m(), tableNode, name, std::move(sig),
   4212                                        mask, &tableIndex)) {
   4213    return false;
   4214  }
   4215 
   4216  if (!f.writeCall(callNode, MozOp::OldCallIndirect)) {
   4217    return false;
   4218  }
   4219 
   4220  // Call signature
   4221  if (!f.encoder().writeVarU32(f.m().table(tableIndex).sigIndex())) {
   4222    return false;
   4223  }
   4224 
   4225  *type = Type::ret(ret);
   4226  return true;
   4227 }
   4228 
   4229 static bool CheckIsExternType(FunctionValidatorShared& f, ParseNode* argNode,
   4230                              Type type) {
   4231  if (!type.isExtern()) {
   4232    return f.failf(argNode, "%s is not a subtype of extern", type.toChars());
   4233  }
   4234  return true;
   4235 }
   4236 
   4237 template <typename Unit>
   4238 static bool CheckFFICall(FunctionValidator<Unit>& f, ParseNode* callNode,
   4239                         unsigned ffiIndex, Type ret, Type* type) {
   4240  MOZ_ASSERT(ret.isCanonical());
   4241 
   4242  TaggedParserAtomIndex calleeName =
   4243      CallCallee(callNode)->as<NameNode>().name();
   4244 
   4245  if (ret.isFloat()) {
   4246    return f.fail(callNode, "FFI calls can't return float");
   4247  }
   4248 
   4249  ValTypeVector args;
   4250  if (!CheckCallArgs<CheckIsExternType>(f, callNode, &args)) {
   4251    return false;
   4252  }
   4253 
   4254  ValTypeVector results;
   4255  Maybe<ValType> retType = ret.canonicalToReturnType();
   4256  if (retType && !results.append(retType.ref())) {
   4257    return false;
   4258  }
   4259 
   4260  FuncType sig(std::move(args), std::move(results));
   4261 
   4262  uint32_t importIndex;
   4263  if (!f.m().declareImport(calleeName, std::move(sig), ffiIndex,
   4264                           &importIndex)) {
   4265    return false;
   4266  }
   4267 
   4268  if (!f.writeCall(callNode, Op::Call)) {
   4269    return false;
   4270  }
   4271 
   4272  if (!f.encoder().writeVarU32(importIndex)) {
   4273    return false;
   4274  }
   4275 
   4276  *type = Type::ret(ret);
   4277  return true;
   4278 }
   4279 
   4280 static bool CheckFloatCoercionArg(FunctionValidatorShared& f,
   4281                                  ParseNode* inputNode, Type inputType) {
   4282  if (inputType.isMaybeDouble()) {
   4283    return f.encoder().writeOp(Op::F32DemoteF64);
   4284  }
   4285  if (inputType.isSigned()) {
   4286    return f.encoder().writeOp(Op::F32ConvertI32S);
   4287  }
   4288  if (inputType.isUnsigned()) {
   4289    return f.encoder().writeOp(Op::F32ConvertI32U);
   4290  }
   4291  if (inputType.isFloatish()) {
   4292    return true;
   4293  }
   4294 
   4295  return f.failf(inputNode,
   4296                 "%s is not a subtype of signed, unsigned, double? or floatish",
   4297                 inputType.toChars());
   4298 }
   4299 
   4300 template <typename Unit>
   4301 static bool CheckCoercedCall(FunctionValidator<Unit>& f, ParseNode* call,
   4302                             Type ret, Type* type);
   4303 
   4304 template <typename Unit>
   4305 static bool CheckCoercionArg(FunctionValidator<Unit>& f, ParseNode* arg,
   4306                             Type expected, Type* type) {
   4307  MOZ_ASSERT(expected.isCanonicalValType());
   4308 
   4309  if (arg->isKind(ParseNodeKind::CallExpr)) {
   4310    return CheckCoercedCall(f, arg, expected, type);
   4311  }
   4312 
   4313  Type argType;
   4314  if (!CheckExpr(f, arg, &argType)) {
   4315    return false;
   4316  }
   4317 
   4318  if (expected.isFloat()) {
   4319    if (!CheckFloatCoercionArg(f, arg, argType)) {
   4320      return false;
   4321    }
   4322  } else {
   4323    MOZ_CRASH("not call coercions");
   4324  }
   4325 
   4326  *type = Type::ret(expected);
   4327  return true;
   4328 }
   4329 
   4330 template <typename Unit>
   4331 static bool CheckMathFRound(FunctionValidator<Unit>& f, ParseNode* callNode,
   4332                            Type* type) {
   4333  if (CallArgListLength(callNode) != 1) {
   4334    return f.fail(callNode, "Math.fround must be passed 1 argument");
   4335  }
   4336 
   4337  ParseNode* argNode = CallArgList(callNode);
   4338  Type argType;
   4339  if (!CheckCoercionArg(f, argNode, Type::Float, &argType)) {
   4340    return false;
   4341  }
   4342 
   4343  MOZ_ASSERT(argType == Type::Float);
   4344  *type = Type::Float;
   4345  return true;
   4346 }
   4347 
   4348 template <typename Unit>
   4349 static bool CheckMathBuiltinCall(FunctionValidator<Unit>& f,
   4350                                 ParseNode* callNode,
   4351                                 AsmJSMathBuiltinFunction func, Type* type) {
   4352  unsigned arity = 0;
   4353  Op f32 = Op::Limit;
   4354  Op f64 = Op::Limit;
   4355  MozOp mozf64 = MozOp::Limit;
   4356  switch (func) {
   4357    case AsmJSMathBuiltin_imul:
   4358      return CheckMathIMul(f, callNode, type);
   4359    case AsmJSMathBuiltin_clz32:
   4360      return CheckMathClz32(f, callNode, type);
   4361    case AsmJSMathBuiltin_abs:
   4362      return CheckMathAbs(f, callNode, type);
   4363    case AsmJSMathBuiltin_sqrt:
   4364      return CheckMathSqrt(f, callNode, type);
   4365    case AsmJSMathBuiltin_fround:
   4366      return CheckMathFRound(f, callNode, type);
   4367    case AsmJSMathBuiltin_min:
   4368      return CheckMathMinMax(f, callNode, /* isMax = */ false, type);
   4369    case AsmJSMathBuiltin_max:
   4370      return CheckMathMinMax(f, callNode, /* isMax = */ true, type);
   4371    case AsmJSMathBuiltin_ceil:
   4372      arity = 1;
   4373      f64 = Op::F64Ceil;
   4374      f32 = Op::F32Ceil;
   4375      break;
   4376    case AsmJSMathBuiltin_floor:
   4377      arity = 1;
   4378      f64 = Op::F64Floor;
   4379      f32 = Op::F32Floor;
   4380      break;
   4381    case AsmJSMathBuiltin_sin:
   4382      arity = 1;
   4383      if (!f.m().alwaysUseFdlibm()) {
   4384        mozf64 = MozOp::F64SinNative;
   4385      } else {
   4386        mozf64 = MozOp::F64SinFdlibm;
   4387      }
   4388      f32 = Op::Unreachable;
   4389      break;
   4390    case AsmJSMathBuiltin_cos:
   4391      arity = 1;
   4392      if (!f.m().alwaysUseFdlibm()) {
   4393        mozf64 = MozOp::F64CosNative;
   4394      } else {
   4395        mozf64 = MozOp::F64CosFdlibm;
   4396      }
   4397      f32 = Op::Unreachable;
   4398      break;
   4399    case AsmJSMathBuiltin_tan:
   4400      arity = 1;
   4401      if (!f.m().alwaysUseFdlibm()) {
   4402        mozf64 = MozOp::F64TanNative;
   4403      } else {
   4404        mozf64 = MozOp::F64TanFdlibm;
   4405      }
   4406      f32 = Op::Unreachable;
   4407      break;
   4408    case AsmJSMathBuiltin_asin:
   4409      arity = 1;
   4410      mozf64 = MozOp::F64Asin;
   4411      f32 = Op::Unreachable;
   4412      break;
   4413    case AsmJSMathBuiltin_acos:
   4414      arity = 1;
   4415      mozf64 = MozOp::F64Acos;
   4416      f32 = Op::Unreachable;
   4417      break;
   4418    case AsmJSMathBuiltin_atan:
   4419      arity = 1;
   4420      mozf64 = MozOp::F64Atan;
   4421      f32 = Op::Unreachable;
   4422      break;
   4423    case AsmJSMathBuiltin_exp:
   4424      arity = 1;
   4425      mozf64 = MozOp::F64Exp;
   4426      f32 = Op::Unreachable;
   4427      break;
   4428    case AsmJSMathBuiltin_log:
   4429      arity = 1;
   4430      mozf64 = MozOp::F64Log;
   4431      f32 = Op::Unreachable;
   4432      break;
   4433    case AsmJSMathBuiltin_pow:
   4434      arity = 2;
   4435      mozf64 = MozOp::F64Pow;
   4436      f32 = Op::Unreachable;
   4437      break;
   4438    case AsmJSMathBuiltin_atan2:
   4439      arity = 2;
   4440      mozf64 = MozOp::F64Atan2;
   4441      f32 = Op::Unreachable;
   4442      break;
   4443    default:
   4444      MOZ_CRASH("unexpected mathBuiltin function");
   4445  }
   4446 
   4447  unsigned actualArity = CallArgListLength(callNode);
   4448  if (actualArity != arity) {
   4449    return f.failf(callNode, "call passed %u arguments, expected %u",
   4450                   actualArity, arity);
   4451  }
   4452 
   4453  if (!f.prepareCall(callNode)) {
   4454    return false;
   4455  }
   4456 
   4457  Type firstType;
   4458  ParseNode* argNode = CallArgList(callNode);
   4459  if (!CheckExpr(f, argNode, &firstType)) {
   4460    return false;
   4461  }
   4462 
   4463  if (!firstType.isMaybeFloat() && !firstType.isMaybeDouble()) {
   4464    return f.fail(
   4465        argNode,
   4466        "arguments to math call should be a subtype of double? or float?");
   4467  }
   4468 
   4469  bool opIsDouble = firstType.isMaybeDouble();
   4470  if (!opIsDouble && f32 == Op::Unreachable) {
   4471    return f.fail(callNode, "math builtin cannot be used as float");
   4472  }
   4473 
   4474  if (arity == 2) {
   4475    Type secondType;
   4476    argNode = NextNode(argNode);
   4477    if (!CheckExpr(f, argNode, &secondType)) {
   4478      return false;
   4479    }
   4480 
   4481    if (firstType.isMaybeDouble() && !secondType.isMaybeDouble()) {
   4482      return f.fail(
   4483          argNode,
   4484          "both arguments to math builtin call should be the same type");
   4485    }
   4486    if (firstType.isMaybeFloat() && !secondType.isMaybeFloat()) {
   4487      return f.fail(
   4488          argNode,
   4489          "both arguments to math builtin call should be the same type");
   4490    }
   4491  }
   4492 
   4493  if (opIsDouble) {
   4494    if (f64 != Op::Limit) {
   4495      if (!f.encoder().writeOp(f64)) {
   4496        return false;
   4497      }
   4498    } else {
   4499      if (!f.encoder().writeOp(mozf64)) {
   4500        return false;
   4501      }
   4502    }
   4503  } else {
   4504    if (!f.encoder().writeOp(f32)) {
   4505      return false;
   4506    }
   4507  }
   4508 
   4509  *type = opIsDouble ? Type::Double : Type::Floatish;
   4510  return true;
   4511 }
   4512 
   4513 template <typename Unit>
   4514 static bool CheckUncoercedCall(FunctionValidator<Unit>& f, ParseNode* expr,
   4515                               Type* type) {
   4516  MOZ_ASSERT(expr->isKind(ParseNodeKind::CallExpr));
   4517 
   4518  const ModuleValidatorShared::Global* global;
   4519  if (IsCallToGlobal(f.m(), expr, &global) && global->isMathFunction()) {
   4520    return CheckMathBuiltinCall(f, expr, global->mathBuiltinFunction(), type);
   4521  }
   4522 
   4523  return f.fail(
   4524      expr,
   4525      "all function calls must be calls to standard lib math functions,"
   4526      " ignored (via f(); or comma-expression), coerced to signed (via f()|0),"
   4527      " coerced to float (via fround(f())), or coerced to double (via +f())");
   4528 }
   4529 
   4530 static bool CoerceResult(FunctionValidatorShared& f, ParseNode* expr,
   4531                         Type expected, Type actual, Type* type) {
   4532  MOZ_ASSERT(expected.isCanonical());
   4533 
   4534  // At this point, the bytecode resembles this:
   4535  //      | the thing we wanted to coerce | current position |>
   4536  switch (expected.which()) {
   4537    case Type::Void:
   4538      if (!actual.isVoid()) {
   4539        if (!f.encoder().writeOp(Op::Drop)) {
   4540          return false;
   4541        }
   4542      }
   4543      break;
   4544    case Type::Int:
   4545      if (!actual.isIntish()) {
   4546        return f.failf(expr, "%s is not a subtype of intish", actual.toChars());
   4547      }
   4548      break;
   4549    case Type::Float:
   4550      if (!CheckFloatCoercionArg(f, expr, actual)) {
   4551        return false;
   4552      }
   4553      break;
   4554    case Type::Double:
   4555      if (actual.isMaybeDouble()) {
   4556        // No conversion necessary.
   4557      } else if (actual.isMaybeFloat()) {
   4558        if (!f.encoder().writeOp(Op::F64PromoteF32)) {
   4559          return false;
   4560        }
   4561      } else if (actual.isSigned()) {
   4562        if (!f.encoder().writeOp(Op::F64ConvertI32S)) {
   4563          return false;
   4564        }
   4565      } else if (actual.isUnsigned()) {
   4566        if (!f.encoder().writeOp(Op::F64ConvertI32U)) {
   4567          return false;
   4568        }
   4569      } else {
   4570        return f.failf(
   4571            expr, "%s is not a subtype of double?, float?, signed or unsigned",
   4572            actual.toChars());
   4573      }
   4574      break;
   4575    default:
   4576      MOZ_CRASH("unexpected uncoerced result type");
   4577  }
   4578 
   4579  *type = Type::ret(expected);
   4580  return true;
   4581 }
   4582 
   4583 template <typename Unit>
   4584 static bool CheckCoercedMathBuiltinCall(FunctionValidator<Unit>& f,
   4585                                        ParseNode* callNode,
   4586                                        AsmJSMathBuiltinFunction func, Type ret,
   4587                                        Type* type) {
   4588  Type actual;
   4589  if (!CheckMathBuiltinCall(f, callNode, func, &actual)) {
   4590    return false;
   4591  }
   4592  return CoerceResult(f, callNode, ret, actual, type);
   4593 }
   4594 
   4595 template <typename Unit>
   4596 static bool CheckCoercedCall(FunctionValidator<Unit>& f, ParseNode* call,
   4597                             Type ret, Type* type) {
   4598  MOZ_ASSERT(ret.isCanonical());
   4599 
   4600  AutoCheckRecursionLimit recursion(f.fc());
   4601  if (!recursion.checkDontReport(f.fc())) {
   4602    return f.m().failOverRecursed();
   4603  }
   4604 
   4605  if (IsNumericLiteral(f.m(), call)) {
   4606    NumLit lit = ExtractNumericLiteral(f.m(), call);
   4607    if (!f.writeConstExpr(lit)) {
   4608      return false;
   4609    }
   4610    return CoerceResult(f, call, ret, Type::lit(lit), type);
   4611  }
   4612 
   4613  ParseNode* callee = CallCallee(call);
   4614 
   4615  if (callee->isKind(ParseNodeKind::ElemExpr)) {
   4616    return CheckFuncPtrCall(f, call, ret, type);
   4617  }
   4618 
   4619  if (!callee->isKind(ParseNodeKind::Name)) {
   4620    return f.fail(callee, "unexpected callee expression type");
   4621  }
   4622 
   4623  TaggedParserAtomIndex calleeName = callee->as<NameNode>().name();
   4624 
   4625  if (const ModuleValidatorShared::Global* global =
   4626          f.lookupGlobal(calleeName)) {
   4627    switch (global->which()) {
   4628      case ModuleValidatorShared::Global::FFI:
   4629        return CheckFFICall(f, call, global->ffiIndex(), ret, type);
   4630      case ModuleValidatorShared::Global::MathBuiltinFunction:
   4631        return CheckCoercedMathBuiltinCall(
   4632            f, call, global->mathBuiltinFunction(), ret, type);
   4633      case ModuleValidatorShared::Global::ConstantLiteral:
   4634      case ModuleValidatorShared::Global::ConstantImport:
   4635      case ModuleValidatorShared::Global::Variable:
   4636      case ModuleValidatorShared::Global::Table:
   4637      case ModuleValidatorShared::Global::ArrayView:
   4638      case ModuleValidatorShared::Global::ArrayViewCtor:
   4639        return f.failName(callee, "'%s' is not callable function", calleeName);
   4640      case ModuleValidatorShared::Global::Function:
   4641        break;
   4642    }
   4643  }
   4644 
   4645  return CheckInternalCall(f, call, calleeName, ret, type);
   4646 }
   4647 
   4648 template <typename Unit>
   4649 static bool CheckPos(FunctionValidator<Unit>& f, ParseNode* pos, Type* type) {
   4650  MOZ_ASSERT(pos->isKind(ParseNodeKind::PosExpr));
   4651  ParseNode* operand = UnaryKid(pos);
   4652 
   4653  if (operand->isKind(ParseNodeKind::CallExpr)) {
   4654    return CheckCoercedCall(f, operand, Type::Double, type);
   4655  }
   4656 
   4657  Type actual;
   4658  if (!CheckExpr(f, operand, &actual)) {
   4659    return false;
   4660  }
   4661 
   4662  return CoerceResult(f, operand, Type::Double, actual, type);
   4663 }
   4664 
   4665 template <typename Unit>
   4666 static bool CheckNot(FunctionValidator<Unit>& f, ParseNode* expr, Type* type) {
   4667  MOZ_ASSERT(expr->isKind(ParseNodeKind::NotExpr));
   4668  ParseNode* operand = UnaryKid(expr);
   4669 
   4670  Type operandType;
   4671  if (!CheckExpr(f, operand, &operandType)) {
   4672    return false;
   4673  }
   4674 
   4675  if (!operandType.isInt()) {
   4676    return f.failf(operand, "%s is not a subtype of int",
   4677                   operandType.toChars());
   4678  }
   4679 
   4680  *type = Type::Int;
   4681  return f.encoder().writeOp(Op::I32Eqz);
   4682 }
   4683 
   4684 template <typename Unit>
   4685 static bool CheckNeg(FunctionValidator<Unit>& f, ParseNode* expr, Type* type) {
   4686  MOZ_ASSERT(expr->isKind(ParseNodeKind::NegExpr));
   4687  ParseNode* operand = UnaryKid(expr);
   4688 
   4689  Type operandType;
   4690  if (!CheckExpr(f, operand, &operandType)) {
   4691    return false;
   4692  }
   4693 
   4694  if (operandType.isInt()) {
   4695    *type = Type::Intish;
   4696    return f.encoder().writeOp(MozOp::I32Neg);
   4697  }
   4698 
   4699  if (operandType.isMaybeDouble()) {
   4700    *type = Type::Double;
   4701    return f.encoder().writeOp(Op::F64Neg);
   4702  }
   4703 
   4704  if (operandType.isMaybeFloat()) {
   4705    *type = Type::Floatish;
   4706    return f.encoder().writeOp(Op::F32Neg);
   4707  }
   4708 
   4709  return f.failf(operand, "%s is not a subtype of int, float? or double?",
   4710                 operandType.toChars());
   4711 }
   4712 
   4713 template <typename Unit>
   4714 static bool CheckCoerceToInt(FunctionValidator<Unit>& f, ParseNode* expr,
   4715                             Type* type) {
   4716  MOZ_ASSERT(expr->isKind(ParseNodeKind::BitNotExpr));
   4717  ParseNode* operand = UnaryKid(expr);
   4718 
   4719  Type operandType;
   4720  if (!CheckExpr(f, operand, &operandType)) {
   4721    return false;
   4722  }
   4723 
   4724  if (operandType.isMaybeDouble() || operandType.isMaybeFloat()) {
   4725    *type = Type::Signed;
   4726    Op opcode =
   4727        operandType.isMaybeDouble() ? Op::I32TruncF64S : Op::I32TruncF32S;
   4728    if (!f.prepareCall(expr)) {
   4729      return false;
   4730    }
   4731    return f.encoder().writeOp(opcode);
   4732  }
   4733 
   4734  if (!operandType.isIntish()) {
   4735    return f.failf(operand, "%s is not a subtype of double?, float? or intish",
   4736                   operandType.toChars());
   4737  }
   4738 
   4739  *type = Type::Signed;
   4740  return true;
   4741 }
   4742 
   4743 template <typename Unit>
   4744 static bool CheckBitNot(FunctionValidator<Unit>& f, ParseNode* neg,
   4745                        Type* type) {
   4746  MOZ_ASSERT(neg->isKind(ParseNodeKind::BitNotExpr));
   4747  ParseNode* operand = UnaryKid(neg);
   4748 
   4749  if (operand->isKind(ParseNodeKind::BitNotExpr)) {
   4750    return CheckCoerceToInt(f, operand, type);
   4751  }
   4752 
   4753  Type operandType;
   4754  if (!CheckExpr(f, operand, &operandType)) {
   4755    return false;
   4756  }
   4757 
   4758  if (!operandType.isIntish()) {
   4759    return f.failf(operand, "%s is not a subtype of intish",
   4760                   operandType.toChars());
   4761  }
   4762 
   4763  if (!f.encoder().writeOp(MozOp::I32BitNot)) {
   4764    return false;
   4765  }
   4766 
   4767  *type = Type::Signed;
   4768  return true;
   4769 }
   4770 
   4771 template <typename Unit>
   4772 static bool CheckAsExprStatement(FunctionValidator<Unit>& f,
   4773                                 ParseNode* exprStmt);
   4774 
   4775 template <typename Unit>
   4776 static bool CheckComma(FunctionValidator<Unit>& f, ParseNode* comma,
   4777                       Type* type) {
   4778  MOZ_ASSERT(comma->isKind(ParseNodeKind::CommaExpr));
   4779  ParseNode* operands = ListHead(comma);
   4780 
   4781  // The block depth isn't taken into account here, because a comma list can't
   4782  // contain breaks and continues and nested control flow structures.
   4783  if (!f.encoder().writeOp(Op::Block)) {
   4784    return false;
   4785  }
   4786 
   4787  size_t typeAt;
   4788  if (!f.encoder().writePatchableFixedU7(&typeAt)) {
   4789    return false;
   4790  }
   4791 
   4792  ParseNode* pn = operands;
   4793  for (; NextNode(pn); pn = NextNode(pn)) {
   4794    if (!CheckAsExprStatement(f, pn)) {
   4795      return false;
   4796    }
   4797  }
   4798 
   4799  if (!CheckExpr(f, pn, type)) {
   4800    return false;
   4801  }
   4802 
   4803  f.encoder().patchFixedU7(typeAt, uint8_t(type->toWasmBlockSignatureType()));
   4804 
   4805  return f.encoder().writeOp(Op::End);
   4806 }
   4807 
   4808 template <typename Unit>
   4809 static bool CheckConditional(FunctionValidator<Unit>& f, ParseNode* ternary,
   4810                             Type* type) {
   4811  MOZ_ASSERT(ternary->isKind(ParseNodeKind::ConditionalExpr));
   4812 
   4813  ParseNode* cond = TernaryKid1(ternary);
   4814  ParseNode* thenExpr = TernaryKid2(ternary);
   4815  ParseNode* elseExpr = TernaryKid3(ternary);
   4816 
   4817  Type condType;
   4818  if (!CheckExpr(f, cond, &condType)) {
   4819    return false;
   4820  }
   4821 
   4822  if (!condType.isInt()) {
   4823    return f.failf(cond, "%s is not a subtype of int", condType.toChars());
   4824  }
   4825 
   4826  size_t typeAt;
   4827  if (!f.pushIf(&typeAt)) {
   4828    return false;
   4829  }
   4830 
   4831  Type thenType;
   4832  if (!CheckExpr(f, thenExpr, &thenType)) {
   4833    return false;
   4834  }
   4835 
   4836  if (!f.switchToElse()) {
   4837    return false;
   4838  }
   4839 
   4840  Type elseType;
   4841  if (!CheckExpr(f, elseExpr, &elseType)) {
   4842    return false;
   4843  }
   4844 
   4845  if (thenType.isInt() && elseType.isInt()) {
   4846    *type = Type::Int;
   4847  } else if (thenType.isDouble() && elseType.isDouble()) {
   4848    *type = Type::Double;
   4849  } else if (thenType.isFloat() && elseType.isFloat()) {
   4850    *type = Type::Float;
   4851  } else {
   4852    return f.failf(
   4853        ternary,
   4854        "then/else branches of conditional must both produce int, float, "
   4855        "double, current types are %s and %s",
   4856        thenType.toChars(), elseType.toChars());
   4857  }
   4858 
   4859  return f.popIf(typeAt, type->toWasmBlockSignatureType());
   4860 }
   4861 
   4862 template <typename Unit>
   4863 static bool IsValidIntMultiplyConstant(ModuleValidator<Unit>& m,
   4864                                       ParseNode* expr) {
   4865  if (!IsNumericLiteral(m, expr)) {
   4866    return false;
   4867  }
   4868 
   4869  NumLit lit = ExtractNumericLiteral(m, expr);
   4870  switch (lit.which()) {
   4871    case NumLit::Fixnum:
   4872    case NumLit::NegativeInt:
   4873      if (Abs(lit.toInt32()) < (uint32_t(1) << 20)) {
   4874        return true;
   4875      }
   4876      return false;
   4877    case NumLit::BigUnsigned:
   4878    case NumLit::Double:
   4879    case NumLit::Float:
   4880    case NumLit::OutOfRangeInt:
   4881      return false;
   4882  }
   4883 
   4884  MOZ_CRASH("Bad literal");
   4885 }
   4886 
   4887 template <typename Unit>
   4888 static bool CheckMultiply(FunctionValidator<Unit>& f, ParseNode* star,
   4889                          Type* type) {
   4890  MOZ_ASSERT(star->isKind(ParseNodeKind::MulExpr));
   4891  ParseNode* lhs = MultiplyLeft(star);
   4892  ParseNode* rhs = MultiplyRight(star);
   4893 
   4894  Type lhsType;
   4895  if (!CheckExpr(f, lhs, &lhsType)) {
   4896    return false;
   4897  }
   4898 
   4899  Type rhsType;
   4900  if (!CheckExpr(f, rhs, &rhsType)) {
   4901    return false;
   4902  }
   4903 
   4904  if (lhsType.isInt() && rhsType.isInt()) {
   4905    if (!IsValidIntMultiplyConstant(f.m(), lhs) &&
   4906        !IsValidIntMultiplyConstant(f.m(), rhs)) {
   4907      return f.fail(
   4908          star,
   4909          "one arg to int multiply must be a small (-2^20, 2^20) int literal");
   4910    }
   4911    *type = Type::Intish;
   4912    return f.encoder().writeOp(Op::I32Mul);
   4913  }
   4914 
   4915  if (lhsType.isMaybeDouble() && rhsType.isMaybeDouble()) {
   4916    *type = Type::Double;
   4917    return f.encoder().writeOp(Op::F64Mul);
   4918  }
   4919 
   4920  if (lhsType.isMaybeFloat() && rhsType.isMaybeFloat()) {
   4921    *type = Type::Floatish;
   4922    return f.encoder().writeOp(Op::F32Mul);
   4923  }
   4924 
   4925  return f.fail(
   4926      star, "multiply operands must be both int, both double? or both float?");
   4927 }
   4928 
   4929 template <typename Unit>
   4930 static bool CheckAddOrSub(FunctionValidator<Unit>& f, ParseNode* expr,
   4931                          Type* type, unsigned* numAddOrSubOut = nullptr) {
   4932  AutoCheckRecursionLimit recursion(f.fc());
   4933  if (!recursion.checkDontReport(f.fc())) {
   4934    return f.m().failOverRecursed();
   4935  }
   4936 
   4937  MOZ_ASSERT(expr->isKind(ParseNodeKind::AddExpr) ||
   4938             expr->isKind(ParseNodeKind::SubExpr));
   4939  ParseNode* lhs = AddSubLeft(expr);
   4940  ParseNode* rhs = AddSubRight(expr);
   4941 
   4942  Type lhsType, rhsType;
   4943  unsigned lhsNumAddOrSub, rhsNumAddOrSub;
   4944 
   4945  if (lhs->isKind(ParseNodeKind::AddExpr) ||
   4946      lhs->isKind(ParseNodeKind::SubExpr)) {
   4947    if (!CheckAddOrSub(f, lhs, &lhsType, &lhsNumAddOrSub)) {
   4948      return false;
   4949    }
   4950    if (lhsType == Type::Intish) {
   4951      lhsType = Type::Int;
   4952    }
   4953  } else {
   4954    if (!CheckExpr(f, lhs, &lhsType)) {
   4955      return false;
   4956    }
   4957    lhsNumAddOrSub = 0;
   4958  }
   4959 
   4960  if (rhs->isKind(ParseNodeKind::AddExpr) ||
   4961      rhs->isKind(ParseNodeKind::SubExpr)) {
   4962    if (!CheckAddOrSub(f, rhs, &rhsType, &rhsNumAddOrSub)) {
   4963      return false;
   4964    }
   4965    if (rhsType == Type::Intish) {
   4966      rhsType = Type::Int;
   4967    }
   4968  } else {
   4969    if (!CheckExpr(f, rhs, &rhsType)) {
   4970      return false;
   4971    }
   4972    rhsNumAddOrSub = 0;
   4973  }
   4974 
   4975  unsigned numAddOrSub = lhsNumAddOrSub + rhsNumAddOrSub + 1;
   4976  if (numAddOrSub > (1 << 20)) {
   4977    return f.fail(expr, "too many + or - without intervening coercion");
   4978  }
   4979 
   4980  if (lhsType.isInt() && rhsType.isInt()) {
   4981    if (!f.encoder().writeOp(
   4982            expr->isKind(ParseNodeKind::AddExpr) ? Op::I32Add : Op::I32Sub)) {
   4983      return false;
   4984    }
   4985    *type = Type::Intish;
   4986  } else if (lhsType.isMaybeDouble() && rhsType.isMaybeDouble()) {
   4987    if (!f.encoder().writeOp(
   4988            expr->isKind(ParseNodeKind::AddExpr) ? Op::F64Add : Op::F64Sub)) {
   4989      return false;
   4990    }
   4991    *type = Type::Double;
   4992  } else if (lhsType.isMaybeFloat() && rhsType.isMaybeFloat()) {
   4993    if (!f.encoder().writeOp(
   4994            expr->isKind(ParseNodeKind::AddExpr) ? Op::F32Add : Op::F32Sub)) {
   4995      return false;
   4996    }
   4997    *type = Type::Floatish;
   4998  } else {
   4999    return f.failf(
   5000        expr,
   5001        "operands to + or - must both be int, float? or double?, got %s and %s",
   5002        lhsType.toChars(), rhsType.toChars());
   5003  }
   5004 
   5005  if (numAddOrSubOut) {
   5006    *numAddOrSubOut = numAddOrSub;
   5007  }
   5008  return true;
   5009 }
   5010 
   5011 template <typename Unit>
   5012 static bool CheckDivOrMod(FunctionValidator<Unit>& f, ParseNode* expr,
   5013                          Type* type) {
   5014  MOZ_ASSERT(expr->isKind(ParseNodeKind::DivExpr) ||
   5015             expr->isKind(ParseNodeKind::ModExpr));
   5016 
   5017  ParseNode* lhs = DivOrModLeft(expr);
   5018  ParseNode* rhs = DivOrModRight(expr);
   5019 
   5020  Type lhsType, rhsType;
   5021  if (!CheckExpr(f, lhs, &lhsType)) {
   5022    return false;
   5023  }
   5024  if (!CheckExpr(f, rhs, &rhsType)) {
   5025    return false;
   5026  }
   5027 
   5028  if (lhsType.isMaybeDouble() && rhsType.isMaybeDouble()) {
   5029    *type = Type::Double;
   5030    if (expr->isKind(ParseNodeKind::DivExpr)) {
   5031      return f.encoder().writeOp(Op::F64Div);
   5032    }
   5033    return f.encoder().writeOp(MozOp::F64Mod);
   5034  }
   5035 
   5036  if (lhsType.isMaybeFloat() && rhsType.isMaybeFloat()) {
   5037    *type = Type::Floatish;
   5038    if (expr->isKind(ParseNodeKind::DivExpr)) {
   5039      return f.encoder().writeOp(Op::F32Div);
   5040    }
   5041    return f.fail(expr, "modulo cannot receive float arguments");
   5042  }
   5043 
   5044  if (lhsType.isSigned() && rhsType.isSigned()) {
   5045    *type = Type::Intish;
   5046    return f.encoder().writeOp(
   5047        expr->isKind(ParseNodeKind::DivExpr) ? Op::I32DivS : Op::I32RemS);
   5048  }
   5049 
   5050  if (lhsType.isUnsigned() && rhsType.isUnsigned()) {
   5051    *type = Type::Intish;
   5052    return f.encoder().writeOp(
   5053        expr->isKind(ParseNodeKind::DivExpr) ? Op::I32DivU : Op::I32RemU);
   5054  }
   5055 
   5056  return f.failf(
   5057      expr,
   5058      "arguments to / or %% must both be double?, float?, signed, or unsigned; "
   5059      "%s and %s are given",
   5060      lhsType.toChars(), rhsType.toChars());
   5061 }
   5062 
   5063 template <typename Unit>
   5064 static bool CheckComparison(FunctionValidator<Unit>& f, ParseNode* comp,
   5065                            Type* type) {
   5066  MOZ_ASSERT(comp->isKind(ParseNodeKind::LtExpr) ||
   5067             comp->isKind(ParseNodeKind::LeExpr) ||
   5068             comp->isKind(ParseNodeKind::GtExpr) ||
   5069             comp->isKind(ParseNodeKind::GeExpr) ||
   5070             comp->isKind(ParseNodeKind::EqExpr) ||
   5071             comp->isKind(ParseNodeKind::NeExpr));
   5072 
   5073  ParseNode* lhs = ComparisonLeft(comp);
   5074  ParseNode* rhs = ComparisonRight(comp);
   5075 
   5076  Type lhsType, rhsType;
   5077  if (!CheckExpr(f, lhs, &lhsType)) {
   5078    return false;
   5079  }
   5080  if (!CheckExpr(f, rhs, &rhsType)) {
   5081    return false;
   5082  }
   5083 
   5084  if (!(lhsType.isSigned() && rhsType.isSigned()) &&
   5085      !(lhsType.isUnsigned() && rhsType.isUnsigned()) &&
   5086      !(lhsType.isDouble() && rhsType.isDouble()) &&
   5087      !(lhsType.isFloat() && rhsType.isFloat())) {
   5088    return f.failf(comp,
   5089                   "arguments to a comparison must both be signed, unsigned, "
   5090                   "floats or doubles; "
   5091                   "%s and %s are given",
   5092                   lhsType.toChars(), rhsType.toChars());
   5093  }
   5094 
   5095  Op stmt;
   5096  if (lhsType.isSigned() && rhsType.isSigned()) {
   5097    switch (comp->getKind()) {
   5098      case ParseNodeKind::EqExpr:
   5099        stmt = Op::I32Eq;
   5100        break;
   5101      case ParseNodeKind::NeExpr:
   5102        stmt = Op::I32Ne;
   5103        break;
   5104      case ParseNodeKind::LtExpr:
   5105        stmt = Op::I32LtS;
   5106        break;
   5107      case ParseNodeKind::LeExpr:
   5108        stmt = Op::I32LeS;
   5109        break;
   5110      case ParseNodeKind::GtExpr:
   5111        stmt = Op::I32GtS;
   5112        break;
   5113      case ParseNodeKind::GeExpr:
   5114        stmt = Op::I32GeS;
   5115        break;
   5116      default:
   5117        MOZ_CRASH("unexpected comparison op");
   5118    }
   5119  } else if (lhsType.isUnsigned() && rhsType.isUnsigned()) {
   5120    switch (comp->getKind()) {
   5121      case ParseNodeKind::EqExpr:
   5122        stmt = Op::I32Eq;
   5123        break;
   5124      case ParseNodeKind::NeExpr:
   5125        stmt = Op::I32Ne;
   5126        break;
   5127      case ParseNodeKind::LtExpr:
   5128        stmt = Op::I32LtU;
   5129        break;
   5130      case ParseNodeKind::LeExpr:
   5131        stmt = Op::I32LeU;
   5132        break;
   5133      case ParseNodeKind::GtExpr:
   5134        stmt = Op::I32GtU;
   5135        break;
   5136      case ParseNodeKind::GeExpr:
   5137        stmt = Op::I32GeU;
   5138        break;
   5139      default:
   5140        MOZ_CRASH("unexpected comparison op");
   5141    }
   5142  } else if (lhsType.isDouble()) {
   5143    switch (comp->getKind()) {
   5144      case ParseNodeKind::EqExpr:
   5145        stmt = Op::F64Eq;
   5146        break;
   5147      case ParseNodeKind::NeExpr:
   5148        stmt = Op::F64Ne;
   5149        break;
   5150      case ParseNodeKind::LtExpr:
   5151        stmt = Op::F64Lt;
   5152        break;
   5153      case ParseNodeKind::LeExpr:
   5154        stmt = Op::F64Le;
   5155        break;
   5156      case ParseNodeKind::GtExpr:
   5157        stmt = Op::F64Gt;
   5158        break;
   5159      case ParseNodeKind::GeExpr:
   5160        stmt = Op::F64Ge;
   5161        break;
   5162      default:
   5163        MOZ_CRASH("unexpected comparison op");
   5164    }
   5165  } else if (lhsType.isFloat()) {
   5166    switch (comp->getKind()) {
   5167      case ParseNodeKind::EqExpr:
   5168        stmt = Op::F32Eq;
   5169        break;
   5170      case ParseNodeKind::NeExpr:
   5171        stmt = Op::F32Ne;
   5172        break;
   5173      case ParseNodeKind::LtExpr:
   5174        stmt = Op::F32Lt;
   5175        break;
   5176      case ParseNodeKind::LeExpr:
   5177        stmt = Op::F32Le;
   5178        break;
   5179      case ParseNodeKind::GtExpr:
   5180        stmt = Op::F32Gt;
   5181        break;
   5182      case ParseNodeKind::GeExpr:
   5183        stmt = Op::F32Ge;
   5184        break;
   5185      default:
   5186        MOZ_CRASH("unexpected comparison op");
   5187    }
   5188  } else {
   5189    MOZ_CRASH("unexpected type");
   5190  }
   5191 
   5192  *type = Type::Int;
   5193  return f.encoder().writeOp(stmt);
   5194 }
   5195 
   5196 template <typename Unit>
   5197 static bool CheckBitwise(FunctionValidator<Unit>& f, ParseNode* bitwise,
   5198                         Type* type) {
   5199  ParseNode* lhs = BitwiseLeft(bitwise);
   5200  ParseNode* rhs = BitwiseRight(bitwise);
   5201 
   5202  int32_t identityElement;
   5203  bool onlyOnRight;
   5204  switch (bitwise->getKind()) {
   5205    case ParseNodeKind::BitOrExpr:
   5206      identityElement = 0;
   5207      onlyOnRight = false;
   5208      *type = Type::Signed;
   5209      break;
   5210    case ParseNodeKind::BitAndExpr:
   5211      identityElement = -1;
   5212      onlyOnRight = false;
   5213      *type = Type::Signed;
   5214      break;
   5215    case ParseNodeKind::BitXorExpr:
   5216      identityElement = 0;
   5217      onlyOnRight = false;
   5218      *type = Type::Signed;
   5219      break;
   5220    case ParseNodeKind::LshExpr:
   5221      identityElement = 0;
   5222      onlyOnRight = true;
   5223      *type = Type::Signed;
   5224      break;
   5225    case ParseNodeKind::RshExpr:
   5226      identityElement = 0;
   5227      onlyOnRight = true;
   5228      *type = Type::Signed;
   5229      break;
   5230    case ParseNodeKind::UrshExpr:
   5231      identityElement = 0;
   5232      onlyOnRight = true;
   5233      *type = Type::Unsigned;
   5234      break;
   5235    default:
   5236      MOZ_CRASH("not a bitwise op");
   5237  }
   5238 
   5239  uint32_t i;
   5240  if (!onlyOnRight && IsLiteralInt(f.m(), lhs, &i) &&
   5241      i == uint32_t(identityElement)) {
   5242    Type rhsType;
   5243    if (!CheckExpr(f, rhs, &rhsType)) {
   5244      return false;
   5245    }
   5246    if (!rhsType.isIntish()) {
   5247      return f.failf(bitwise, "%s is not a subtype of intish",
   5248                     rhsType.toChars());
   5249    }
   5250    return true;
   5251  }
   5252 
   5253  if (IsLiteralInt(f.m(), rhs, &i) && i == uint32_t(identityElement)) {
   5254    if (bitwise->isKind(ParseNodeKind::BitOrExpr) &&
   5255        lhs->isKind(ParseNodeKind::CallExpr)) {
   5256      return CheckCoercedCall(f, lhs, Type::Int, type);
   5257    }
   5258 
   5259    Type lhsType;
   5260    if (!CheckExpr(f, lhs, &lhsType)) {
   5261      return false;
   5262    }
   5263    if (!lhsType.isIntish()) {
   5264      return f.failf(bitwise, "%s is not a subtype of intish",
   5265                     lhsType.toChars());
   5266    }
   5267    return true;
   5268  }
   5269 
   5270  Type lhsType;
   5271  if (!CheckExpr(f, lhs, &lhsType)) {
   5272    return false;
   5273  }
   5274 
   5275  Type rhsType;
   5276  if (!CheckExpr(f, rhs, &rhsType)) {
   5277    return false;
   5278  }
   5279 
   5280  if (!lhsType.isIntish()) {
   5281    return f.failf(lhs, "%s is not a subtype of intish", lhsType.toChars());
   5282  }
   5283  if (!rhsType.isIntish()) {
   5284    return f.failf(rhs, "%s is not a subtype of intish", rhsType.toChars());
   5285  }
   5286 
   5287  switch (bitwise->getKind()) {
   5288    case ParseNodeKind::BitOrExpr:
   5289      if (!f.encoder().writeOp(Op::I32Or)) return false;
   5290      break;
   5291    case ParseNodeKind::BitAndExpr:
   5292      if (!f.encoder().writeOp(Op::I32And)) return false;
   5293      break;
   5294    case ParseNodeKind::BitXorExpr:
   5295      if (!f.encoder().writeOp(Op::I32Xor)) return false;
   5296      break;
   5297    case ParseNodeKind::LshExpr:
   5298      if (!f.encoder().writeOp(Op::I32Shl)) return false;
   5299      break;
   5300    case ParseNodeKind::RshExpr:
   5301      if (!f.encoder().writeOp(Op::I32ShrS)) return false;
   5302      break;
   5303    case ParseNodeKind::UrshExpr:
   5304      if (!f.encoder().writeOp(Op::I32ShrU)) return false;
   5305      break;
   5306    default:
   5307      MOZ_CRASH("not a bitwise op");
   5308  }
   5309 
   5310  return true;
   5311 }
   5312 
   5313 template <typename Unit>
   5314 static bool CheckExpr(FunctionValidator<Unit>& f, ParseNode* expr, Type* type) {
   5315  AutoCheckRecursionLimit recursion(f.fc());
   5316  if (!recursion.checkDontReport(f.fc())) {
   5317    return f.m().failOverRecursed();
   5318  }
   5319 
   5320  if (IsNumericLiteral(f.m(), expr)) {
   5321    return CheckNumericLiteral(f, expr, type);
   5322  }
   5323 
   5324  switch (expr->getKind()) {
   5325    case ParseNodeKind::Name:
   5326      return CheckVarRef(f, expr, type);
   5327    case ParseNodeKind::ElemExpr:
   5328      return CheckLoadArray(f, expr, type);
   5329    case ParseNodeKind::AssignExpr:
   5330      return CheckAssign(f, expr, type);
   5331    case ParseNodeKind::PosExpr:
   5332      return CheckPos(f, expr, type);
   5333    case ParseNodeKind::NotExpr:
   5334      return CheckNot(f, expr, type);
   5335    case ParseNodeKind::NegExpr:
   5336      return CheckNeg(f, expr, type);
   5337    case ParseNodeKind::BitNotExpr:
   5338      return CheckBitNot(f, expr, type);
   5339    case ParseNodeKind::CommaExpr:
   5340      return CheckComma(f, expr, type);
   5341    case ParseNodeKind::ConditionalExpr:
   5342      return CheckConditional(f, expr, type);
   5343    case ParseNodeKind::MulExpr:
   5344      return CheckMultiply(f, expr, type);
   5345    case ParseNodeKind::CallExpr:
   5346      return CheckUncoercedCall(f, expr, type);
   5347 
   5348    case ParseNodeKind::AddExpr:
   5349    case ParseNodeKind::SubExpr:
   5350      return CheckAddOrSub(f, expr, type);
   5351 
   5352    case ParseNodeKind::DivExpr:
   5353    case ParseNodeKind::ModExpr:
   5354      return CheckDivOrMod(f, expr, type);
   5355 
   5356    case ParseNodeKind::LtExpr:
   5357    case ParseNodeKind::LeExpr:
   5358    case ParseNodeKind::GtExpr:
   5359    case ParseNodeKind::GeExpr:
   5360    case ParseNodeKind::EqExpr:
   5361    case ParseNodeKind::NeExpr:
   5362      return CheckComparison(f, expr, type);
   5363 
   5364    case ParseNodeKind::BitOrExpr:
   5365    case ParseNodeKind::BitAndExpr:
   5366    case ParseNodeKind::BitXorExpr:
   5367    case ParseNodeKind::LshExpr:
   5368    case ParseNodeKind::RshExpr:
   5369    case ParseNodeKind::UrshExpr:
   5370      return CheckBitwise(f, expr, type);
   5371 
   5372    default:;
   5373  }
   5374 
   5375  return f.fail(expr, "unsupported expression");
   5376 }
   5377 
   5378 template <typename Unit>
   5379 static bool CheckStatement(FunctionValidator<Unit>& f, ParseNode* stmt);
   5380 
   5381 template <typename Unit>
   5382 static bool CheckAsExprStatement(FunctionValidator<Unit>& f, ParseNode* expr) {
   5383  if (expr->isKind(ParseNodeKind::CallExpr)) {
   5384    Type ignored;
   5385    return CheckCoercedCall(f, expr, Type::Void, &ignored);
   5386  }
   5387 
   5388  Type resultType;
   5389  if (!CheckExpr(f, expr, &resultType)) {
   5390    return false;
   5391  }
   5392 
   5393  if (!resultType.isVoid()) {
   5394    if (!f.encoder().writeOp(Op::Drop)) {
   5395      return false;
   5396    }
   5397  }
   5398 
   5399  return true;
   5400 }
   5401 
   5402 template <typename Unit>
   5403 static bool CheckExprStatement(FunctionValidator<Unit>& f,
   5404                               ParseNode* exprStmt) {
   5405  MOZ_ASSERT(exprStmt->isKind(ParseNodeKind::ExpressionStmt));
   5406  return CheckAsExprStatement(f, UnaryKid(exprStmt));
   5407 }
   5408 
   5409 template <typename Unit>
   5410 static bool CheckLoopConditionOnEntry(FunctionValidator<Unit>& f,
   5411                                      ParseNode* cond) {
   5412  uint32_t maybeLit;
   5413  if (IsLiteralInt(f.m(), cond, &maybeLit) && maybeLit) {
   5414    return true;
   5415  }
   5416 
   5417  Type condType;
   5418  if (!CheckExpr(f, cond, &condType)) {
   5419    return false;
   5420  }
   5421  if (!condType.isInt()) {
   5422    return f.failf(cond, "%s is not a subtype of int", condType.toChars());
   5423  }
   5424 
   5425  if (!f.encoder().writeOp(Op::I32Eqz)) {
   5426    return false;
   5427  }
   5428 
   5429  // brIf (i32.eqz $f) $out
   5430  return f.writeBreakIf();
   5431 }
   5432 
   5433 template <typename Unit>
   5434 static bool CheckWhile(FunctionValidator<Unit>& f, ParseNode* whileStmt,
   5435                       const LabelVector* labels = nullptr) {
   5436  MOZ_ASSERT(whileStmt->isKind(ParseNodeKind::WhileStmt));
   5437  ParseNode* cond = BinaryLeft(whileStmt);
   5438  ParseNode* body = BinaryRight(whileStmt);
   5439 
   5440  // A while loop `while(#cond) #body` is equivalent to:
   5441  // (block $after_loop
   5442  //    (loop $top
   5443  //       (brIf $after_loop (i32.eq 0 #cond))
   5444  //       #body
   5445  //       (br $top)
   5446  //    )
   5447  // )
   5448  if (labels && !f.addLabels(*labels, 0, 1)) {
   5449    return false;
   5450  }
   5451 
   5452  if (!f.pushLoop()) {
   5453    return false;
   5454  }
   5455 
   5456  if (!CheckLoopConditionOnEntry(f, cond)) {
   5457    return false;
   5458  }
   5459  if (!CheckStatement(f, body)) {
   5460    return false;
   5461  }
   5462  if (!f.writeContinue()) {
   5463    return false;
   5464  }
   5465 
   5466  if (!f.popLoop()) {
   5467    return false;
   5468  }
   5469  if (labels) {
   5470    f.removeLabels(*labels);
   5471  }
   5472  return true;
   5473 }
   5474 
   5475 template <typename Unit>
   5476 static bool CheckFor(FunctionValidator<Unit>& f, ParseNode* forStmt,
   5477                     const LabelVector* labels = nullptr) {
   5478  MOZ_ASSERT(forStmt->isKind(ParseNodeKind::ForStmt));
   5479  ParseNode* forHead = BinaryLeft(forStmt);
   5480  ParseNode* body = BinaryRight(forStmt);
   5481 
   5482  if (!forHead->isKind(ParseNodeKind::ForHead)) {
   5483    return f.fail(forHead, "unsupported for-loop statement");
   5484  }
   5485 
   5486  ParseNode* maybeInit = TernaryKid1(forHead);
   5487  ParseNode* maybeCond = TernaryKid2(forHead);
   5488  ParseNode* maybeInc = TernaryKid3(forHead);
   5489 
   5490  // A for-loop `for (#init; #cond; #inc) #body` is equivalent to:
   5491  // (block                                               // depth X
   5492  //   (#init)
   5493  //   (block $after_loop                                 // depth X+1 (block)
   5494  //     (loop $loop_top                                  // depth X+2 (loop)
   5495  //       (brIf $after (eq 0 #cond))
   5496  //       (block $after_body #body)                      // depth X+3
   5497  //       #inc
   5498  //       (br $loop_top)
   5499  //     )
   5500  //   )
   5501  // )
   5502  // A break in the body should break out to $after_loop, i.e. depth + 1.
   5503  // A continue in the body should break out to $after_body, i.e. depth + 3.
   5504  if (labels && !f.addLabels(*labels, 1, 3)) {
   5505    return false;
   5506  }
   5507 
   5508  if (!f.pushUnbreakableBlock()) {
   5509    return false;
   5510  }
   5511 
   5512  if (maybeInit && !CheckAsExprStatement(f, maybeInit)) {
   5513    return false;
   5514  }
   5515 
   5516  {
   5517    if (!f.pushLoop()) {
   5518      return false;
   5519    }
   5520 
   5521    if (maybeCond && !CheckLoopConditionOnEntry(f, maybeCond)) {
   5522      return false;
   5523    }
   5524 
   5525    {
   5526      // Continuing in the body should just break out to the increment.
   5527      if (!f.pushContinuableBlock()) {
   5528        return false;
   5529      }
   5530      if (!CheckStatement(f, body)) {
   5531        return false;
   5532      }
   5533      if (!f.popContinuableBlock()) {
   5534        return false;
   5535      }
   5536    }
   5537 
   5538    if (maybeInc && !CheckAsExprStatement(f, maybeInc)) {
   5539      return false;
   5540    }
   5541 
   5542    if (!f.writeContinue()) {
   5543      return false;
   5544    }
   5545    if (!f.popLoop()) {
   5546      return false;
   5547    }
   5548  }
   5549 
   5550  if (!f.popUnbreakableBlock()) {
   5551    return false;
   5552  }
   5553 
   5554  if (labels) {
   5555    f.removeLabels(*labels);
   5556  }
   5557 
   5558  return true;
   5559 }
   5560 
   5561 template <typename Unit>
   5562 static bool CheckDoWhile(FunctionValidator<Unit>& f, ParseNode* whileStmt,
   5563                         const LabelVector* labels = nullptr) {
   5564  MOZ_ASSERT(whileStmt->isKind(ParseNodeKind::DoWhileStmt));
   5565  ParseNode* body = BinaryLeft(whileStmt);
   5566  ParseNode* cond = BinaryRight(whileStmt);
   5567 
   5568  // A do-while loop `do { #body } while (#cond)` is equivalent to:
   5569  // (block $after_loop           // depth X
   5570  //   (loop $top                 // depth X+1
   5571  //     (block #body)            // depth X+2
   5572  //     (brIf #cond $top)
   5573  //   )
   5574  // )
   5575  // A break should break out of the entire loop, i.e. at depth 0.
   5576  // A continue should break out to the condition, i.e. at depth 2.
   5577  if (labels && !f.addLabels(*labels, 0, 2)) {
   5578    return false;
   5579  }
   5580 
   5581  if (!f.pushLoop()) {
   5582    return false;
   5583  }
   5584 
   5585  {
   5586    // An unlabeled continue in the body should break out to the condition.
   5587    if (!f.pushContinuableBlock()) {
   5588      return false;
   5589    }
   5590    if (!CheckStatement(f, body)) {
   5591      return false;
   5592    }
   5593    if (!f.popContinuableBlock()) {
   5594      return false;
   5595    }
   5596  }
   5597 
   5598  Type condType;
   5599  if (!CheckExpr(f, cond, &condType)) {
   5600    return false;
   5601  }
   5602  if (!condType.isInt()) {
   5603    return f.failf(cond, "%s is not a subtype of int", condType.toChars());
   5604  }
   5605 
   5606  if (!f.writeContinueIf()) {
   5607    return false;
   5608  }
   5609 
   5610  if (!f.popLoop()) {
   5611    return false;
   5612  }
   5613  if (labels) {
   5614    f.removeLabels(*labels);
   5615  }
   5616  return true;
   5617 }
   5618 
   5619 template <typename Unit>
   5620 static bool CheckStatementList(FunctionValidator<Unit>& f, ParseNode*,
   5621                               const LabelVector* = nullptr);
   5622 
   5623 template <typename Unit>
   5624 static bool CheckLabel(FunctionValidator<Unit>& f, ParseNode* labeledStmt) {
   5625  MOZ_ASSERT(labeledStmt->isKind(ParseNodeKind::LabelStmt));
   5626 
   5627  LabelVector labels;
   5628  ParseNode* innermost = labeledStmt;
   5629  do {
   5630    if (!labels.append(LabeledStatementLabel(innermost))) {
   5631      return false;
   5632    }
   5633    innermost = LabeledStatementStatement(innermost);
   5634  } while (innermost->getKind() == ParseNodeKind::LabelStmt);
   5635 
   5636  switch (innermost->getKind()) {
   5637    case ParseNodeKind::ForStmt:
   5638      return CheckFor(f, innermost, &labels);
   5639    case ParseNodeKind::DoWhileStmt:
   5640      return CheckDoWhile(f, innermost, &labels);
   5641    case ParseNodeKind::WhileStmt:
   5642      return CheckWhile(f, innermost, &labels);
   5643    case ParseNodeKind::StatementList:
   5644      return CheckStatementList(f, innermost, &labels);
   5645    default:
   5646      break;
   5647  }
   5648 
   5649  if (!f.pushUnbreakableBlock(&labels)) {
   5650    return false;
   5651  }
   5652 
   5653  if (!CheckStatement(f, innermost)) {
   5654    return false;
   5655  }
   5656 
   5657  return f.popUnbreakableBlock(&labels);
   5658 }
   5659 
   5660 template <typename Unit>
   5661 static bool CheckIf(FunctionValidator<Unit>& f, ParseNode* ifStmt) {
   5662  uint32_t numIfEnd = 1;
   5663 
   5664 recurse:
   5665  MOZ_ASSERT(ifStmt->isKind(ParseNodeKind::IfStmt));
   5666  ParseNode* cond = TernaryKid1(ifStmt);
   5667  ParseNode* thenStmt = TernaryKid2(ifStmt);
   5668  ParseNode* elseStmt = TernaryKid3(ifStmt);
   5669 
   5670  Type condType;
   5671  if (!CheckExpr(f, cond, &condType)) {
   5672    return false;
   5673  }
   5674  if (!condType.isInt()) {
   5675    return f.failf(cond, "%s is not a subtype of int", condType.toChars());
   5676  }
   5677 
   5678  size_t typeAt;
   5679  if (!f.pushIf(&typeAt)) {
   5680    return false;
   5681  }
   5682 
   5683  f.setIfType(typeAt, TypeCode::BlockVoid);
   5684 
   5685  if (!CheckStatement(f, thenStmt)) {
   5686    return false;
   5687  }
   5688 
   5689  if (elseStmt) {
   5690    if (!f.switchToElse()) {
   5691      return false;
   5692    }
   5693 
   5694    if (elseStmt->isKind(ParseNodeKind::IfStmt)) {
   5695      ifStmt = elseStmt;
   5696      if (numIfEnd++ == UINT32_MAX) {
   5697        return false;
   5698      }
   5699      goto recurse;
   5700    }
   5701 
   5702    if (!CheckStatement(f, elseStmt)) {
   5703      return false;
   5704    }
   5705  }
   5706 
   5707  for (uint32_t i = 0; i != numIfEnd; ++i) {
   5708    if (!f.popIf()) {
   5709      return false;
   5710    }
   5711  }
   5712 
   5713  return true;
   5714 }
   5715 
   5716 static bool CheckCaseExpr(FunctionValidatorShared& f, ParseNode* caseExpr,
   5717                          int32_t* value) {
   5718  if (!IsNumericLiteral(f.m(), caseExpr)) {
   5719    return f.fail(caseExpr,
   5720                  "switch case expression must be an integer literal");
   5721  }
   5722 
   5723  NumLit lit = ExtractNumericLiteral(f.m(), caseExpr);
   5724  switch (lit.which()) {
   5725    case NumLit::Fixnum:
   5726    case NumLit::NegativeInt:
   5727      *value = lit.toInt32();
   5728      break;
   5729    case NumLit::OutOfRangeInt:
   5730    case NumLit::BigUnsigned:
   5731      return f.fail(caseExpr, "switch case expression out of integer range");
   5732    case NumLit::Double:
   5733    case NumLit::Float:
   5734      return f.fail(caseExpr,
   5735                    "switch case expression must be an integer literal");
   5736  }
   5737 
   5738  return true;
   5739 }
   5740 
   5741 static bool CheckDefaultAtEnd(FunctionValidatorShared& f, ParseNode* stmt) {
   5742  for (; stmt; stmt = NextNode(stmt)) {
   5743    if (IsDefaultCase(stmt) && NextNode(stmt) != nullptr) {
   5744      return f.fail(stmt, "default label must be at the end");
   5745    }
   5746  }
   5747 
   5748  return true;
   5749 }
   5750 
   5751 static bool CheckSwitchRange(FunctionValidatorShared& f, ParseNode* stmt,
   5752                             int32_t* low, int32_t* high,
   5753                             uint32_t* tableLength) {
   5754  if (IsDefaultCase(stmt)) {
   5755    *low = 0;
   5756    *high = -1;
   5757    *tableLength = 0;
   5758    return true;
   5759  }
   5760 
   5761  int32_t i = 0;
   5762  if (!CheckCaseExpr(f, CaseExpr(stmt), &i)) {
   5763    return false;
   5764  }
   5765 
   5766  *low = *high = i;
   5767 
   5768  ParseNode* initialStmt = stmt;
   5769  for (stmt = NextNode(stmt); stmt && !IsDefaultCase(stmt);
   5770       stmt = NextNode(stmt)) {
   5771    int32_t i = 0;
   5772    if (!CheckCaseExpr(f, CaseExpr(stmt), &i)) {
   5773      return false;
   5774    }
   5775 
   5776    *low = std::min(*low, i);
   5777    *high = std::max(*high, i);
   5778  }
   5779 
   5780  int64_t i64 = (int64_t(*high) - int64_t(*low)) + 1;
   5781  if (i64 > MaxBrTableElems) {
   5782    return f.fail(
   5783        initialStmt,
   5784        "all switch statements generate tables; this table would be too big");
   5785  }
   5786 
   5787  *tableLength = uint32_t(i64);
   5788  return true;
   5789 }
   5790 
   5791 template <typename Unit>
   5792 static bool CheckSwitchExpr(FunctionValidator<Unit>& f, ParseNode* switchExpr) {
   5793  Type exprType;
   5794  if (!CheckExpr(f, switchExpr, &exprType)) {
   5795    return false;
   5796  }
   5797  if (!exprType.isSigned()) {
   5798    return f.failf(switchExpr, "%s is not a subtype of signed",
   5799                   exprType.toChars());
   5800  }
   5801  return true;
   5802 }
   5803 
   5804 // A switch will be constructed as:
   5805 // - the default block wrapping all the other blocks, to be able to break
   5806 // out of the switch with an unlabeled break statement. It has two statements
   5807 // (an inner block and the default expr). asm.js rules require default to be at
   5808 // the end, so the default block always encloses all the cases blocks.
   5809 // - one block per case between low and high; undefined cases just jump to the
   5810 // default case. Each of these blocks contain two statements: the next case's
   5811 // block and the possibly empty statement list comprising the case body. The
   5812 // last block pushed is the first case so the (relative) branch target therefore
   5813 // matches the sequential order of cases.
   5814 // - one block for the br_table, so that the first break goes to the first
   5815 // case's block.
   5816 template <typename Unit>
   5817 static bool CheckSwitch(FunctionValidator<Unit>& f, ParseNode* switchStmt) {
   5818  MOZ_ASSERT(switchStmt->isKind(ParseNodeKind::SwitchStmt));
   5819 
   5820  ParseNode* switchExpr = BinaryLeft(switchStmt);
   5821  ParseNode* switchBody = BinaryRight(switchStmt);
   5822 
   5823  if (switchBody->is<LexicalScopeNode>()) {
   5824    LexicalScopeNode* scope = &switchBody->as<LexicalScopeNode>();
   5825    if (!scope->isEmptyScope()) {
   5826      return f.fail(scope, "switch body may not contain lexical declarations");
   5827    }
   5828    switchBody = scope->scopeBody();
   5829  }
   5830 
   5831  ParseNode* stmt = ListHead(switchBody);
   5832  if (!stmt) {
   5833    if (!CheckSwitchExpr(f, switchExpr)) {
   5834      return false;
   5835    }
   5836    return f.encoder().writeOp(Op::Drop);
   5837  }
   5838 
   5839  if (!CheckDefaultAtEnd(f, stmt)) {
   5840    return false;
   5841  }
   5842 
   5843  int32_t low = 0, high = 0;
   5844  uint32_t tableLength = 0;
   5845  if (!CheckSwitchRange(f, stmt, &low, &high, &tableLength)) {
   5846    return false;
   5847  }
   5848 
   5849  static const uint32_t CASE_NOT_DEFINED = UINT32_MAX;
   5850 
   5851  Uint32Vector caseDepths;
   5852  if (!caseDepths.appendN(CASE_NOT_DEFINED, tableLength)) {
   5853    return false;
   5854  }
   5855 
   5856  uint32_t numCases = 0;
   5857  for (ParseNode* s = stmt; s && !IsDefaultCase(s); s = NextNode(s)) {
   5858    int32_t caseValue = ExtractNumericLiteral(f.m(), CaseExpr(s)).toInt32();
   5859 
   5860    MOZ_ASSERT(caseValue >= low);
   5861    unsigned i = caseValue - low;
   5862    if (caseDepths[i] != CASE_NOT_DEFINED) {
   5863      return f.fail(s, "no duplicate case labels");
   5864    }
   5865 
   5866    MOZ_ASSERT(numCases != CASE_NOT_DEFINED);
   5867    caseDepths[i] = numCases++;
   5868  }
   5869 
   5870  // Open the wrapping breakable default block.
   5871  if (!f.pushBreakableBlock()) {
   5872    return false;
   5873  }
   5874 
   5875  // Open all the case blocks.
   5876  for (uint32_t i = 0; i < numCases; i++) {
   5877    if (!f.pushUnbreakableBlock()) {
   5878      return false;
   5879    }
   5880  }
   5881 
   5882  // Open the br_table block.
   5883  if (!f.pushUnbreakableBlock()) {
   5884    return false;
   5885  }
   5886 
   5887  // The default block is the last one.
   5888  uint32_t defaultDepth = numCases;
   5889 
   5890  // Subtract lowest case value, so that all the cases start from 0.
   5891  if (low) {
   5892    if (!CheckSwitchExpr(f, switchExpr)) {
   5893      return false;
   5894    }
   5895    if (!f.writeInt32Lit(low)) {
   5896      return false;
   5897    }
   5898    if (!f.encoder().writeOp(Op::I32Sub)) {
   5899      return false;
   5900    }
   5901  } else {
   5902    if (!CheckSwitchExpr(f, switchExpr)) {
   5903      return false;
   5904    }
   5905  }
   5906 
   5907  // Start the br_table block.
   5908  if (!f.encoder().writeOp(Op::BrTable)) {
   5909    return false;
   5910  }
   5911 
   5912  // Write the number of cases (tableLength - 1 + 1 (default)).
   5913  // Write the number of cases (tableLength - 1 + 1 (default)).
   5914  if (!f.encoder().writeVarU32(tableLength)) {
   5915    return false;
   5916  }
   5917 
   5918  // Each case value describes the relative depth to the actual block. When
   5919  // a case is not explicitly defined, it goes to the default.
   5920  for (size_t i = 0; i < tableLength; i++) {
   5921    uint32_t target =
   5922        caseDepths[i] == CASE_NOT_DEFINED ? defaultDepth : caseDepths[i];
   5923    if (!f.encoder().writeVarU32(target)) {
   5924      return false;
   5925    }
   5926  }
   5927 
   5928  // Write the default depth.
   5929  if (!f.encoder().writeVarU32(defaultDepth)) {
   5930    return false;
   5931  }
   5932 
   5933  // Our br_table is done. Close its block, write the cases down in order.
   5934  if (!f.popUnbreakableBlock()) {
   5935    return false;
   5936  }
   5937 
   5938  for (; stmt && !IsDefaultCase(stmt); stmt = NextNode(stmt)) {
   5939    if (!CheckStatement(f, CaseBody(stmt))) {
   5940      return false;
   5941    }
   5942    if (!f.popUnbreakableBlock()) {
   5943      return false;
   5944    }
   5945  }
   5946 
   5947  // Write the default block.
   5948  if (stmt && IsDefaultCase(stmt)) {
   5949    if (!CheckStatement(f, CaseBody(stmt))) {
   5950      return false;
   5951    }
   5952  }
   5953 
   5954  // Close the wrapping block.
   5955  return f.popBreakableBlock();
   5956 }
   5957 
   5958 static bool CheckReturnType(FunctionValidatorShared& f, ParseNode* usepn,
   5959                            Type ret) {
   5960  Maybe<ValType> type = ret.canonicalToReturnType();
   5961 
   5962  if (!f.hasAlreadyReturned()) {
   5963    f.setReturnedType(type);
   5964    return true;
   5965  }
   5966 
   5967  if (f.returnedType() != type) {
   5968    return f.failf(usepn, "%s incompatible with previous return of type %s",
   5969                   ToString(type, nullptr).get(),
   5970                   ToString(f.returnedType(), nullptr).get());
   5971  }
   5972 
   5973  return true;
   5974 }
   5975 
   5976 template <typename Unit>
   5977 static bool CheckReturn(FunctionValidator<Unit>& f, ParseNode* returnStmt) {
   5978  ParseNode* expr = ReturnExpr(returnStmt);
   5979 
   5980  if (!expr) {
   5981    if (!CheckReturnType(f, returnStmt, Type::Void)) {
   5982      return false;
   5983    }
   5984  } else {
   5985    Type type;
   5986    if (!CheckExpr(f, expr, &type)) {
   5987      return false;
   5988    }
   5989 
   5990    if (!type.isReturnType()) {
   5991      return f.failf(expr, "%s is not a valid return type", type.toChars());
   5992    }
   5993 
   5994    if (!CheckReturnType(f, expr, Type::canonicalize(type))) {
   5995      return false;
   5996    }
   5997  }
   5998 
   5999  return f.encoder().writeOp(Op::Return);
   6000 }
   6001 
   6002 template <typename Unit>
   6003 static bool CheckStatementList(FunctionValidator<Unit>& f, ParseNode* stmtList,
   6004                               const LabelVector* labels /*= nullptr */) {
   6005  MOZ_ASSERT(stmtList->isKind(ParseNodeKind::StatementList));
   6006 
   6007  if (!f.pushUnbreakableBlock(labels)) {
   6008    return false;
   6009  }
   6010 
   6011  for (ParseNode* stmt = ListHead(stmtList); stmt; stmt = NextNode(stmt)) {
   6012    if (!CheckStatement(f, stmt)) {
   6013      return false;
   6014    }
   6015  }
   6016 
   6017  return f.popUnbreakableBlock(labels);
   6018 }
   6019 
   6020 template <typename Unit>
   6021 static bool CheckLexicalScope(FunctionValidator<Unit>& f, ParseNode* node) {
   6022  LexicalScopeNode* lexicalScope = &node->as<LexicalScopeNode>();
   6023  if (!lexicalScope->isEmptyScope()) {
   6024    return f.fail(lexicalScope, "cannot have 'let' or 'const' declarations");
   6025  }
   6026 
   6027  return CheckStatement(f, lexicalScope->scopeBody());
   6028 }
   6029 
   6030 static bool CheckBreakOrContinue(FunctionValidatorShared& f, bool isBreak,
   6031                                 ParseNode* stmt) {
   6032  if (TaggedParserAtomIndex maybeLabel = LoopControlMaybeLabel(stmt)) {
   6033    return f.writeLabeledBreakOrContinue(maybeLabel, isBreak);
   6034  }
   6035  return f.writeUnlabeledBreakOrContinue(isBreak);
   6036 }
   6037 
   6038 template <typename Unit>
   6039 static bool CheckStatement(FunctionValidator<Unit>& f, ParseNode* stmt) {
   6040  AutoCheckRecursionLimit recursion(f.fc());
   6041  if (!recursion.checkDontReport(f.fc())) {
   6042    return f.m().failOverRecursed();
   6043  }
   6044 
   6045  switch (stmt->getKind()) {
   6046    case ParseNodeKind::EmptyStmt:
   6047      return true;
   6048    case ParseNodeKind::ExpressionStmt:
   6049      return CheckExprStatement(f, stmt);
   6050    case ParseNodeKind::WhileStmt:
   6051      return CheckWhile(f, stmt);
   6052    case ParseNodeKind::ForStmt:
   6053      return CheckFor(f, stmt);
   6054    case ParseNodeKind::DoWhileStmt:
   6055      return CheckDoWhile(f, stmt);
   6056    case ParseNodeKind::LabelStmt:
   6057      return CheckLabel(f, stmt);
   6058    case ParseNodeKind::IfStmt:
   6059      return CheckIf(f, stmt);
   6060    case ParseNodeKind::SwitchStmt:
   6061      return CheckSwitch(f, stmt);
   6062    case ParseNodeKind::ReturnStmt:
   6063      return CheckReturn(f, stmt);
   6064    case ParseNodeKind::StatementList:
   6065      return CheckStatementList(f, stmt);
   6066    case ParseNodeKind::BreakStmt:
   6067      return CheckBreakOrContinue(f, true, stmt);
   6068    case ParseNodeKind::ContinueStmt:
   6069      return CheckBreakOrContinue(f, false, stmt);
   6070    case ParseNodeKind::LexicalScope:
   6071      return CheckLexicalScope(f, stmt);
   6072    default:;
   6073  }
   6074 
   6075  return f.fail(stmt, "unexpected statement kind");
   6076 }
   6077 
   6078 template <typename Unit>
   6079 static bool ParseFunction(ModuleValidator<Unit>& m, FunctionNode** funNodeOut,
   6080                          unsigned* line) {
   6081  auto& tokenStream = m.tokenStream();
   6082 
   6083  tokenStream.consumeKnownToken(TokenKind::Function,
   6084                                TokenStreamShared::SlashIsRegExp);
   6085 
   6086  auto& anyChars = tokenStream.anyCharsAccess();
   6087  uint32_t toStringStart = anyChars.currentToken().pos.begin;
   6088  *line = anyChars.lineNumber(anyChars.lineToken(toStringStart));
   6089 
   6090  TokenKind tk;
   6091  if (!tokenStream.getToken(&tk, TokenStreamShared::SlashIsRegExp)) {
   6092    return false;
   6093  }
   6094  if (tk == TokenKind::Mul) {
   6095    return m.failCurrentOffset("unexpected generator function");
   6096  }
   6097  if (!TokenKindIsPossibleIdentifier(tk)) {
   6098    return false;  // The regular parser will throw a SyntaxError, no need to
   6099                   // m.fail.
   6100  }
   6101 
   6102  TaggedParserAtomIndex name = m.parser().bindingIdentifier(YieldIsName);
   6103  if (!name) {
   6104    return false;
   6105  }
   6106 
   6107  FunctionNode* funNode;
   6108  MOZ_TRY_VAR_OR_RETURN(funNode,
   6109                        m.parser().handler_.newFunction(
   6110                            FunctionSyntaxKind::Statement, m.parser().pos()),
   6111                        false);
   6112 
   6113  ParseContext* outerpc = m.parser().pc_;
   6114  Directives directives(outerpc);
   6115  FunctionFlags flags(FunctionFlags::INTERPRETED_NORMAL);
   6116  FunctionBox* funbox = m.parser().newFunctionBox(
   6117      funNode, name, flags, toStringStart, directives,
   6118      GeneratorKind::NotGenerator, FunctionAsyncKind::SyncFunction);
   6119  if (!funbox) {
   6120    return false;
   6121  }
   6122  funbox->initWithEnclosingParseContext(outerpc, FunctionSyntaxKind::Statement);
   6123 
   6124  Directives newDirectives = directives;
   6125  SourceParseContext funpc(&m.parser(), funbox, &newDirectives);
   6126  if (!funpc.init()) {
   6127    return false;
   6128  }
   6129 
   6130  if (!m.parser().functionFormalParametersAndBody(
   6131          InAllowed, YieldIsName, &funNode, FunctionSyntaxKind::Statement)) {
   6132    if (anyChars.hadError() || directives == newDirectives) {
   6133      return false;
   6134    }
   6135 
   6136    return m.fail(funNode, "encountered new directive in function");
   6137  }
   6138 
   6139  MOZ_ASSERT(!anyChars.hadError());
   6140  MOZ_ASSERT(directives == newDirectives);
   6141 
   6142  *funNodeOut = funNode;
   6143  return true;
   6144 }
   6145 
   6146 template <typename Unit>
   6147 static bool CheckFunction(ModuleValidator<Unit>& m) {
   6148  // asm.js modules can be quite large when represented as parse trees so pop
   6149  // the backing LifoAlloc after parsing/compiling each function. Release the
   6150  // parser's lifo memory after the last use of a parse node.
   6151  frontend::ParserBase::Mark mark = m.parser().mark();
   6152  auto releaseMark =
   6153      mozilla::MakeScopeExit([&m, &mark] { m.parser().release(mark); });
   6154 
   6155  FunctionNode* funNode = nullptr;
   6156  unsigned line = 0;
   6157  if (!ParseFunction(m, &funNode, &line)) {
   6158    return false;
   6159  }
   6160 
   6161  if (!CheckFunctionHead(m, funNode)) {
   6162    return false;
   6163  }
   6164 
   6165  FunctionValidator<Unit> f(m, funNode);
   6166 
   6167  ParseNode* stmtIter = ListHead(FunctionStatementList(funNode));
   6168 
   6169  if (!CheckProcessingDirectives(m, &stmtIter)) {
   6170    return false;
   6171  }
   6172 
   6173  ValTypeVector args;
   6174  if (!CheckArguments(f, &stmtIter, &args)) {
   6175    return false;
   6176  }
   6177 
   6178  if (!CheckVariables(f, &stmtIter)) {
   6179    return false;
   6180  }
   6181 
   6182  ParseNode* lastNonEmptyStmt = nullptr;
   6183  for (; stmtIter; stmtIter = NextNonEmptyStatement(stmtIter)) {
   6184    lastNonEmptyStmt = stmtIter;
   6185    if (!CheckStatement(f, stmtIter)) {
   6186      return false;
   6187    }
   6188  }
   6189 
   6190  if (!CheckFinalReturn(f, lastNonEmptyStmt)) {
   6191    return false;
   6192  }
   6193 
   6194  ValTypeVector results;
   6195  if (f.returnedType()) {
   6196    if (!results.append(f.returnedType().ref())) {
   6197      return false;
   6198    }
   6199  }
   6200 
   6201  FuncType sig(std::move(args), std::move(results));
   6202 
   6203  ModuleValidatorShared::Func* func = nullptr;
   6204  if (!CheckFunctionSignature(m, funNode, std::move(sig), FunctionName(funNode),
   6205                              &func)) {
   6206    return false;
   6207  }
   6208 
   6209  if (func->defined()) {
   6210    return m.failName(funNode, "function '%s' already defined",
   6211                      FunctionName(funNode));
   6212  }
   6213 
   6214  f.define(func, line);
   6215 
   6216  return true;
   6217 }
   6218 
   6219 static bool CheckAllFunctionsDefined(ModuleValidatorShared& m) {
   6220  for (unsigned i = 0; i < m.numFuncDefs(); i++) {
   6221    const ModuleValidatorShared::Func& f = m.funcDef(i);
   6222    if (!f.defined()) {
   6223      return m.failNameOffset(f.firstUse(), "missing definition of function %s",
   6224                              f.name());
   6225    }
   6226  }
   6227 
   6228  return true;
   6229 }
   6230 
   6231 template <typename Unit>
   6232 static bool CheckFunctions(ModuleValidator<Unit>& m) {
   6233  while (true) {
   6234    TokenKind tk;
   6235    if (!PeekToken(m.parser(), &tk)) {
   6236      return false;
   6237    }
   6238 
   6239    if (tk != TokenKind::Function) {
   6240      break;
   6241    }
   6242 
   6243    if (!CheckFunction(m)) {
   6244      return false;
   6245    }
   6246  }
   6247 
   6248  return CheckAllFunctionsDefined(m);
   6249 }
   6250 
   6251 template <typename Unit>
   6252 static bool CheckFuncPtrTable(ModuleValidator<Unit>& m, ParseNode* decl) {
   6253  if (!decl->isKind(ParseNodeKind::AssignExpr)) {
   6254    return m.fail(decl, "function-pointer table must have initializer");
   6255  }
   6256  AssignmentNode* assignNode = &decl->as<AssignmentNode>();
   6257 
   6258  ParseNode* var = assignNode->left();
   6259 
   6260  if (!var->isKind(ParseNodeKind::Name)) {
   6261    return m.fail(var, "function-pointer table name is not a plain name");
   6262  }
   6263 
   6264  ParseNode* arrayLiteral = assignNode->right();
   6265 
   6266  if (!arrayLiteral->isKind(ParseNodeKind::ArrayExpr)) {
   6267    return m.fail(
   6268        var, "function-pointer table's initializer must be an array literal");
   6269  }
   6270 
   6271  unsigned length = ListLength(arrayLiteral);
   6272 
   6273  if (!IsPowerOfTwo(length)) {
   6274    return m.failf(arrayLiteral,
   6275                   "function-pointer table length must be a power of 2 (is %u)",
   6276                   length);
   6277  }
   6278 
   6279  unsigned mask = length - 1;
   6280 
   6281  Uint32Vector elemFuncDefIndices;
   6282  const FuncType* sig = nullptr;
   6283  for (ParseNode* elem = ListHead(arrayLiteral); elem; elem = NextNode(elem)) {
   6284    if (!elem->isKind(ParseNodeKind::Name)) {
   6285      return m.fail(
   6286          elem, "function-pointer table's elements must be names of functions");
   6287    }
   6288 
   6289    TaggedParserAtomIndex funcName = elem->as<NameNode>().name();
   6290    const ModuleValidatorShared::Func* func = m.lookupFuncDef(funcName);
   6291    if (!func) {
   6292      return m.fail(
   6293          elem, "function-pointer table's elements must be names of functions");
   6294    }
   6295 
   6296    const FuncType& funcSig =
   6297        m.codeMeta()->types->type(func->sigIndex()).funcType();
   6298    if (sig) {
   6299      if (!FuncType::strictlyEquals(*sig, funcSig)) {
   6300        return m.fail(elem, "all functions in table must have same signature");
   6301      }
   6302    } else {
   6303      sig = &funcSig;
   6304    }
   6305 
   6306    if (!elemFuncDefIndices.append(func->funcDefIndex())) {
   6307      return false;
   6308    }
   6309  }
   6310 
   6311  FuncType copy;
   6312  if (!copy.clone(*sig)) {
   6313    return false;
   6314  }
   6315 
   6316  uint32_t tableIndex;
   6317  if (!CheckFuncPtrTableAgainstExisting(m, var, var->as<NameNode>().name(),
   6318                                        std::move(copy), mask, &tableIndex)) {
   6319    return false;
   6320  }
   6321 
   6322  if (!m.defineFuncPtrTable(tableIndex, std::move(elemFuncDefIndices))) {
   6323    return m.fail(var, "duplicate function-pointer definition");
   6324  }
   6325 
   6326  return true;
   6327 }
   6328 
   6329 template <typename Unit>
   6330 static bool CheckFuncPtrTables(ModuleValidator<Unit>& m) {
   6331  while (true) {
   6332    ParseNode* varStmt;
   6333    if (!ParseVarOrConstStatement(m.parser(), &varStmt)) {
   6334      return false;
   6335    }
   6336    if (!varStmt) {
   6337      break;
   6338    }
   6339    for (ParseNode* var = VarListHead(varStmt); var; var = NextNode(var)) {
   6340      if (!CheckFuncPtrTable(m, var)) {
   6341        return false;
   6342      }
   6343    }
   6344  }
   6345 
   6346  for (unsigned i = 0; i < m.numFuncPtrTables(); i++) {
   6347    ModuleValidatorShared::Table& table = m.table(i);
   6348    if (!table.defined()) {
   6349      return m.failNameOffset(table.firstUse(),
   6350                              "function-pointer table %s wasn't defined",
   6351                              table.name());
   6352    }
   6353  }
   6354 
   6355  return true;
   6356 }
   6357 
   6358 static bool CheckModuleExportFunction(
   6359    ModuleValidatorShared& m, ParseNode* pn,
   6360    TaggedParserAtomIndex maybeFieldName = TaggedParserAtomIndex::null()) {
   6361  if (!pn->isKind(ParseNodeKind::Name)) {
   6362    return m.fail(pn, "expected name of exported function");
   6363  }
   6364 
   6365  TaggedParserAtomIndex funcName = pn->as<NameNode>().name();
   6366  const ModuleValidatorShared::Func* func = m.lookupFuncDef(funcName);
   6367  if (!func) {
   6368    return m.failName(pn, "function '%s' not found", funcName);
   6369  }
   6370 
   6371  return m.addExportField(*func, maybeFieldName);
   6372 }
   6373 
   6374 static bool CheckModuleExportObject(ModuleValidatorShared& m,
   6375                                    ParseNode* object) {
   6376  MOZ_ASSERT(object->isKind(ParseNodeKind::ObjectExpr));
   6377 
   6378  for (ParseNode* pn = ListHead(object); pn; pn = NextNode(pn)) {
   6379    if (!IsNormalObjectField(pn)) {
   6380      return m.fail(pn,
   6381                    "only normal object properties may be used in the export "
   6382                    "object literal");
   6383    }
   6384 
   6385    TaggedParserAtomIndex fieldName = ObjectNormalFieldName(pn);
   6386 
   6387    ParseNode* initNode = ObjectNormalFieldInitializer(pn);
   6388    if (!initNode->isKind(ParseNodeKind::Name)) {
   6389      return m.fail(
   6390          initNode,
   6391          "initializer of exported object literal must be name of function");
   6392    }
   6393 
   6394    if (!CheckModuleExportFunction(m, initNode, fieldName)) {
   6395      return false;
   6396    }
   6397  }
   6398 
   6399  return true;
   6400 }
   6401 
   6402 template <typename Unit>
   6403 static bool CheckModuleReturn(ModuleValidator<Unit>& m) {
   6404  TokenKind tk;
   6405  if (!GetToken(m.parser(), &tk)) {
   6406    return false;
   6407  }
   6408  auto& ts = m.parser().tokenStream;
   6409  if (tk != TokenKind::Return) {
   6410    return m.failCurrentOffset(
   6411        (tk == TokenKind::RightCurly || tk == TokenKind::Eof)
   6412            ? "expecting return statement"
   6413            : "invalid asm.js. statement");
   6414  }
   6415  ts.anyCharsAccess().ungetToken();
   6416 
   6417  ParseNode* returnStmt;
   6418  MOZ_TRY_VAR_OR_RETURN(returnStmt, m.parser().statementListItem(YieldIsName),
   6419                        false);
   6420 
   6421  ParseNode* returnExpr = ReturnExpr(returnStmt);
   6422  if (!returnExpr) {
   6423    return m.fail(returnStmt, "export statement must return something");
   6424  }
   6425 
   6426  if (returnExpr->isKind(ParseNodeKind::ObjectExpr)) {
   6427    if (!CheckModuleExportObject(m, returnExpr)) {
   6428      return false;
   6429    }
   6430  } else {
   6431    if (!CheckModuleExportFunction(m, returnExpr)) {
   6432      return false;
   6433    }
   6434  }
   6435 
   6436  return true;
   6437 }
   6438 
   6439 template <typename Unit>
   6440 static bool CheckModuleEnd(ModuleValidator<Unit>& m) {
   6441  TokenKind tk;
   6442  if (!GetToken(m.parser(), &tk)) {
   6443    return false;
   6444  }
   6445 
   6446  if (tk != TokenKind::Eof && tk != TokenKind::RightCurly) {
   6447    return m.failCurrentOffset(
   6448        "top-level export (return) must be the last statement");
   6449  }
   6450 
   6451  m.parser().tokenStream.anyCharsAccess().ungetToken();
   6452  return true;
   6453 }
   6454 
   6455 template <typename Unit>
   6456 static SharedModule CheckModule(FrontendContext* fc,
   6457                                ParserAtomsTable& parserAtoms,
   6458                                AsmJSParser<Unit>& parser, ParseNode* stmtList,
   6459                                unsigned* time) {
   6460  int64_t before = PRMJ_Now();
   6461 
   6462  ScriptedCaller scriptedCaller;
   6463  if (parser.ss->filename()) {
   6464    scriptedCaller.line = 0;  // unused
   6465    scriptedCaller.filename = DuplicateString(parser.ss->filename());
   6466    if (!scriptedCaller.filename) {
   6467      return nullptr;
   6468    }
   6469  }
   6470 
   6471  // The default options are fine for asm.js
   6472  SharedCompileArgs args =
   6473      CompileArgs::buildForAsmJS(std::move(scriptedCaller));
   6474  if (!args) {
   6475    ReportOutOfMemory(fc);
   6476    return nullptr;
   6477  }
   6478 
   6479  MutableModuleMetadata moduleMeta = js_new<ModuleMetadata>();
   6480  if (!moduleMeta || !moduleMeta->init(*args, ModuleKind::AsmJS)) {
   6481    return nullptr;
   6482  }
   6483  MutableCodeMetadata codeMeta = moduleMeta->codeMeta;
   6484 
   6485  FunctionNode* moduleFunctionNode = parser.pc_->functionBox()->functionNode;
   6486 
   6487  ModuleValidator<Unit> m(fc, parserAtoms, moduleMeta, codeMeta, parser,
   6488                          moduleFunctionNode);
   6489  if (!m.init()) {
   6490    return nullptr;
   6491  }
   6492 
   6493  if (!CheckFunctionHead(m, moduleFunctionNode)) {
   6494    return nullptr;
   6495  }
   6496 
   6497  if (!CheckModuleArguments(m, moduleFunctionNode)) {
   6498    return nullptr;
   6499  }
   6500 
   6501  if (!CheckPrecedingStatements(m, stmtList)) {
   6502    return nullptr;
   6503  }
   6504 
   6505  if (!CheckModuleProcessingDirectives(m)) {
   6506    return nullptr;
   6507  }
   6508 
   6509  if (!CheckModuleGlobals(m)) {
   6510    return nullptr;
   6511  }
   6512 
   6513  if (!m.startFunctionBodies()) {
   6514    return nullptr;
   6515  }
   6516 
   6517  if (!CheckFunctions(m)) {
   6518    return nullptr;
   6519  }
   6520 
   6521  if (!CheckFuncPtrTables(m)) {
   6522    return nullptr;
   6523  }
   6524 
   6525  if (!CheckModuleReturn(m)) {
   6526    return nullptr;
   6527  }
   6528 
   6529  if (!CheckModuleEnd(m)) {
   6530    return nullptr;
   6531  }
   6532 
   6533  SharedModule module = m.finish();
   6534  if (!module) {
   6535    return nullptr;
   6536  }
   6537 
   6538  *time = (PRMJ_Now() - before) / PRMJ_USEC_PER_MSEC;
   6539  return module;
   6540 }
   6541 
   6542 /*****************************************************************************/
   6543 // Link-time validation
   6544 
   6545 static bool LinkFail(JSContext* cx, const char* str) {
   6546  WarnNumberASCII(cx, JSMSG_USE_ASM_LINK_FAIL, str);
   6547  return false;
   6548 }
   6549 
   6550 static bool IsMaybeWrappedScriptedProxy(JSObject* obj) {
   6551  JSObject* unwrapped = UncheckedUnwrap(obj);
   6552  return unwrapped && IsScriptedProxy(unwrapped);
   6553 }
   6554 
   6555 static bool GetDataProperty(JSContext* cx, HandleValue objVal,
   6556                            Handle<JSAtom*> field, MutableHandleValue v) {
   6557  if (!objVal.isObject()) {
   6558    return LinkFail(cx, "accessing property of non-object");
   6559  }
   6560 
   6561  RootedObject obj(cx, &objVal.toObject());
   6562  if (IsMaybeWrappedScriptedProxy(obj)) {
   6563    return LinkFail(cx, "accessing property of a Proxy");
   6564  }
   6565 
   6566  RootedId id(cx, AtomToId(field));
   6567  Rooted<mozilla::Maybe<PropertyDescriptor>> desc(cx);
   6568  RootedObject holder(cx);
   6569  if (!GetPropertyDescriptor(cx, obj, id, &desc, &holder)) {
   6570    return false;
   6571  }
   6572 
   6573  if (!desc.isSome()) {
   6574    return LinkFail(cx, "property not present on object");
   6575  }
   6576 
   6577  if (!desc->isDataDescriptor()) {
   6578    return LinkFail(cx, "property is not a data property");
   6579  }
   6580 
   6581  v.set(desc->value());
   6582  return true;
   6583 }
   6584 
   6585 static bool GetDataProperty(JSContext* cx, HandleValue objVal,
   6586                            const char* fieldChars, MutableHandleValue v) {
   6587  Rooted<JSAtom*> field(cx,
   6588                        AtomizeUTF8Chars(cx, fieldChars, strlen(fieldChars)));
   6589  if (!field) {
   6590    return false;
   6591  }
   6592 
   6593  return GetDataProperty(cx, objVal, field, v);
   6594 }
   6595 
   6596 static bool GetDataProperty(JSContext* cx, HandleValue objVal,
   6597                            const ImmutableTenuredPtr<PropertyName*>& field,
   6598                            MutableHandleValue v) {
   6599  Handle<PropertyName*> fieldHandle = field;
   6600  return GetDataProperty(cx, objVal, fieldHandle, v);
   6601 }
   6602 
   6603 static bool HasObjectValueOfMethodPure(JSObject* obj, JSContext* cx) {
   6604  Value v;
   6605  if (!GetPropertyPure(cx, obj, NameToId(cx->names().valueOf), &v)) {
   6606    return false;
   6607  }
   6608 
   6609  JSFunction* fun;
   6610  if (!IsFunctionObject(v, &fun)) {
   6611    return false;
   6612  }
   6613 
   6614  return IsSelfHostedFunctionWithName(fun, cx->names().Object_valueOf);
   6615 }
   6616 
   6617 static bool HasPureCoercion(JSContext* cx, HandleValue v) {
   6618  // Ideally, we'd reject all non-primitives, but Emscripten has a bug that
   6619  // generates code that passes functions for some imports. To avoid breaking
   6620  // all the code that contains this bug, we make an exception for functions
   6621  // that don't have user-defined valueOf or toString, for their coercions
   6622  // are not observable and coercion via ToNumber/ToInt32 definitely produces
   6623  // NaN/0. We should remove this special case later once most apps have been
   6624  // built with newer Emscripten.
   6625  return v.toObject().is<JSFunction>() &&
   6626         HasNoToPrimitiveMethodPure(&v.toObject(), cx) &&
   6627         HasObjectValueOfMethodPure(&v.toObject(), cx) &&
   6628         HasNativeMethodPure(&v.toObject(), cx->names().toString, fun_toString,
   6629                             cx);
   6630 }
   6631 
   6632 static bool ValidateGlobalVariable(JSContext* cx, const AsmJSGlobal& global,
   6633                                   HandleValue importVal,
   6634                                   Maybe<LitValPOD>* val) {
   6635  switch (global.varInitKind()) {
   6636    case AsmJSGlobal::InitConstant:
   6637      val->emplace(global.varInitVal());
   6638      return true;
   6639 
   6640    case AsmJSGlobal::InitImport: {
   6641      RootedValue v(cx);
   6642      if (!GetDataProperty(cx, importVal, global.field(), &v)) {
   6643        return false;
   6644      }
   6645 
   6646      if (!v.isPrimitive() && !HasPureCoercion(cx, v)) {
   6647        return LinkFail(cx, "Imported values must be primitives");
   6648      }
   6649 
   6650      switch (global.varInitImportType().kind()) {
   6651        case ValType::I32: {
   6652          int32_t i32;
   6653          if (!ToInt32(cx, v, &i32)) {
   6654            return false;
   6655          }
   6656          val->emplace(uint32_t(i32));
   6657          return true;
   6658        }
   6659        case ValType::I64:
   6660          MOZ_CRASH("int64");
   6661        case ValType::V128:
   6662          MOZ_CRASH("v128");
   6663        case ValType::F32: {
   6664          float f;
   6665          if (!RoundFloat32(cx, v, &f)) {
   6666            return false;
   6667          }
   6668          val->emplace(f);
   6669          return true;
   6670        }
   6671        case ValType::F64: {
   6672          double d;
   6673          if (!ToNumber(cx, v, &d)) {
   6674            return false;
   6675          }
   6676          val->emplace(d);
   6677          return true;
   6678        }
   6679        case ValType::Ref: {
   6680          MOZ_CRASH("not available in asm.js");
   6681        }
   6682      }
   6683    }
   6684  }
   6685 
   6686  MOZ_CRASH("unreachable");
   6687 }
   6688 
   6689 static bool ValidateFFI(JSContext* cx, const AsmJSGlobal& global,
   6690                        HandleValue importVal,
   6691                        MutableHandle<FunctionVector> ffis) {
   6692  RootedValue v(cx);
   6693  if (!GetDataProperty(cx, importVal, global.field(), &v)) {
   6694    return false;
   6695  }
   6696 
   6697  if (!IsFunctionObject(v)) {
   6698    return LinkFail(cx, "FFI imports must be functions");
   6699  }
   6700 
   6701  ffis[global.ffiIndex()].set(&v.toObject().as<JSFunction>());
   6702  return true;
   6703 }
   6704 
   6705 static bool ValidateArrayView(JSContext* cx, const AsmJSGlobal& global,
   6706                              HandleValue globalVal) {
   6707  if (!global.field()) {
   6708    return true;
   6709  }
   6710 
   6711  if (Scalar::isBigIntType(global.viewType())) {
   6712    return LinkFail(cx, "bad typed array constructor");
   6713  }
   6714 
   6715  RootedValue v(cx);
   6716  if (!GetDataProperty(cx, globalVal, global.field(), &v)) {
   6717    return false;
   6718  }
   6719 
   6720  bool tac = IsTypedArrayConstructor(v, global.viewType());
   6721  if (!tac) {
   6722    return LinkFail(cx, "bad typed array constructor");
   6723  }
   6724 
   6725  return true;
   6726 }
   6727 
   6728 static InlinableNative ToInlinableNative(AsmJSMathBuiltinFunction func) {
   6729  switch (func) {
   6730    case AsmJSMathBuiltin_sin:
   6731      return InlinableNative::MathSin;
   6732    case AsmJSMathBuiltin_cos:
   6733      return InlinableNative::MathCos;
   6734    case AsmJSMathBuiltin_tan:
   6735      return InlinableNative::MathTan;
   6736    case AsmJSMathBuiltin_asin:
   6737      return InlinableNative::MathASin;
   6738    case AsmJSMathBuiltin_acos:
   6739      return InlinableNative::MathACos;
   6740    case AsmJSMathBuiltin_atan:
   6741      return InlinableNative::MathATan;
   6742    case AsmJSMathBuiltin_ceil:
   6743      return InlinableNative::MathCeil;
   6744    case AsmJSMathBuiltin_floor:
   6745      return InlinableNative::MathFloor;
   6746    case AsmJSMathBuiltin_exp:
   6747      return InlinableNative::MathExp;
   6748    case AsmJSMathBuiltin_log:
   6749      return InlinableNative::MathLog;
   6750    case AsmJSMathBuiltin_pow:
   6751      return InlinableNative::MathPow;
   6752    case AsmJSMathBuiltin_sqrt:
   6753      return InlinableNative::MathSqrt;
   6754    case AsmJSMathBuiltin_abs:
   6755      return InlinableNative::MathAbs;
   6756    case AsmJSMathBuiltin_atan2:
   6757      return InlinableNative::MathATan2;
   6758    case AsmJSMathBuiltin_imul:
   6759      return InlinableNative::MathImul;
   6760    case AsmJSMathBuiltin_fround:
   6761      return InlinableNative::MathFRound;
   6762    case AsmJSMathBuiltin_min:
   6763      return InlinableNative::MathMin;
   6764    case AsmJSMathBuiltin_max:
   6765      return InlinableNative::MathMax;
   6766    case AsmJSMathBuiltin_clz32:
   6767      return InlinableNative::MathClz32;
   6768  }
   6769  MOZ_CRASH("Invalid asm.js math builtin function");
   6770 }
   6771 
   6772 static bool ValidateMathBuiltinFunction(
   6773    JSContext* cx, const CodeMetadataForAsmJSImpl& codeMetaForAsmJS,
   6774    const AsmJSGlobal& global, HandleValue globalVal) {
   6775  RootedValue v(cx);
   6776  if (!GetDataProperty(cx, globalVal, cx->names().Math, &v)) {
   6777    return false;
   6778  }
   6779 
   6780  if (!GetDataProperty(cx, v, global.field(), &v)) {
   6781    return false;
   6782  }
   6783 
   6784  InlinableNative native = ToInlinableNative(global.mathBuiltinFunction());
   6785 
   6786  JSFunction* fun;
   6787  if (!IsFunctionObject(v, &fun) || !fun->hasJitInfo() ||
   6788      fun->jitInfo()->type() != JSJitInfo::InlinableNative ||
   6789      fun->jitInfo()->inlinableNative != native) {
   6790    return LinkFail(cx, "bad Math.* builtin function");
   6791  }
   6792  if (fun->realm()->creationOptions().alwaysUseFdlibm() !=
   6793      codeMetaForAsmJS.alwaysUseFdlibm) {
   6794    return LinkFail(cx,
   6795                    "Math.* builtin function and asm.js use different native"
   6796                    " math implementations.");
   6797  }
   6798 
   6799  return true;
   6800 }
   6801 
   6802 static bool ValidateConstant(JSContext* cx, const AsmJSGlobal& global,
   6803                             HandleValue globalVal) {
   6804  RootedValue v(cx, globalVal);
   6805 
   6806  if (global.constantKind() == AsmJSGlobal::MathConstant) {
   6807    if (!GetDataProperty(cx, v, cx->names().Math, &v)) {
   6808      return false;
   6809    }
   6810  }
   6811 
   6812  if (!GetDataProperty(cx, v, global.field(), &v)) {
   6813    return false;
   6814  }
   6815 
   6816  if (!v.isNumber()) {
   6817    return LinkFail(cx, "math / global constant value needs to be a number");
   6818  }
   6819 
   6820  // NaN != NaN
   6821  if (std::isnan(global.constantValue())) {
   6822    if (!std::isnan(v.toNumber())) {
   6823      return LinkFail(cx, "global constant value needs to be NaN");
   6824    }
   6825  } else {
   6826    if (v.toNumber() != global.constantValue()) {
   6827      return LinkFail(cx, "global constant value mismatch");
   6828    }
   6829  }
   6830 
   6831  return true;
   6832 }
   6833 
   6834 static bool CheckBuffer(JSContext* cx, const CodeMetadata& codeMeta,
   6835                        HandleValue bufferVal,
   6836                        MutableHandle<ArrayBufferObject*> buffer) {
   6837  if (!bufferVal.isObject()) {
   6838    return LinkFail(cx, "buffer must be an object");
   6839  }
   6840  JSObject* bufferObj = &bufferVal.toObject();
   6841 
   6842  if (codeMeta.memories[0].isShared()) {
   6843    if (!bufferObj->is<SharedArrayBufferObject>()) {
   6844      return LinkFail(
   6845          cx, "shared views can only be constructed onto SharedArrayBuffer");
   6846    }
   6847    return LinkFail(cx, "Unable to prepare SharedArrayBuffer for asm.js use");
   6848  }
   6849 
   6850  if (!bufferObj->is<ArrayBufferObject>()) {
   6851    return LinkFail(cx,
   6852                    "unshared views can only be constructed onto ArrayBuffer");
   6853  }
   6854 
   6855  buffer.set(&bufferObj->as<ArrayBufferObject>());
   6856 
   6857  size_t memoryLength = buffer->byteLength();
   6858 
   6859  if (!IsValidAsmJSHeapLength(memoryLength)) {
   6860    UniqueChars msg;
   6861    if (memoryLength > MaxHeapLength) {
   6862      msg = JS_smprintf("ArrayBuffer byteLength 0x%" PRIx64
   6863                        " is not a valid heap length - it is too long."
   6864                        " The longest valid length is 0x%" PRIx64,
   6865                        uint64_t(memoryLength), MaxHeapLength);
   6866    } else {
   6867      msg = JS_smprintf("ArrayBuffer byteLength 0x%" PRIx64
   6868                        " is not a valid heap length. The next "
   6869                        "valid length is 0x%" PRIx64,
   6870                        uint64_t(memoryLength),
   6871                        RoundUpToNextValidAsmJSHeapLength(memoryLength));
   6872    }
   6873    if (!msg) {
   6874      return false;
   6875    }
   6876    return LinkFail(cx, msg.get());
   6877  }
   6878 
   6879  // This check is sufficient without considering the size of the loaded datum
   6880  // because heap loads and stores start on an aligned boundary and the heap
   6881  // byteLength has larger alignment.
   6882  uint64_t minMemoryLength = codeMeta.memories.length() != 0
   6883                                 ? codeMeta.memories[0].initialLength()
   6884                                 : 0;
   6885  MOZ_ASSERT((minMemoryLength - 1) <= INT32_MAX);
   6886  if (memoryLength < minMemoryLength) {
   6887    UniqueChars msg(JS_smprintf("ArrayBuffer byteLength of 0x%" PRIx64
   6888                                " is less than 0x%" PRIx64 " (the "
   6889                                "size implied "
   6890                                "by const heap accesses).",
   6891                                uint64_t(memoryLength), minMemoryLength));
   6892    if (!msg) {
   6893      return false;
   6894    }
   6895    return LinkFail(cx, msg.get());
   6896  }
   6897 
   6898  // ArrayBuffer lengths in SpiderMonkey used to be restricted to <= INT32_MAX,
   6899  // but that has since been relaxed for the benefit of wasm.  We keep the old
   6900  // limit for asm.js so as to avoid having to worry about whether the asm.js
   6901  // implementation is safe for larger heaps.
   6902  if (memoryLength >= INT32_MAX) {
   6903    UniqueChars msg(
   6904        JS_smprintf("ArrayBuffer byteLength 0x%" PRIx64
   6905                    " is too large for asm.js (implementation limit).",
   6906                    uint64_t(memoryLength)));
   6907    if (!msg) {
   6908      return false;
   6909    }
   6910    return LinkFail(cx, msg.get());
   6911  }
   6912 
   6913  if (buffer->isResizable()) {
   6914    return LinkFail(cx,
   6915                    "Unable to prepare resizable ArrayBuffer for asm.js use");
   6916  }
   6917 
   6918  if (buffer->isImmutable()) {
   6919    return LinkFail(cx,
   6920                    "Unable to prepare immutable ArrayBuffer for asm.js use");
   6921  }
   6922 
   6923  if (!buffer->prepareForAsmJS()) {
   6924    return LinkFail(cx, "Unable to prepare ArrayBuffer for asm.js use");
   6925  }
   6926 
   6927  MOZ_ASSERT(buffer->isPreparedForAsmJS());
   6928  return true;
   6929 }
   6930 
   6931 static bool GetImports(JSContext* cx,
   6932                       const CodeMetadataForAsmJSImpl& codeMetaForAsmJS,
   6933                       HandleValue globalVal, HandleValue importVal,
   6934                       ImportValues* imports) {
   6935  Rooted<FunctionVector> ffis(cx, FunctionVector(cx));
   6936  if (!ffis.resize(codeMetaForAsmJS.numFFIs)) {
   6937    return false;
   6938  }
   6939 
   6940  for (const AsmJSGlobal& global : codeMetaForAsmJS.asmJSGlobals) {
   6941    switch (global.which()) {
   6942      case AsmJSGlobal::Variable: {
   6943        Maybe<LitValPOD> litVal;
   6944        if (!ValidateGlobalVariable(cx, global, importVal, &litVal)) {
   6945          return false;
   6946        }
   6947        if (!imports->globalValues.append(Val(litVal->asLitVal()))) {
   6948          return false;
   6949        }
   6950        break;
   6951      }
   6952      case AsmJSGlobal::FFI:
   6953        if (!ValidateFFI(cx, global, importVal, &ffis)) {
   6954          return false;
   6955        }
   6956        break;
   6957      case AsmJSGlobal::ArrayView:
   6958      case AsmJSGlobal::ArrayViewCtor:
   6959        if (!ValidateArrayView(cx, global, globalVal)) {
   6960          return false;
   6961        }
   6962        break;
   6963      case AsmJSGlobal::MathBuiltinFunction:
   6964        if (!ValidateMathBuiltinFunction(cx, codeMetaForAsmJS, global,
   6965                                         globalVal)) {
   6966          return false;
   6967        }
   6968        break;
   6969      case AsmJSGlobal::Constant:
   6970        if (!ValidateConstant(cx, global, globalVal)) {
   6971          return false;
   6972        }
   6973        break;
   6974    }
   6975  }
   6976 
   6977  for (const AsmJSImport& import : codeMetaForAsmJS.asmJSImports) {
   6978    if (!imports->funcs.append(ffis[import.ffiIndex()])) {
   6979      return false;
   6980    }
   6981  }
   6982 
   6983  return true;
   6984 }
   6985 
   6986 static bool TryInstantiate(JSContext* cx, const CallArgs& args,
   6987                           const Module& module,
   6988                           const CodeMetadataForAsmJSImpl& codeMetaForAsmJS,
   6989                           MutableHandle<WasmInstanceObject*> instanceObj,
   6990                           MutableHandleObject exportObj) {
   6991  HandleValue globalVal = args.get(0);
   6992  HandleValue importVal = args.get(1);
   6993  HandleValue bufferVal = args.get(2);
   6994 
   6995  MOZ_RELEASE_ASSERT(HasPlatformSupport());
   6996 
   6997  if (!wasm::EnsureFullSignalHandlers(cx)) {
   6998    return LinkFail(cx, "failed to install signal handlers");
   6999  }
   7000 
   7001  Rooted<ImportValues> imports(cx);
   7002 
   7003  if (module.codeMeta().memories.length() != 0) {
   7004    MOZ_ASSERT(module.codeMeta().memories.length() == 1);
   7005    Rooted<ArrayBufferObject*> buffer(cx);
   7006    if (!CheckBuffer(cx, module.codeMeta(), bufferVal, &buffer)) {
   7007      return false;
   7008    }
   7009 
   7010    Rooted<WasmMemoryObject*> memory(
   7011        cx, WasmMemoryObject::create(cx, buffer, /* isHuge= */ false, nullptr));
   7012    if (!memory || !imports.get().memories.append(memory)) {
   7013      return false;
   7014    }
   7015  }
   7016 
   7017  if (!GetImports(cx, codeMetaForAsmJS, globalVal, importVal,
   7018                  imports.address())) {
   7019    return false;
   7020  }
   7021 
   7022  if (!module.instantiate(cx, imports.get(), nullptr, instanceObj)) {
   7023    return false;
   7024  }
   7025 
   7026  exportObj.set(&instanceObj->exportsObj());
   7027  return true;
   7028 }
   7029 
   7030 static bool HandleInstantiationFailure(
   7031    JSContext* cx, const CallArgs& args,
   7032    const CodeMetadataForAsmJSImpl& codeMetaForAsmJS) {
   7033  using js::frontend::FunctionSyntaxKind;
   7034 
   7035  Rooted<JSAtom*> name(cx, args.callee().as<JSFunction>().fullExplicitName());
   7036 
   7037  if (cx->isExceptionPending()) {
   7038    return false;
   7039  }
   7040 
   7041  ScriptSource* source = codeMetaForAsmJS.maybeScriptSource();
   7042 
   7043  // Source discarding is allowed to affect JS semantics because it is never
   7044  // enabled for normal JS content.
   7045  bool haveSource;
   7046  if (!ScriptSource::loadSource(cx, source, &haveSource)) {
   7047    return false;
   7048  }
   7049  if (!haveSource) {
   7050    JS_ReportErrorASCII(cx,
   7051                        "asm.js link failure with source discarding enabled");
   7052    return false;
   7053  }
   7054 
   7055  uint32_t begin = codeMetaForAsmJS.toStringStart;
   7056  uint32_t end = codeMetaForAsmJS.srcEndAfterCurly();
   7057  Rooted<JSLinearString*> src(cx, source->substringDontDeflate(cx, begin, end));
   7058  if (!src) {
   7059    return false;
   7060  }
   7061 
   7062  JS::CompileOptions options(cx);
   7063  options.setMutedErrors(source->mutedErrors())
   7064      .setFile(source->filename())
   7065      .setNoScriptRval(false);
   7066  options.setAsmJSOption(AsmJSOption::DisabledByLinker);
   7067 
   7068  // The exported function inherits an implicit strict context if the module
   7069  // also inherited it somehow.
   7070  if (codeMetaForAsmJS.strict) {
   7071    options.setForceStrictMode();
   7072  }
   7073 
   7074  AutoStableStringChars linearChars(cx);
   7075  if (!linearChars.initTwoByte(cx, src)) {
   7076    return false;
   7077  }
   7078 
   7079  SourceText<char16_t> srcBuf;
   7080  if (!srcBuf.initMaybeBorrowed(cx, linearChars)) {
   7081    return false;
   7082  }
   7083 
   7084  FunctionSyntaxKind syntaxKind = FunctionSyntaxKind::Statement;
   7085 
   7086  RootedFunction fun(cx, frontend::CompileStandaloneFunction(
   7087                             cx, options, srcBuf, Nothing(), syntaxKind));
   7088  if (!fun) {
   7089    return false;
   7090  }
   7091 
   7092  fun->initEnvironment(&cx->global()->lexicalEnvironment());
   7093 
   7094  // Call the function we just recompiled.
   7095  args.setCallee(ObjectValue(*fun));
   7096  return InternalCallOrConstruct(
   7097      cx, args, args.isConstructing() ? CONSTRUCT : NO_CONSTRUCT);
   7098 }
   7099 
   7100 static const Module& AsmJSModuleFunctionToModule(JSFunction* fun) {
   7101  MOZ_ASSERT(IsAsmJSModule(fun));
   7102  const Value& v = fun->getExtendedSlot(FunctionExtended::ASMJS_MODULE_SLOT);
   7103  return v.toObject().as<WasmModuleObject>().module();
   7104 }
   7105 
   7106 // Implements the semantics of an asm.js module function that has been
   7107 // successfully validated.
   7108 bool js::InstantiateAsmJS(JSContext* cx, unsigned argc, JS::Value* vp) {
   7109  CallArgs args = CallArgsFromVp(argc, vp);
   7110 
   7111  JSFunction* callee = &args.callee().as<JSFunction>();
   7112  const Module& module = AsmJSModuleFunctionToModule(callee);
   7113  const CodeMetadataForAsmJSImpl& codeMetaForAsmJS =
   7114      module.codeMetaForAsmJS()->asAsmJS();
   7115 
   7116  Rooted<WasmInstanceObject*> instanceObj(cx);
   7117  RootedObject exportObj(cx);
   7118  if (!TryInstantiate(cx, args, module, codeMetaForAsmJS, &instanceObj,
   7119                      &exportObj)) {
   7120    // Link-time validation checks failed, so reparse the entire asm.js
   7121    // module from scratch to get normal interpreted bytecode which we can
   7122    // simply Invoke. Very slow.
   7123    return HandleInstantiationFailure(cx, args, codeMetaForAsmJS);
   7124  }
   7125 
   7126  args.rval().set(ObjectValue(*exportObj));
   7127  return true;
   7128 }
   7129 
   7130 /*****************************************************************************/
   7131 // Top-level js::CompileAsmJS
   7132 
   7133 static bool NoExceptionPending(FrontendContext* fc) { return !fc->hadErrors(); }
   7134 
   7135 static bool SuccessfulValidation(frontend::ParserBase& parser,
   7136                                 unsigned compilationTime) {
   7137  unsigned errNum = js::SupportDifferentialTesting()
   7138                        ? JSMSG_USE_ASM_TYPE_OK_NO_TIME
   7139                        : JSMSG_USE_ASM_TYPE_OK;
   7140 
   7141  char timeChars[20];
   7142  SprintfLiteral(timeChars, "%u", compilationTime);
   7143 
   7144  return parser.warningNoOffset(errNum, timeChars);
   7145 }
   7146 
   7147 static bool TypeFailureWarning(frontend::ParserBase& parser, const char* str) {
   7148  if (parser.options().throwOnAsmJSValidationFailure()) {
   7149    parser.errorNoOffset(JSMSG_USE_ASM_TYPE_FAIL, str ? str : "");
   7150    return false;
   7151  }
   7152 
   7153  // Per the asm.js standard convention, whether failure sets a pending
   7154  // exception determines whether to attempt non-asm.js reparsing, so ignore
   7155  // the return value below.
   7156  (void)parser.warningNoOffset(JSMSG_USE_ASM_TYPE_FAIL, str ? str : "");
   7157  return false;
   7158 }
   7159 
   7160 // asm.js requires Ion to be available on the current hardware/OS and to be
   7161 // enabled for wasm, since asm.js compilation goes via wasm.
   7162 static bool IsAsmJSCompilerAvailable(JSContext* cx) {
   7163  return HasPlatformSupport() && WasmCompilerForAsmJSAvailable(cx);
   7164 }
   7165 
   7166 static bool EstablishPreconditions(frontend::ParserBase& parser) {
   7167  switch (parser.options().asmJSOption()) {
   7168    case AsmJSOption::DisabledByAsmJSPref:
   7169      return TypeFailureWarning(
   7170          parser, "Asm.js optimizer disabled by 'asmjs' runtime option");
   7171    case AsmJSOption::DisabledByLinker:
   7172      return TypeFailureWarning(
   7173          parser,
   7174          "Asm.js optimizer disabled by linker (instantiation failure)");
   7175    case AsmJSOption::DisabledByNoWasmCompiler:
   7176      return TypeFailureWarning(parser,
   7177                                "Asm.js optimizer disabled because no suitable "
   7178                                "wasm compiler is available");
   7179    case AsmJSOption::DisabledByDebugger:
   7180      return TypeFailureWarning(
   7181          parser, "Asm.js optimizer disabled because debugger is active");
   7182    case AsmJSOption::Enabled:
   7183      break;
   7184  }
   7185 
   7186  if (parser.pc_->isGenerator()) {
   7187    return TypeFailureWarning(parser,
   7188                              "Asm.js optimizer disabled in generator context");
   7189  }
   7190 
   7191  if (parser.pc_->isAsync()) {
   7192    return TypeFailureWarning(parser,
   7193                              "Asm.js optimizer disabled in async context");
   7194  }
   7195 
   7196  if (parser.pc_->isArrowFunction()) {
   7197    return TypeFailureWarning(
   7198        parser, "Asm.js optimizer disabled in arrow function context");
   7199  }
   7200 
   7201  // Class constructors are also methods
   7202  if (parser.pc_->isMethod() || parser.pc_->isGetterOrSetter()) {
   7203    return TypeFailureWarning(
   7204        parser,
   7205        "Asm.js optimizer disabled in class constructor or method context");
   7206  }
   7207 
   7208  return true;
   7209 }
   7210 
   7211 template <typename Unit>
   7212 static bool DoCompileAsmJS(FrontendContext* fc, ParserAtomsTable& parserAtoms,
   7213                           AsmJSParser<Unit>& parser, ParseNode* stmtList,
   7214                           bool* validated) {
   7215  *validated = false;
   7216 
   7217  // Various conditions disable asm.js optimizations.
   7218  if (!EstablishPreconditions(parser)) {
   7219    return NoExceptionPending(fc);
   7220  }
   7221 
   7222  // "Checking" parses, validates and compiles, producing a fully compiled
   7223  // WasmModuleObject as result.
   7224  unsigned time;
   7225  SharedModule module = CheckModule(fc, parserAtoms, parser, stmtList, &time);
   7226  if (!module) {
   7227    return NoExceptionPending(fc);
   7228  }
   7229 
   7230  // Finished! Save the ref-counted module on the FunctionBox. When JSFunctions
   7231  // are eventually allocated we will create an asm.js constructor for it.
   7232  FunctionBox* funbox = parser.pc_->functionBox();
   7233  MOZ_ASSERT(funbox->isInterpreted());
   7234  if (!funbox->setAsmJSModule(module)) {
   7235    return NoExceptionPending(fc);
   7236  }
   7237 
   7238  // Success! Write to the console with a "warning" message indicating
   7239  // total compilation time.
   7240  *validated = true;
   7241  SuccessfulValidation(parser, time);
   7242  return NoExceptionPending(fc);
   7243 }
   7244 
   7245 bool js::CompileAsmJS(FrontendContext* fc, ParserAtomsTable& parserAtoms,
   7246                      AsmJSParser<char16_t>& parser, ParseNode* stmtList,
   7247                      bool* validated) {
   7248  return DoCompileAsmJS(fc, parserAtoms, parser, stmtList, validated);
   7249 }
   7250 
   7251 bool js::CompileAsmJS(FrontendContext* fc, ParserAtomsTable& parserAtoms,
   7252                      AsmJSParser<Utf8Unit>& parser, ParseNode* stmtList,
   7253                      bool* validated) {
   7254  return DoCompileAsmJS(fc, parserAtoms, parser, stmtList, validated);
   7255 }
   7256 
   7257 /*****************************************************************************/
   7258 // asm.js testing functions
   7259 
   7260 bool js::IsAsmJSModuleNative(Native native) {
   7261  return native == InstantiateAsmJS;
   7262 }
   7263 
   7264 bool js::IsAsmJSModule(JSFunction* fun) {
   7265  return fun->maybeNative() == InstantiateAsmJS;
   7266 }
   7267 
   7268 bool js::IsAsmJSFunction(JSFunction* fun) {
   7269  return fun->kind() == FunctionFlags::AsmJS;
   7270 }
   7271 
   7272 bool js::IsAsmJSStrictModeModuleOrFunction(JSFunction* fun) {
   7273  if (IsAsmJSModule(fun)) {
   7274    return AsmJSModuleFunctionToModule(fun)
   7275        .codeMetaForAsmJS()
   7276        ->asAsmJS()
   7277        .strict;
   7278  }
   7279 
   7280  if (IsAsmJSFunction(fun)) {
   7281    return fun->wasmInstance().codeMetaForAsmJS()->asAsmJS().strict;
   7282  }
   7283 
   7284  return false;
   7285 }
   7286 
   7287 bool js::IsAsmJSCompilationAvailable(JSContext* cx) {
   7288  return cx->options().asmJS() && IsAsmJSCompilerAvailable(cx);
   7289 }
   7290 
   7291 bool js::IsAsmJSCompilationAvailable(JSContext* cx, unsigned argc, Value* vp) {
   7292  CallArgs args = CallArgsFromVp(argc, vp);
   7293  bool available = IsAsmJSCompilationAvailable(cx);
   7294  args.rval().set(BooleanValue(available));
   7295  return true;
   7296 }
   7297 
   7298 static JSFunction* MaybeWrappedNativeFunction(const Value& v) {
   7299  if (!v.isObject()) {
   7300    return nullptr;
   7301  }
   7302 
   7303  return v.toObject().maybeUnwrapIf<JSFunction>();
   7304 }
   7305 
   7306 bool js::IsAsmJSModule(JSContext* cx, unsigned argc, Value* vp) {
   7307  CallArgs args = CallArgsFromVp(argc, vp);
   7308 
   7309  bool rval = false;
   7310  if (JSFunction* fun = MaybeWrappedNativeFunction(args.get(0))) {
   7311    rval = IsAsmJSModule(fun);
   7312  }
   7313 
   7314  args.rval().set(BooleanValue(rval));
   7315  return true;
   7316 }
   7317 
   7318 bool js::IsAsmJSFunction(JSContext* cx, unsigned argc, Value* vp) {
   7319  CallArgs args = CallArgsFromVp(argc, vp);
   7320 
   7321  bool rval = false;
   7322  if (JSFunction* fun = MaybeWrappedNativeFunction(args.get(0))) {
   7323    rval = IsAsmJSFunction(fun);
   7324  }
   7325 
   7326  args.rval().set(BooleanValue(rval));
   7327  return true;
   7328 }
   7329 
   7330 /*****************************************************************************/
   7331 // asm.js toString/toSource support
   7332 
   7333 JSString* js::AsmJSModuleToString(JSContext* cx, HandleFunction fun,
   7334                                  bool isToSource) {
   7335  MOZ_ASSERT(IsAsmJSModule(fun));
   7336 
   7337  const CodeMetadataForAsmJSImpl& codeMetaForAsmJS =
   7338      AsmJSModuleFunctionToModule(fun).codeMetaForAsmJS()->asAsmJS();
   7339  uint32_t begin = codeMetaForAsmJS.toStringStart;
   7340  uint32_t end = codeMetaForAsmJS.srcEndAfterCurly();
   7341  ScriptSource* source = codeMetaForAsmJS.maybeScriptSource();
   7342 
   7343  JSStringBuilder out(cx);
   7344 
   7345  if (isToSource && fun->isLambda() && !out.append("(")) {
   7346    return nullptr;
   7347  }
   7348 
   7349  bool haveSource;
   7350  if (!ScriptSource::loadSource(cx, source, &haveSource)) {
   7351    return nullptr;
   7352  }
   7353 
   7354  if (!haveSource) {
   7355    if (!out.append("function ")) {
   7356      return nullptr;
   7357    }
   7358    if (fun->fullExplicitName() && !out.append(fun->fullExplicitName())) {
   7359      return nullptr;
   7360    }
   7361    if (!out.append("() {\n    [native code]\n}")) {
   7362      return nullptr;
   7363    }
   7364  } else {
   7365    Rooted<JSLinearString*> src(cx, source->substring(cx, begin, end));
   7366    if (!src) {
   7367      return nullptr;
   7368    }
   7369 
   7370    if (!out.append(src)) {
   7371      return nullptr;
   7372    }
   7373  }
   7374 
   7375  if (isToSource && fun->isLambda() && !out.append(")")) {
   7376    return nullptr;
   7377  }
   7378 
   7379  return out.finishString();
   7380 }
   7381 
   7382 JSString* js::AsmJSFunctionToString(JSContext* cx, HandleFunction fun) {
   7383  MOZ_ASSERT(IsAsmJSFunction(fun));
   7384 
   7385  const CodeMetadataForAsmJSImpl& codeMetaForAsmJS =
   7386      fun->wasmInstance().codeMetaForAsmJS()->asAsmJS();
   7387  const AsmJSExport& f =
   7388      codeMetaForAsmJS.lookupAsmJSExport(fun->wasmFuncIndex());
   7389 
   7390  uint32_t begin = codeMetaForAsmJS.srcStart + f.startOffsetInModule();
   7391  uint32_t end = codeMetaForAsmJS.srcStart + f.endOffsetInModule();
   7392 
   7393  ScriptSource* source = codeMetaForAsmJS.maybeScriptSource();
   7394  JSStringBuilder out(cx);
   7395 
   7396  if (!out.append("function ")) {
   7397    return nullptr;
   7398  }
   7399 
   7400  bool haveSource;
   7401  if (!ScriptSource::loadSource(cx, source, &haveSource)) {
   7402    return nullptr;
   7403  }
   7404 
   7405  if (!haveSource) {
   7406    // asm.js functions can't be anonymous
   7407    MOZ_ASSERT(fun->fullExplicitName());
   7408    if (!out.append(fun->fullExplicitName())) {
   7409      return nullptr;
   7410    }
   7411    if (!out.append("() {\n    [native code]\n}")) {
   7412      return nullptr;
   7413    }
   7414  } else {
   7415    Rooted<JSLinearString*> src(cx, source->substring(cx, begin, end));
   7416    if (!src) {
   7417      return nullptr;
   7418    }
   7419    if (!out.append(src)) {
   7420      return nullptr;
   7421    }
   7422  }
   7423 
   7424  return out.finishString();
   7425 }
   7426 
   7427 bool js::IsValidAsmJSHeapLength(size_t length) {
   7428  if (length < MinHeapLength) {
   7429    return false;
   7430  }
   7431 
   7432  // The heap length is limited by what a wasm memory32 can handle.
   7433  if (length > MaxMemoryBytes(AddressType::I32, wasm::PageSize::Standard)) {
   7434    return false;
   7435  }
   7436 
   7437  // asm.js specifies that the heap size must fit in an ARM immediate.
   7438  return IsValidARMImmediate(length);
   7439 }