LCOV - code coverage report
Current view: top level - src/asmjs - asm-parser.cc (source / functions) Hit Total Coverage
Test: app.info Lines: 1200 1301 92.2 %
Date: 2019-03-21 Functions: 63 73 86.3 %

          Line data    Source code
       1             : // Copyright 2017 the V8 project authors. All rights reserved.
       2             : // Use of this source code is governed by a BSD-style license that can be
       3             : // found in the LICENSE file.
       4             : 
       5             : #include "src/asmjs/asm-parser.h"
       6             : 
       7             : #include <math.h>
       8             : #include <string.h>
       9             : 
      10             : #include <algorithm>
      11             : 
      12             : #include "src/asmjs/asm-js.h"
      13             : #include "src/asmjs/asm-types.h"
      14             : #include "src/base/optional.h"
      15             : #include "src/base/overflowing-math.h"
      16             : #include "src/conversions-inl.h"
      17             : #include "src/flags.h"
      18             : #include "src/parsing/scanner.h"
      19             : #include "src/wasm/wasm-limits.h"
      20             : #include "src/wasm/wasm-opcodes.h"
      21             : 
      22             : namespace v8 {
      23             : namespace internal {
      24             : namespace wasm {
      25             : 
      26             : #ifdef DEBUG
      27             : #define FAIL_AND_RETURN(ret, msg)                                        \
      28             :   failed_ = true;                                                        \
      29             :   failure_message_ = msg;                                                \
      30             :   failure_location_ = static_cast<int>(scanner_.Position());             \
      31             :   if (FLAG_trace_asm_parser) {                                           \
      32             :     PrintF("[asm.js failure: %s, token: '%s', see: %s:%d]\n", msg,       \
      33             :            scanner_.Name(scanner_.Token()).c_str(), __FILE__, __LINE__); \
      34             :   }                                                                      \
      35             :   return ret;
      36             : #else
      37             : #define FAIL_AND_RETURN(ret, msg)                            \
      38             :   failed_ = true;                                            \
      39             :   failure_message_ = msg;                                    \
      40             :   failure_location_ = static_cast<int>(scanner_.Position()); \
      41             :   return ret;
      42             : #endif
      43             : 
      44             : #define FAIL(msg) FAIL_AND_RETURN(, msg)
      45             : #define FAILn(msg) FAIL_AND_RETURN(nullptr, msg)
      46             : 
      47             : #define EXPECT_TOKEN_OR_RETURN(ret, token)      \
      48             :   do {                                          \
      49             :     if (scanner_.Token() != token) {            \
      50             :       FAIL_AND_RETURN(ret, "Unexpected token"); \
      51             :     }                                           \
      52             :     scanner_.Next();                            \
      53             :   } while (false)
      54             : 
      55             : #define EXPECT_TOKEN(token) EXPECT_TOKEN_OR_RETURN(, token)
      56             : #define EXPECT_TOKENn(token) EXPECT_TOKEN_OR_RETURN(nullptr, token)
      57             : 
      58             : #define RECURSE_OR_RETURN(ret, call)                                       \
      59             :   do {                                                                     \
      60             :     DCHECK(!failed_);                                                      \
      61             :     if (GetCurrentStackPosition() < stack_limit_) {                        \
      62             :       FAIL_AND_RETURN(ret, "Stack overflow while parsing asm.js module."); \
      63             :     }                                                                      \
      64             :     call;                                                                  \
      65             :     if (failed_) return ret;                                               \
      66             :   } while (false)
      67             : 
      68             : #define RECURSE(call) RECURSE_OR_RETURN(, call)
      69             : #define RECURSEn(call) RECURSE_OR_RETURN(nullptr, call)
      70             : 
      71             : #define TOK(name) AsmJsScanner::kToken_##name
      72             : 
      73        3742 : AsmJsParser::AsmJsParser(Zone* zone, uintptr_t stack_limit,
      74             :                          Utf16CharacterStream* stream)
      75             :     : zone_(zone),
      76             :       scanner_(stream),
      77        3742 :       module_builder_(new (zone) WasmModuleBuilder(zone)),
      78             :       return_type_(nullptr),
      79             :       stack_limit_(stack_limit),
      80             :       global_var_info_(zone),
      81             :       local_var_info_(zone),
      82             :       failed_(false),
      83             :       failure_location_(kNoSourcePosition),
      84             :       stdlib_name_(kTokenNone),
      85             :       foreign_name_(kTokenNone),
      86             :       heap_name_(kTokenNone),
      87             :       inside_heap_assignment_(false),
      88             :       heap_access_type_(nullptr),
      89             :       block_stack_(zone),
      90             :       call_coercion_(nullptr),
      91             :       call_coercion_deferred_(nullptr),
      92             :       pending_label_(0),
      93       18710 :       global_imports_(zone) {
      94        3742 :   module_builder_->SetMinMemorySize(0);
      95        3742 :   InitializeStdlibTypes();
      96        3742 : }
      97             : 
      98        3742 : void AsmJsParser::InitializeStdlibTypes() {
      99             :   auto* d = AsmType::Double();
     100             :   auto* dq = AsmType::DoubleQ();
     101        3742 :   stdlib_dq2d_ = AsmType::Function(zone(), d);
     102             :   stdlib_dq2d_->AsFunctionType()->AddArgument(dq);
     103             : 
     104        3742 :   stdlib_dqdq2d_ = AsmType::Function(zone(), d);
     105             :   stdlib_dqdq2d_->AsFunctionType()->AddArgument(dq);
     106        3742 :   stdlib_dqdq2d_->AsFunctionType()->AddArgument(dq);
     107             : 
     108             :   auto* f = AsmType::Float();
     109             :   auto* fh = AsmType::Floatish();
     110             :   auto* fq = AsmType::FloatQ();
     111             :   auto* fq2fh = AsmType::Function(zone(), fh);
     112             :   fq2fh->AsFunctionType()->AddArgument(fq);
     113             : 
     114             :   auto* s = AsmType::Signed();
     115             :   auto* u = AsmType::Unsigned();
     116             :   auto* s2u = AsmType::Function(zone(), u);
     117             :   s2u->AsFunctionType()->AddArgument(s);
     118             : 
     119             :   auto* i = AsmType::Int();
     120        7484 :   stdlib_i2s_ = AsmType::Function(zone_, s);
     121             :   stdlib_i2s_->AsFunctionType()->AddArgument(i);
     122             : 
     123        3742 :   stdlib_ii2s_ = AsmType::Function(zone(), s);
     124             :   stdlib_ii2s_->AsFunctionType()->AddArgument(i);
     125        3742 :   stdlib_ii2s_->AsFunctionType()->AddArgument(i);
     126             : 
     127             :   // The signatures in "9 Standard Library" of the spec draft are outdated and
     128             :   // have been superseded with the following by an errata:
     129             :   //  - Math.min/max : (signed, signed...) -> signed
     130             :   //                   (double, double...) -> double
     131             :   //                   (float, float...) -> float
     132        3742 :   auto* minmax_d = AsmType::MinMaxType(zone(), d, d);
     133        3742 :   auto* minmax_f = AsmType::MinMaxType(zone(), f, f);
     134        3742 :   auto* minmax_s = AsmType::MinMaxType(zone(), s, s);
     135        3742 :   stdlib_minmax_ = AsmType::OverloadedFunction(zone());
     136        3742 :   stdlib_minmax_->AsOverloadedFunctionType()->AddOverload(minmax_s);
     137        7484 :   stdlib_minmax_->AsOverloadedFunctionType()->AddOverload(minmax_f);
     138        7484 :   stdlib_minmax_->AsOverloadedFunctionType()->AddOverload(minmax_d);
     139             : 
     140             :   // The signatures in "9 Standard Library" of the spec draft are outdated and
     141             :   // have been superseded with the following by an errata:
     142             :   //  - Math.abs : (signed) -> unsigned
     143             :   //               (double?) -> double
     144             :   //               (float?) -> floatish
     145        3742 :   stdlib_abs_ = AsmType::OverloadedFunction(zone());
     146        3742 :   stdlib_abs_->AsOverloadedFunctionType()->AddOverload(s2u);
     147        7484 :   stdlib_abs_->AsOverloadedFunctionType()->AddOverload(stdlib_dq2d_);
     148        7484 :   stdlib_abs_->AsOverloadedFunctionType()->AddOverload(fq2fh);
     149             : 
     150             :   // The signatures in "9 Standard Library" of the spec draft are outdated and
     151             :   // have been superseded with the following by an errata:
     152             :   //  - Math.ceil/floor/sqrt : (double?) -> double
     153             :   //                           (float?) -> floatish
     154        3742 :   stdlib_ceil_like_ = AsmType::OverloadedFunction(zone());
     155        7484 :   stdlib_ceil_like_->AsOverloadedFunctionType()->AddOverload(stdlib_dq2d_);
     156        7484 :   stdlib_ceil_like_->AsOverloadedFunctionType()->AddOverload(fq2fh);
     157             : 
     158        3742 :   stdlib_fround_ = AsmType::FroundType(zone());
     159        3742 : }
     160             : 
     161       59399 : FunctionSig* AsmJsParser::ConvertSignature(AsmType* return_type,
     162             :                                            const ZoneVector<AsmType*>& params) {
     163             :   FunctionSig::Builder sig_builder(
     164       59399 :       zone(), !return_type->IsA(AsmType::Void()) ? 1 : 0, params.size());
     165      182805 :   for (auto param : params) {
     166      123406 :     if (param->IsA(AsmType::Double())) {
     167             :       sig_builder.AddParam(kWasmF64);
     168      119699 :     } else if (param->IsA(AsmType::Float())) {
     169             :       sig_builder.AddParam(kWasmF32);
     170      118761 :     } else if (param->IsA(AsmType::Int())) {
     171             :       sig_builder.AddParam(kWasmI32);
     172             :     } else {
     173           0 :       UNREACHABLE();
     174             :     }
     175             :   }
     176       59399 :   if (!return_type->IsA(AsmType::Void())) {
     177       30528 :     if (return_type->IsA(AsmType::Double())) {
     178             :       sig_builder.AddReturn(kWasmF64);
     179       28360 :     } else if (return_type->IsA(AsmType::Float())) {
     180             :       sig_builder.AddReturn(kWasmF32);
     181       28059 :     } else if (return_type->IsA(AsmType::Signed())) {
     182             :       sig_builder.AddReturn(kWasmI32);
     183             :     } else {
     184           0 :       UNREACHABLE();
     185             :     }
     186             :   }
     187       59399 :   return sig_builder.Build();
     188             : }
     189             : 
     190        3742 : bool AsmJsParser::Run() {
     191        3742 :   ValidateModule();
     192        3742 :   return !failed_;
     193             : }
     194             : 
     195             : class AsmJsParser::TemporaryVariableScope {
     196             :  public:
     197             :   explicit TemporaryVariableScope(AsmJsParser* parser) : parser_(parser) {
     198        4135 :     local_depth_ = parser_->function_temp_locals_depth_;
     199        4135 :     parser_->function_temp_locals_depth_++;
     200             :   }
     201             :   ~TemporaryVariableScope() {
     202             :     DCHECK_EQ(local_depth_, parser_->function_temp_locals_depth_ - 1);
     203        4135 :     parser_->function_temp_locals_depth_--;
     204             :   }
     205             :   uint32_t get() const { return parser_->TempVariable(local_depth_); }
     206             : 
     207             :  private:
     208             :   AsmJsParser* parser_;
     209             :   int local_depth_;
     210             : };
     211             : 
     212     2807315 : wasm::AsmJsParser::VarInfo* AsmJsParser::GetVarInfo(
     213             :     AsmJsScanner::token_t token) {
     214     2807315 :   if (AsmJsScanner::IsGlobal(token)) {
     215     1274760 :     size_t old = global_var_info_.size();
     216             :     size_t index = AsmJsScanner::GlobalIndex(token);
     217     2549520 :     size_t sz = std::max(old, index + 1);
     218     1274760 :     if (sz != old) {
     219       21840 :       global_var_info_.resize(sz);
     220             :     }
     221             :     return &global_var_info_[index];
     222     1532555 :   } else if (AsmJsScanner::IsLocal(token)) {
     223     1532555 :     size_t old = local_var_info_.size();
     224             :     size_t index = AsmJsScanner::LocalIndex(token);
     225     3065110 :     size_t sz = std::max(old, index + 1);
     226     1532555 :     if (sz != old) {
     227      575711 :       local_var_info_.resize(sz);
     228             :     }
     229             :     return &local_var_info_[index];
     230             :   }
     231           0 :   UNREACHABLE();
     232             : }
     233             : 
     234           0 : uint32_t AsmJsParser::VarIndex(VarInfo* info) {
     235             :   DCHECK_EQ(info->kind, VarKind::kGlobal);
     236       62468 :   return info->index + static_cast<uint32_t>(global_imports_.size());
     237             : }
     238             : 
     239         507 : void AsmJsParser::AddGlobalImport(Vector<const char> name, AsmType* type,
     240             :                                   ValueType vtype, bool mutable_variable,
     241             :                                   VarInfo* info) {
     242             :   // Allocate a separate variable for the import.
     243             :   // TODO(mstarzinger): Consider using the imported global directly instead of
     244             :   // allocating a separate global variable for immutable (i.e. const) imports.
     245         507 :   DeclareGlobal(info, mutable_variable, type, vtype);
     246             : 
     247             :   // Record the need to initialize the global from the import.
     248        1014 :   global_imports_.push_back({name, vtype, info});
     249         507 : }
     250             : 
     251           0 : void AsmJsParser::DeclareGlobal(VarInfo* info, bool mutable_variable,
     252             :                                 AsmType* type, ValueType vtype,
     253             :                                 const WasmInitExpr& init) {
     254        2330 :   info->kind = VarKind::kGlobal;
     255        2330 :   info->type = type;
     256        2330 :   info->index = module_builder_->AddGlobal(vtype, false, true, init);
     257        2330 :   info->mutable_variable = mutable_variable;
     258           0 : }
     259             : 
     260           0 : void AsmJsParser::DeclareStdlibFunc(VarInfo* info, VarKind kind,
     261             :                                     AsmType* type) {
     262        4335 :   info->kind = kind;
     263        4335 :   info->type = type;
     264        4335 :   info->index = 0;  // unused
     265        4335 :   info->mutable_variable = false;
     266           0 : }
     267             : 
     268           0 : uint32_t AsmJsParser::TempVariable(int index) {
     269        8950 :   if (index + 1 > function_temp_locals_used_) {
     270        1612 :     function_temp_locals_used_ = index + 1;
     271             :   }
     272        8950 :   return function_temp_locals_offset_ + index;
     273             : }
     274             : 
     275       19829 : Vector<const char> AsmJsParser::CopyCurrentIdentifierString() {
     276             :   const std::string& str = scanner_.GetIdentifierString();
     277             :   char* buffer = zone()->NewArray<char>(str.size());
     278       19829 :   str.copy(buffer, str.size());
     279       19829 :   return Vector<const char>(buffer, static_cast<int>(str.size()));
     280             : }
     281             : 
     282      915304 : void AsmJsParser::SkipSemicolon() {
     283      915304 :   if (Check(';')) {
     284             :     // Had a semicolon.
     285       32722 :   } else if (!Peek('}') && !scanner_.IsPrecededByNewline()) {
     286          22 :     FAIL("Expected ;");
     287             :   }
     288             : }
     289             : 
     290       14641 : void AsmJsParser::Begin(AsmJsScanner::token_t label) {
     291             :   BareBegin(BlockKind::kRegular, label);
     292       14641 :   current_function_builder_->EmitWithU8(kExprBlock, kLocalVoid);
     293       14641 : }
     294             : 
     295       14013 : void AsmJsParser::Loop(AsmJsScanner::token_t label) {
     296             :   BareBegin(BlockKind::kLoop, label);
     297             :   size_t position = scanner_.Position();
     298       14013 :   current_function_builder_->AddAsmWasmOffset(position, position);
     299       14013 :   current_function_builder_->EmitWithU8(kExprLoop, kLocalVoid);
     300       14013 : }
     301             : 
     302           0 : void AsmJsParser::End() {
     303             :   BareEnd();
     304       37412 :   current_function_builder_->Emit(kExprEnd);
     305           0 : }
     306             : 
     307           0 : void AsmJsParser::BareBegin(BlockKind kind, AsmJsScanner::token_t label) {
     308             :   BlockInfo info;
     309      116140 :   info.kind = kind;
     310      116140 :   info.label = label;
     311      116140 :   block_stack_.push_back(info);
     312           0 : }
     313             : 
     314           0 : void AsmJsParser::BareEnd() {
     315             :   DCHECK_GT(block_stack_.size(), 0);
     316             :   block_stack_.pop_back();
     317           0 : }
     318             : 
     319           0 : int AsmJsParser::FindContinueLabelDepth(AsmJsScanner::token_t label) {
     320             :   int count = 0;
     321       23602 :   for (auto it = block_stack_.rbegin(); it != block_stack_.rend();
     322             :        ++it, ++count) {
     323       24684 :     if (it->kind == BlockKind::kLoop &&
     324         889 :         (label == kTokenNone || it->label == label)) {
     325             :       return count;
     326             :     }
     327             :   }
     328             :   return -1;
     329             : }
     330             : 
     331           0 : int AsmJsParser::FindBreakLabelDepth(AsmJsScanner::token_t label) {
     332             :   int count = 0;
     333      820994 :   for (auto it = block_stack_.rbegin(); it != block_stack_.rend();
     334             :        ++it, ++count) {
     335      845916 :     if (it->kind == BlockKind::kRegular &&
     336       13893 :         (label == kTokenNone || it->label == label)) {
     337             :       return count;
     338             :     }
     339             :   }
     340             :   return -1;
     341             : }
     342             : 
     343             : // 6.1 ValidateModule
     344        3742 : void AsmJsParser::ValidateModule() {
     345        3742 :   RECURSE(ValidateModuleParameters());
     346        3702 :   EXPECT_TOKEN('{');
     347        3702 :   EXPECT_TOKEN(TOK(UseAsm));
     348        3702 :   RECURSE(SkipSemicolon());
     349        3697 :   RECURSE(ValidateModuleVars());
     350       15592 :   while (Peek(TOK(function))) {
     351       12636 :     RECURSE(ValidateFunction());
     352             :   }
     353        3145 :   while (Peek(TOK(var))) {
     354         205 :     RECURSE(ValidateFunctionTable());
     355             :   }
     356        2940 :   RECURSE(ValidateExport());
     357        2515 :   RECURSE(SkipSemicolon());
     358        2515 :   EXPECT_TOKEN('}');
     359             : 
     360             :   // Check that all functions were eventually defined.
     361       30683 :   for (auto& info : global_var_info_) {
     362       28196 :     if (info.kind == VarKind::kFunction && !info.function_defined) {
     363          16 :       FAIL("Undefined function");
     364             :     }
     365       28180 :     if (info.kind == VarKind::kTable && !info.function_defined) {
     366           8 :       FAIL("Undefined function table");
     367             :     }
     368       28172 :     if (info.kind == VarKind::kImportedFunction && !info.function_defined) {
     369             :       // For imported functions without a single call site, we insert a dummy
     370             :       // import here to preserve the fact that there actually was an import.
     371             :       FunctionSig* void_void_sig = FunctionSig::Builder(zone(), 0, 0).Build();
     372        1204 :       module_builder_->AddImport(info.import->function_name, void_void_sig);
     373             :     }
     374             :   }
     375             : 
     376             :   // Add start function to initialize things.
     377        2487 :   WasmFunctionBuilder* start = module_builder_->AddFunction();
     378        2487 :   module_builder_->MarkStartFunction(start);
     379        2956 :   for (auto& global_import : global_imports_) {
     380         469 :     uint32_t import_index = module_builder_->AddGlobalImport(
     381         938 :         global_import.import_name, global_import.value_type);
     382         469 :     start->EmitWithI32V(kExprGetGlobal, import_index);
     383         938 :     start->EmitWithI32V(kExprSetGlobal, VarIndex(global_import.var_info));
     384             :   }
     385        2487 :   start->Emit(kExprEnd);
     386             :   FunctionSig::Builder b(zone(), 0, 0);
     387        2487 :   start->SetSignature(b.Build());
     388             : }
     389             : 
     390             : // 6.1 ValidateModule - parameters
     391        3742 : void AsmJsParser::ValidateModuleParameters() {
     392        3742 :   EXPECT_TOKEN('(');
     393        3742 :   stdlib_name_ = 0;
     394        3742 :   foreign_name_ = 0;
     395        3742 :   heap_name_ = 0;
     396        3742 :   if (!Peek(')')) {
     397        2643 :     if (!scanner_.IsGlobal()) {
     398           0 :       FAIL("Expected stdlib parameter");
     399             :     }
     400        2643 :     stdlib_name_ = Consume();
     401        2643 :     if (!Peek(')')) {
     402        1861 :       EXPECT_TOKEN(',');
     403        1861 :       if (!scanner_.IsGlobal()) {
     404           0 :         FAIL("Expected foreign parameter");
     405             :       }
     406        1861 :       foreign_name_ = Consume();
     407        1861 :       if (!Peek(')')) {
     408        1785 :         EXPECT_TOKEN(',');
     409        1785 :         if (!scanner_.IsGlobal()) {
     410           0 :           FAIL("Expected heap parameter");
     411             :         }
     412        1785 :         heap_name_ = Consume();
     413             :       }
     414             :     }
     415             :   }
     416        3742 :   EXPECT_TOKEN(')');
     417             : }
     418             : 
     419             : // 6.1 ValidateModule - variables
     420        3697 : void AsmJsParser::ValidateModuleVars() {
     421       20325 :   while (Peek(TOK(var)) || Peek(TOK(const))) {
     422             :     bool mutable_variable = true;
     423        8453 :     if (Check(TOK(var))) {
     424             :       // Had a var.
     425             :     } else {
     426          63 :       EXPECT_TOKEN(TOK(const));
     427             :       mutable_variable = false;
     428             :     }
     429             :     for (;;) {
     430        8875 :       RECURSE(ValidateModuleVar(mutable_variable));
     431        8736 :       if (Check(',')) {
     432             :         continue;
     433             :       }
     434             :       break;
     435             :     }
     436        8314 :     SkipSemicolon();
     437             :   }
     438             : }
     439             : 
     440             : // 6.1 ValidateModule - one variable
     441        8875 : void AsmJsParser::ValidateModuleVar(bool mutable_variable) {
     442        8875 :   if (!scanner_.IsGlobal()) {
     443           0 :     FAIL("Expected identifier");
     444             :   }
     445        8875 :   VarInfo* info = GetVarInfo(Consume());
     446        8875 :   if (info->kind != VarKind::kUnused) {
     447           0 :     FAIL("Redefinition of variable");
     448             :   }
     449        8875 :   EXPECT_TOKEN('=');
     450             :   double dvalue = 0.0;
     451             :   uint32_t uvalue = 0;
     452        8870 :   if (CheckForDouble(&dvalue)) {
     453         166 :     DeclareGlobal(info, mutable_variable, AsmType::Double(), kWasmF64,
     454             :                   WasmInitExpr(dvalue));
     455        8704 :   } else if (CheckForUnsigned(&uvalue)) {
     456        1448 :     if (uvalue > 0x7FFFFFFF) {
     457           8 :       FAIL("Numeric literal out of range");
     458             :     }
     459        2880 :     DeclareGlobal(info, mutable_variable,
     460             :                   mutable_variable ? AsmType::Int() : AsmType::Signed(),
     461             :                   kWasmI32, WasmInitExpr(static_cast<int32_t>(uvalue)));
     462        7256 :   } else if (Check('-')) {
     463           8 :     if (CheckForDouble(&dvalue)) {
     464           8 :       DeclareGlobal(info, mutable_variable, AsmType::Double(), kWasmF64,
     465             :                     WasmInitExpr(-dvalue));
     466           4 :     } else if (CheckForUnsigned(&uvalue)) {
     467           4 :       if (uvalue > 0x7FFFFFFF) {
     468           0 :         FAIL("Numeric literal out of range");
     469             :       }
     470          12 :       DeclareGlobal(info, mutable_variable,
     471             :                     mutable_variable ? AsmType::Int() : AsmType::Signed(),
     472             :                     kWasmI32, WasmInitExpr(-static_cast<int32_t>(uvalue)));
     473             :     } else {
     474           0 :       FAIL("Expected numeric literal");
     475             :     }
     476        7249 :   } else if (Check(TOK(new))) {
     477        1317 :     RECURSE(ValidateModuleVarNewStdlib(info));
     478       11864 :   } else if (Check(stdlib_name_)) {
     479        3270 :     EXPECT_TOKEN('.');
     480        3266 :     RECURSE(ValidateModuleVarStdlib(info));
     481        2662 :   } else if (Peek(foreign_name_) || Peek('+')) {
     482        2606 :     RECURSE(ValidateModuleVarImport(info, mutable_variable));
     483          56 :   } else if (scanner_.IsGlobal()) {
     484          42 :     RECURSE(ValidateModuleVarFromGlobal(info, mutable_variable));
     485             :   } else {
     486          14 :     FAIL("Bad variable declaration");
     487             :   }
     488             : }
     489             : 
     490             : // 6.1 ValidateModule - global float declaration
     491          42 : void AsmJsParser::ValidateModuleVarFromGlobal(VarInfo* info,
     492             :                                               bool mutable_variable) {
     493          42 :   VarInfo* src_info = GetVarInfo(Consume());
     494          42 :   if (!src_info->type->IsA(stdlib_fround_)) {
     495          22 :     if (src_info->mutable_variable) {
     496          18 :       FAIL("Can only use immutable variables in global definition");
     497             :     }
     498           4 :     if (mutable_variable) {
     499           0 :       FAIL("Can only define immutable variables with other immutables");
     500             :     }
     501          12 :     if (!src_info->type->IsA(AsmType::Int()) &&
     502           4 :         !src_info->type->IsA(AsmType::Float()) &&
     503           0 :         !src_info->type->IsA(AsmType::Double())) {
     504           0 :       FAIL("Expected int, float, double, or fround for global definition");
     505             :     }
     506           4 :     info->kind = VarKind::kGlobal;
     507           4 :     info->type = src_info->type;
     508           4 :     info->index = src_info->index;
     509           4 :     info->mutable_variable = false;
     510           4 :     return;
     511             :   }
     512          20 :   EXPECT_TOKEN('(');
     513             :   bool negate = false;
     514          20 :   if (Check('-')) {
     515             :     negate = true;
     516             :   }
     517             :   double dvalue = 0.0;
     518             :   uint32_t uvalue = 0;
     519          20 :   if (CheckForDouble(&dvalue)) {
     520          16 :     if (negate) {
     521           4 :       dvalue = -dvalue;
     522             :     }
     523          16 :     DeclareGlobal(info, mutable_variable, AsmType::Float(), kWasmF32,
     524             :                   WasmInitExpr(DoubleToFloat32(dvalue)));
     525           4 :   } else if (CheckForUnsigned(&uvalue)) {
     526           4 :     dvalue = uvalue;
     527           4 :     if (negate) {
     528           0 :       dvalue = -dvalue;
     529             :     }
     530           8 :     DeclareGlobal(info, mutable_variable, AsmType::Float(), kWasmF32,
     531             :                   WasmInitExpr(static_cast<float>(dvalue)));
     532             :   } else {
     533           0 :     FAIL("Expected numeric literal");
     534             :   }
     535          20 :   EXPECT_TOKEN(')');
     536             : }
     537             : 
     538             : // 6.1 ValidateModule - foreign imports
     539        2606 : void AsmJsParser::ValidateModuleVarImport(VarInfo* info,
     540             :                                           bool mutable_variable) {
     541        2606 :   if (Check('+')) {
     542         178 :     EXPECT_TOKEN(foreign_name_);
     543         170 :     EXPECT_TOKEN('.');
     544         170 :     Vector<const char> name = CopyCurrentIdentifierString();
     545         170 :     AddGlobalImport(name, AsmType::Double(), kWasmF64, mutable_variable, info);
     546         170 :     scanner_.Next();
     547             :   } else {
     548        2436 :     EXPECT_TOKEN(foreign_name_);
     549        2432 :     EXPECT_TOKEN('.');
     550        2432 :     Vector<const char> name = CopyCurrentIdentifierString();
     551        2432 :     scanner_.Next();
     552        2432 :     if (Check('|')) {
     553         341 :       if (!CheckForZero()) {
     554           4 :         FAIL("Expected |0 type annotation for foreign integer import");
     555             :       }
     556         337 :       AddGlobalImport(name, AsmType::Int(), kWasmI32, mutable_variable, info);
     557             :     } else {
     558        2091 :       info->kind = VarKind::kImportedFunction;
     559             :       info->import = new (zone()->New(sizeof(FunctionImportInfo)))
     560        6273 :           FunctionImportInfo(name, zone());
     561        2091 :       info->mutable_variable = false;
     562             :     }
     563             :   }
     564             : }
     565             : 
     566             : // 6.1 ValidateModule - one variable
     567             : // 9 - Standard Library - heap types
     568        1317 : void AsmJsParser::ValidateModuleVarNewStdlib(VarInfo* info) {
     569        1317 :   EXPECT_TOKEN(stdlib_name_);
     570        1268 :   EXPECT_TOKEN('.');
     571        1268 :   switch (Consume()) {
     572             : #define V(name, _junk1, _junk2, _junk3)                          \
     573             :   case TOK(name):                                                \
     574             :     DeclareStdlibFunc(info, VarKind::kSpecial, AsmType::name()); \
     575             :     stdlib_uses_.Add(StandardMember::k##name);                   \
     576             :     break;
     577             :     STDLIB_ARRAY_TYPE_LIST(V)
     578             : #undef V
     579             :     default:
     580           0 :       FAIL("Expected ArrayBuffer view");
     581             :       break;
     582             :   }
     583        1268 :   EXPECT_TOKEN('(');
     584        1268 :   EXPECT_TOKEN(heap_name_);
     585        1244 :   EXPECT_TOKEN(')');
     586             : }
     587             : 
     588             : // 6.1 ValidateModule - one variable
     589             : // 9 - Standard Library
     590        3266 : void AsmJsParser::ValidateModuleVarStdlib(VarInfo* info) {
     591        3266 :   if (Check(TOK(Math))) {
     592        3204 :     EXPECT_TOKEN('.');
     593        3204 :     switch (Consume()) {
     594             : #define V(name, const_value)                                \
     595             :   case TOK(name):                                           \
     596             :     DeclareGlobal(info, false, AsmType::Double(), kWasmF64, \
     597             :                   WasmInitExpr(const_value));               \
     598             :     stdlib_uses_.Add(StandardMember::kMath##name);          \
     599             :     break;
     600         137 :       STDLIB_MATH_VALUE_LIST(V)
     601             : #undef V
     602             : #define V(name, Name, op, sig)                                      \
     603             :   case TOK(name):                                                   \
     604             :     DeclareStdlibFunc(info, VarKind::kMath##Name, stdlib_##sig##_); \
     605             :     stdlib_uses_.Add(StandardMember::kMath##Name);                  \
     606             :     break;
     607        3067 :       STDLIB_MATH_FUNCTION_LIST(V)
     608             : #undef V
     609             :       default:
     610           0 :         FAIL("Invalid member of stdlib.Math");
     611             :     }
     612          62 :   } else if (Check(TOK(Infinity))) {
     613          14 :     DeclareGlobal(info, false, AsmType::Double(), kWasmF64,
     614             :                   WasmInitExpr(std::numeric_limits<double>::infinity()));
     615             :     stdlib_uses_.Add(StandardMember::kInfinity);
     616          48 :   } else if (Check(TOK(NaN))) {
     617          38 :     DeclareGlobal(info, false, AsmType::Double(), kWasmF64,
     618             :                   WasmInitExpr(std::numeric_limits<double>::quiet_NaN()));
     619             :     stdlib_uses_.Add(StandardMember::kNaN);
     620             :   } else {
     621          10 :     FAIL("Invalid member of stdlib");
     622             :   }
     623             : }
     624             : 
     625             : // 6.2 ValidateExport
     626        2940 : void AsmJsParser::ValidateExport() {
     627             :   // clang-format off
     628        2940 :   EXPECT_TOKEN(TOK(return));
     629             :   // clang-format on
     630        2899 :   if (Check('{')) {
     631        1865 :     for (;;) {
     632        4591 :       Vector<const char> name = CopyCurrentIdentifierString();
     633        4591 :       if (!scanner_.IsGlobal() && !scanner_.IsLocal()) {
     634         660 :         FAIL("Illegal export name");
     635             :       }
     636             :       Consume();
     637        4265 :       EXPECT_TOKEN(':');
     638        4261 :       if (!scanner_.IsGlobal()) {
     639           4 :         FAIL("Expected function name");
     640             :       }
     641        4257 :       VarInfo* info = GetVarInfo(Consume());
     642        4257 :       if (info->kind != VarKind::kFunction) {
     643           0 :         FAIL("Expected function");
     644             :       }
     645        4257 :       module_builder_->AddExport(name, info->function_builder);
     646        4257 :       if (Check(',')) {
     647        1910 :         if (!Peek('}')) {
     648        1865 :           continue;
     649             :         }
     650             :       }
     651        2392 :       break;
     652             :     }
     653        2392 :     EXPECT_TOKEN('}');
     654             :   } else {
     655         173 :     if (!scanner_.IsGlobal()) {
     656          50 :       FAIL("Single function export must be a function name");
     657             :     }
     658         123 :     VarInfo* info = GetVarInfo(Consume());
     659         123 :     if (info->kind != VarKind::kFunction) {
     660           0 :       FAIL("Single function export must be a function");
     661             :     }
     662         246 :     module_builder_->AddExport(CStrVector(AsmJs::kSingleFunctionName),
     663         123 :                                info->function_builder);
     664             :   }
     665             : }
     666             : 
     667             : // 6.3 ValidateFunctionTable
     668         205 : void AsmJsParser::ValidateFunctionTable() {
     669         205 :   EXPECT_TOKEN(TOK(var));
     670         205 :   if (!scanner_.IsGlobal()) {
     671           0 :     FAIL("Expected table name");
     672             :   }
     673         205 :   VarInfo* table_info = GetVarInfo(Consume());
     674         205 :   if (table_info->kind == VarKind::kTable) {
     675         193 :     if (table_info->function_defined) {
     676           4 :       FAIL("Function table redefined");
     677             :     }
     678         189 :     table_info->function_defined = true;
     679          12 :   } else if (table_info->kind != VarKind::kUnused) {
     680           4 :     FAIL("Function table name collides");
     681             :   }
     682         197 :   EXPECT_TOKEN('=');
     683         197 :   EXPECT_TOKEN('[');
     684             :   uint64_t count = 0;
     685             :   for (;;) {
     686        4201 :     if (!scanner_.IsGlobal()) {
     687           4 :       FAIL("Expected function name");
     688             :     }
     689        4197 :     VarInfo* info = GetVarInfo(Consume());
     690        4197 :     if (info->kind != VarKind::kFunction) {
     691           0 :       FAIL("Expected function");
     692             :     }
     693             :     // Only store the function into a table if we used the table somewhere
     694             :     // (i.e. tables are first seen at their use sites and allocated there).
     695        4197 :     if (table_info->kind == VarKind::kTable) {
     696        4193 :       if (count >= static_cast<uint64_t>(table_info->mask) + 1) {
     697           0 :         FAIL("Exceeded function table size");
     698             :       }
     699        4193 :       if (!info->type->IsA(table_info->type)) {
     700           4 :         FAIL("Function table definition doesn't match use");
     701             :       }
     702        8378 :       module_builder_->SetIndirectFunction(
     703        8378 :           static_cast<uint32_t>(table_info->index + count), info->index);
     704             :     }
     705        4193 :     ++count;
     706        4193 :     if (Check(',')) {
     707        4004 :       if (!Peek(']')) {
     708             :         continue;
     709             :       }
     710             :     }
     711             :     break;
     712             :   }
     713         189 :   EXPECT_TOKEN(']');
     714         374 :   if (table_info->kind == VarKind::kTable &&
     715         185 :       count != static_cast<uint64_t>(table_info->mask) + 1) {
     716           0 :     FAIL("Function table size does not match uses");
     717             :   }
     718         189 :   SkipSemicolon();
     719             : }
     720             : 
     721             : // 6.4 ValidateFunction
     722       12636 : void AsmJsParser::ValidateFunction() {
     723       13234 :   EXPECT_TOKEN(TOK(function));
     724       12636 :   if (!scanner_.IsGlobal()) {
     725           0 :     FAIL("Expected function name");
     726             :   }
     727             : 
     728       12636 :   Vector<const char> function_name_str = CopyCurrentIdentifierString();
     729             :   AsmJsScanner::token_t function_name = Consume();
     730       12636 :   VarInfo* function_info = GetVarInfo(function_name);
     731       12636 :   if (function_info->kind == VarKind::kUnused) {
     732        9724 :     function_info->kind = VarKind::kFunction;
     733        9724 :     function_info->function_builder = module_builder_->AddFunction();
     734        9724 :     function_info->index = function_info->function_builder->func_index();
     735        9724 :     function_info->mutable_variable = false;
     736        2912 :   } else if (function_info->kind != VarKind::kFunction) {
     737           4 :     FAIL("Function name collides with variable");
     738        2908 :   } else if (function_info->function_defined) {
     739           8 :     FAIL("Function redefined");
     740             :   }
     741             : 
     742       12624 :   function_info->function_defined = true;
     743       12624 :   function_info->function_builder->SetName(function_name_str);
     744       12624 :   current_function_builder_ = function_info->function_builder;
     745       12624 :   return_type_ = nullptr;
     746             : 
     747             :   // Record start of the function, used as position for the stack check.
     748       12624 :   current_function_builder_->SetAsmFunctionStartPosition(scanner_.Position());
     749             : 
     750       12624 :   CachedVector<AsmType*> params(cached_asm_type_p_vectors_);
     751       12624 :   ValidateFunctionParams(&params);
     752             : 
     753             :   // Check against limit on number of parameters.
     754       12624 :   if (params.size() >= kV8MaxWasmFunctionParams) {
     755          10 :     FAIL("Number of parameters exceeds internal limit");
     756             :   }
     757             : 
     758       12614 :   CachedVector<ValueType> locals(cached_valuetype_vectors_);
     759       12614 :   ValidateFunctionLocals(params.size(), &locals);
     760             : 
     761             :   function_temp_locals_offset_ = static_cast<uint32_t>(
     762       25228 :       params.size() + locals.size());
     763       12614 :   function_temp_locals_used_ = 0;
     764       12614 :   function_temp_locals_depth_ = 0;
     765             : 
     766             :   bool last_statement_is_return = false;
     767      118552 :   while (!failed_ && !Peek('}')) {
     768             :     // clang-format off
     769             :     last_statement_is_return = Peek(TOK(return));
     770             :     // clang-format on
     771      106362 :     RECURSE(ValidateStatement());
     772             :   }
     773       12190 :   EXPECT_TOKEN('}');
     774             : 
     775       12051 :   if (!last_statement_is_return) {
     776        2235 :     if (return_type_ == nullptr) {
     777        1824 :       return_type_ = AsmType::Void();
     778         411 :     } else if (!return_type_->IsA(AsmType::Void())) {
     779           4 :       FAIL("Expected return at end of non-void function");
     780             :     }
     781             :   }
     782             :   DCHECK_NOT_NULL(return_type_);
     783             : 
     784             :   // TODO(bradnelson): WasmModuleBuilder can't take this in the right order.
     785             :   //                   We should fix that so we can use it instead.
     786       12047 :   FunctionSig* sig = ConvertSignature(return_type_, params);
     787       12047 :   current_function_builder_->SetSignature(sig);
     788      555986 :   for (auto local : locals) {
     789      543939 :     current_function_builder_->AddLocal(local);
     790             :   }
     791             :   // Add bonus temps.
     792       15223 :   for (int i = 0; i < function_temp_locals_used_; ++i) {
     793        1588 :     current_function_builder_->AddLocal(kWasmI32);
     794             :   }
     795             : 
     796             :   // Check against limit on number of local variables.
     797       12047 :   if (locals.size() + function_temp_locals_used_ > kV8MaxWasmFunctionLocals) {
     798           5 :     FAIL("Number of local variables exceeds internal limit");
     799             :   }
     800             : 
     801             :   // End function
     802       12042 :   current_function_builder_->Emit(kExprEnd);
     803             : 
     804             :   // Record (or validate) function type.
     805       12042 :   AsmType* function_type = AsmType::Function(zone(), return_type_);
     806       33094 :   for (auto t : params) {
     807             :     function_type->AsFunctionType()->AddArgument(t);
     808             :   }
     809       12042 :   function_info = GetVarInfo(function_name);
     810       12042 :   if (function_info->type->IsA(AsmType::None())) {
     811             :     DCHECK_EQ(function_info->kind, VarKind::kFunction);
     812        9087 :     function_info->type = function_type;
     813        2955 :   } else if (!function_type->IsA(function_info->type)) {
     814             :     // TODO(bradnelson): Should IsExactly be used here?
     815           4 :     FAIL("Function definition doesn't match use");
     816             :   }
     817             : 
     818       12038 :   scanner_.ResetLocals();
     819             :   local_var_info_.clear();
     820             : }
     821             : 
     822             : // 6.4 ValidateFunction
     823       12624 : void AsmJsParser::ValidateFunctionParams(ZoneVector<AsmType*>* params) {
     824             :   // TODO(bradnelson): Do this differently so that the scanner doesn't need to
     825             :   // have a state transition that needs knowledge of how the scanner works
     826             :   // inside.
     827             :   scanner_.EnterLocalScope();
     828       12739 :   EXPECT_TOKEN('(');
     829             :   CachedVector<AsmJsScanner::token_t> function_parameters(
     830       12624 :       cached_token_t_vectors_);
     831       44204 :   while (!failed_ && !Peek(')')) {
     832       31580 :     if (!scanner_.IsLocal()) {
     833           0 :       FAIL("Expected parameter name");
     834             :     }
     835       63160 :     function_parameters.push_back(Consume());
     836       31580 :     if (!Peek(')')) {
     837       21109 :       EXPECT_TOKEN(',');
     838             :     }
     839             :   }
     840       12624 :   EXPECT_TOKEN(')');
     841             :   scanner_.EnterGlobalScope();
     842       12624 :   EXPECT_TOKEN('{');
     843             :   // 5.1 Parameter Type Annotations
     844       44070 :   for (auto p : function_parameters) {
     845       31561 :     EXPECT_TOKEN(p);
     846       31471 :     EXPECT_TOKEN('=');
     847       31471 :     VarInfo* info = GetVarInfo(p);
     848       31471 :     if (info->kind != VarKind::kUnused) {
     849           0 :       FAIL("Duplicate parameter name");
     850             :     }
     851       31471 :     if (Check(p)) {
     852       19341 :       EXPECT_TOKEN('|');
     853       19332 :       if (!CheckForZero()) {
     854           8 :         FAIL("Bad integer parameter annotation.");
     855             :       }
     856       19324 :       info->kind = VarKind::kLocal;
     857       19324 :       info->type = AsmType::Int();
     858       19324 :       info->index = static_cast<uint32_t>(params->size());
     859       38648 :       params->push_back(AsmType::Int());
     860       12130 :     } else if (Check('+')) {
     861       11319 :       EXPECT_TOKEN(p);
     862       11315 :       info->kind = VarKind::kLocal;
     863       11315 :       info->type = AsmType::Double();
     864       11315 :       info->index = static_cast<uint32_t>(params->size());
     865       22630 :       params->push_back(AsmType::Double());
     866             :     } else {
     867        1618 :       if (!scanner_.IsGlobal() ||
     868        1614 :           !GetVarInfo(Consume())->type->IsA(stdlib_fround_)) {
     869           4 :         FAIL("Expected fround");
     870             :       }
     871         807 :       EXPECT_TOKEN('(');
     872         807 :       EXPECT_TOKEN(p);
     873         807 :       EXPECT_TOKEN(')');
     874         807 :       info->kind = VarKind::kLocal;
     875         807 :       info->type = AsmType::Float();
     876         807 :       info->index = static_cast<uint32_t>(params->size());
     877        1614 :       params->push_back(AsmType::Float());
     878             :     }
     879       31446 :     SkipSemicolon();
     880             :   }
     881             : }
     882             : 
     883             : // 6.4 ValidateFunction - locals
     884       12614 : void AsmJsParser::ValidateFunctionLocals(size_t param_count,
     885             :                                          ZoneVector<ValueType>* locals) {
     886             :   DCHECK(locals->empty());
     887             :   // Local Variables.
     888     1026396 :   while (Peek(TOK(var))) {
     889             :     scanner_.EnterLocalScope();
     890      506912 :     EXPECT_TOKEN(TOK(var));
     891             :     scanner_.EnterGlobalScope();
     892       37328 :     for (;;) {
     893      544240 :       if (!scanner_.IsLocal()) {
     894           0 :         FAIL("Expected local variable identifier");
     895             :       }
     896      544240 :       VarInfo* info = GetVarInfo(Consume());
     897      544240 :       if (info->kind != VarKind::kUnused) {
     898           0 :         FAIL("Duplicate local variable name");
     899             :       }
     900             :       // Store types.
     901      544240 :       EXPECT_TOKEN('=');
     902             :       double dvalue = 0.0;
     903             :       uint32_t uvalue = 0;
     904      544240 :       if (Check('-')) {
     905          36 :         if (CheckForDouble(&dvalue)) {
     906          16 :           info->kind = VarKind::kLocal;
     907          16 :           info->type = AsmType::Double();
     908          16 :           info->index = static_cast<uint32_t>(param_count + locals->size());
     909          32 :           locals->push_back(kWasmF64);
     910          16 :           current_function_builder_->EmitF64Const(-dvalue);
     911          16 :           current_function_builder_->EmitSetLocal(info->index);
     912          20 :         } else if (CheckForUnsigned(&uvalue)) {
     913          20 :           if (uvalue > 0x7FFFFFFF) {
     914           0 :             FAIL("Numeric literal out of range");
     915             :           }
     916          20 :           info->kind = VarKind::kLocal;
     917          20 :           info->type = AsmType::Int();
     918          20 :           info->index = static_cast<uint32_t>(param_count + locals->size());
     919          40 :           locals->push_back(kWasmI32);
     920          20 :           int32_t value = -static_cast<int32_t>(uvalue);
     921          20 :           current_function_builder_->EmitI32Const(value);
     922          20 :           current_function_builder_->EmitSetLocal(info->index);
     923             :         } else {
     924           0 :           FAIL("Expected variable initial value");
     925             :         }
     926      544204 :       } else if (scanner_.IsGlobal()) {
     927          48 :         VarInfo* sinfo = GetVarInfo(Consume());
     928          48 :         if (sinfo->kind == VarKind::kGlobal) {
     929          12 :           if (sinfo->mutable_variable) {
     930           0 :             FAIL("Initializing from global requires const variable");
     931             :           }
     932          12 :           info->kind = VarKind::kLocal;
     933          12 :           info->type = sinfo->type;
     934          12 :           info->index = static_cast<uint32_t>(param_count + locals->size());
     935          12 :           if (sinfo->type->IsA(AsmType::Int())) {
     936           8 :             locals->push_back(kWasmI32);
     937           8 :           } else if (sinfo->type->IsA(AsmType::Float())) {
     938           8 :             locals->push_back(kWasmF32);
     939           4 :           } else if (sinfo->type->IsA(AsmType::Double())) {
     940           8 :             locals->push_back(kWasmF64);
     941             :           } else {
     942           0 :             FAIL("Bad local variable definition");
     943             :           }
     944          12 :           current_function_builder_->EmitWithI32V(kExprGetGlobal,
     945          12 :                                                     VarIndex(sinfo));
     946          12 :           current_function_builder_->EmitSetLocal(info->index);
     947          36 :         } else if (sinfo->type->IsA(stdlib_fround_)) {
     948          36 :           EXPECT_TOKEN('(');
     949             :           bool negate = false;
     950          36 :           if (Check('-')) {
     951             :             negate = true;
     952             :           }
     953             :           double dvalue = 0.0;
     954          36 :           if (CheckForDouble(&dvalue)) {
     955          20 :             info->kind = VarKind::kLocal;
     956          20 :             info->type = AsmType::Float();
     957          20 :             info->index = static_cast<uint32_t>(param_count + locals->size());
     958          40 :             locals->push_back(kWasmF32);
     959          20 :             if (negate) {
     960           0 :               dvalue = -dvalue;
     961             :             }
     962          20 :             current_function_builder_->EmitF32Const(dvalue);
     963          20 :             current_function_builder_->EmitSetLocal(info->index);
     964          16 :           } else if (CheckForUnsigned(&uvalue)) {
     965          12 :             if (uvalue > 0x7FFFFFFF) {
     966           0 :               FAIL("Numeric literal out of range");
     967             :             }
     968          12 :             info->kind = VarKind::kLocal;
     969          12 :             info->type = AsmType::Float();
     970          12 :             info->index = static_cast<uint32_t>(param_count + locals->size());
     971          24 :             locals->push_back(kWasmF32);
     972             :             int32_t value = static_cast<int32_t>(uvalue);
     973          12 :             if (negate) {
     974           0 :               value = -value;
     975             :             }
     976          12 :             float fvalue = static_cast<float>(value);
     977          12 :             current_function_builder_->EmitF32Const(fvalue);
     978          12 :             current_function_builder_->EmitSetLocal(info->index);
     979             :           } else {
     980           4 :             FAIL("Expected variable initial value");
     981             :           }
     982          32 :           EXPECT_TOKEN(')');
     983             :         } else {
     984           0 :           FAIL("expected fround or const global");
     985             :         }
     986      544156 :       } else if (CheckForDouble(&dvalue)) {
     987        3782 :         info->kind = VarKind::kLocal;
     988        3782 :         info->type = AsmType::Double();
     989        3782 :         info->index = static_cast<uint32_t>(param_count + locals->size());
     990        7564 :         locals->push_back(kWasmF64);
     991        3782 :         current_function_builder_->EmitF64Const(dvalue);
     992        3782 :         current_function_builder_->EmitSetLocal(info->index);
     993      540374 :       } else if (CheckForUnsigned(&uvalue)) {
     994      540357 :         info->kind = VarKind::kLocal;
     995      540357 :         info->type = AsmType::Int();
     996      540357 :         info->index = static_cast<uint32_t>(param_count + locals->size());
     997     1080714 :         locals->push_back(kWasmI32);
     998      540357 :         int32_t value = static_cast<int32_t>(uvalue);
     999      540357 :         current_function_builder_->EmitI32Const(value);
    1000      540357 :         current_function_builder_->EmitSetLocal(info->index);
    1001             :       } else {
    1002          17 :         FAIL("Expected variable initial value");
    1003             :       }
    1004      544219 :       if (!Peek(',')) {
    1005             :         break;
    1006             :       }
    1007             :       scanner_.EnterLocalScope();
    1008       37328 :       EXPECT_TOKEN(',');
    1009             :       scanner_.EnterGlobalScope();
    1010             :     }
    1011      506891 :     SkipSemicolon();
    1012             :   }
    1013             : }
    1014             : 
    1015             : // 6.5 ValidateStatement
    1016      523700 : void AsmJsParser::ValidateStatement() {
    1017      523700 :   call_coercion_ = nullptr;
    1018      523700 :   if (Peek('{')) {
    1019       93478 :     RECURSE(Block());
    1020      430222 :   } else if (Peek(';')) {
    1021        1185 :     RECURSE(EmptyStatement());
    1022      429037 :   } else if (Peek(TOK(if))) {
    1023       58030 :     RECURSE(IfStatement());
    1024             :     // clang-format off
    1025      371007 :   } else if (Peek(TOK(return))) {
    1026             :     // clang-format on
    1027       34999 :     RECURSE(ReturnStatement());
    1028      336008 :   } else if (IterationStatement()) {
    1029             :     // Handled in IterationStatement.
    1030      321987 :   } else if (Peek(TOK(break))) {
    1031       24930 :     RECURSE(BreakStatement());
    1032      297057 :   } else if (Peek(TOK(continue))) {
    1033        1082 :     RECURSE(ContinueStatement());
    1034      295975 :   } else if (Peek(TOK(switch))) {
    1035         617 :     RECURSE(SwitchStatement());
    1036             :   } else {
    1037      295358 :     RECURSE(ExpressionStatement());
    1038             :   }
    1039             : }
    1040             : 
    1041             : // 6.5.1 Block
    1042       93478 : void AsmJsParser::Block() {
    1043       93478 :   bool can_break_to_block = pending_label_ != 0;
    1044       93478 :   if (can_break_to_block) {
    1045          16 :     Begin(pending_label_);
    1046             :   }
    1047       93478 :   pending_label_ = 0;
    1048       93478 :   EXPECT_TOKEN('{');
    1049      394486 :   while (!failed_ && !Peek('}')) {
    1050      301032 :     RECURSE(ValidateStatement());
    1051             :   }
    1052       93454 :   EXPECT_TOKEN('}');
    1053       93454 :   if (can_break_to_block) {
    1054             :     End();
    1055             :   }
    1056             : }
    1057             : 
    1058             : // 6.5.2 ExpressionStatement
    1059      295358 : void AsmJsParser::ExpressionStatement() {
    1060      295358 :   if (scanner_.IsGlobal() || scanner_.IsLocal()) {
    1061             :     // NOTE: Both global or local identifiers can also be used as labels.
    1062      295302 :     scanner_.Next();
    1063      295302 :     if (Peek(':')) {
    1064        2529 :       scanner_.Rewind();
    1065        2529 :       RECURSE(LabelledStatement());
    1066             :       return;
    1067             :     }
    1068      292773 :     scanner_.Rewind();
    1069             :   }
    1070             :   AsmType* ret;
    1071      292829 :   RECURSE(ret = ValidateExpression());
    1072      292676 :   if (!ret->IsA(AsmType::Void())) {
    1073      269570 :     current_function_builder_->Emit(kExprDrop);
    1074             :   }
    1075      292676 :   SkipSemicolon();
    1076             : }
    1077             : 
    1078             : // 6.5.3 EmptyStatement
    1079        1185 : void AsmJsParser::EmptyStatement() { EXPECT_TOKEN(';'); }
    1080             : 
    1081             : // 6.5.4 IfStatement
    1082       58030 : void AsmJsParser::IfStatement() {
    1083       58030 :   EXPECT_TOKEN(TOK(if));
    1084       58030 :   EXPECT_TOKEN('(');
    1085       58030 :   RECURSE(Expression(AsmType::Int()));
    1086       57998 :   EXPECT_TOKEN(')');
    1087       57998 :   current_function_builder_->EmitWithU8(kExprIf, kLocalVoid);
    1088             :   BareBegin();
    1089       57998 :   RECURSE(ValidateStatement());
    1090       57974 :   if (Check(TOK(else))) {
    1091       21271 :     current_function_builder_->Emit(kExprElse);
    1092       21271 :     RECURSE(ValidateStatement());
    1093             :   }
    1094       57974 :   current_function_builder_->Emit(kExprEnd);
    1095             :   BareEnd();
    1096             : }
    1097             : 
    1098             : // 6.5.5 ReturnStatement
    1099       34999 : void AsmJsParser::ReturnStatement() {
    1100             :   // clang-format off
    1101       34999 :   EXPECT_TOKEN(TOK(return));
    1102             :   // clang-format on
    1103       34999 :   if (!Peek(';') && !Peek('}')) {
    1104             :     // TODO(bradnelson): See if this can be factored out.
    1105             :     AsmType* ret;
    1106       28734 :     RECURSE(ret = Expression(return_type_));
    1107       28607 :     if (ret->IsA(AsmType::Double())) {
    1108         950 :       return_type_ = AsmType::Double();
    1109       27657 :     } else if (ret->IsA(AsmType::Float())) {
    1110         181 :       return_type_ = AsmType::Float();
    1111       27476 :     } else if (ret->IsA(AsmType::Signed())) {
    1112       27434 :       return_type_ = AsmType::Signed();
    1113             :     } else {
    1114          42 :       FAIL("Invalid return type");
    1115             :     }
    1116        6265 :   } else if (return_type_ == nullptr) {
    1117        2819 :     return_type_ = AsmType::Void();
    1118        3446 :   } else if (!return_type_->IsA(AsmType::Void())) {
    1119           4 :     FAIL("Invalid void return type");
    1120             :   }
    1121       34826 :   current_function_builder_->Emit(kExprReturn);
    1122       34826 :   SkipSemicolon();
    1123             : }
    1124             : 
    1125             : // 6.5.6 IterationStatement
    1126      336008 : bool AsmJsParser::IterationStatement() {
    1127      336008 :   if (Peek(TOK(while))) {
    1128        5127 :     WhileStatement();
    1129      330881 :   } else if (Peek(TOK(do))) {
    1130        8749 :     DoStatement();
    1131      322132 :   } else if (Peek(TOK(for))) {
    1132         145 :     ForStatement();
    1133             :   } else {
    1134             :     return false;
    1135             :   }
    1136             :   return true;
    1137             : }
    1138             : 
    1139             : // 6.5.6 IterationStatement - while
    1140        5127 : void AsmJsParser::WhileStatement() {
    1141             :   // a: block {
    1142        5127 :   Begin(pending_label_);
    1143             :   //   b: loop {
    1144        5127 :   Loop(pending_label_);
    1145        5127 :   pending_label_ = 0;
    1146        5127 :   EXPECT_TOKEN(TOK(while));
    1147        5127 :   EXPECT_TOKEN('(');
    1148        5127 :   RECURSE(Expression(AsmType::Int()));
    1149        5111 :   EXPECT_TOKEN(')');
    1150             :   //     if (!CONDITION) break a;
    1151        5111 :   current_function_builder_->Emit(kExprI32Eqz);
    1152        5111 :   current_function_builder_->EmitWithU8(kExprBrIf, 1);
    1153             :   //     BODY
    1154        5111 :   RECURSE(ValidateStatement());
    1155             :   //     continue b;
    1156        5107 :   current_function_builder_->EmitWithU8(kExprBr, 0);
    1157             :   End();
    1158             :   //   }
    1159             :   // }
    1160             :   End();
    1161             : }
    1162             : 
    1163             : // 6.5.6 IterationStatement - do
    1164        8749 : void AsmJsParser::DoStatement() {
    1165             :   // a: block {
    1166        8749 :   Begin(pending_label_);
    1167             :   //   b: loop {
    1168        8749 :   Loop();
    1169             :   //     c: block {  // but treated like loop so continue works
    1170        8749 :   BareBegin(BlockKind::kLoop, pending_label_);
    1171        8749 :   current_function_builder_->EmitWithU8(kExprBlock, kLocalVoid);
    1172        8749 :   pending_label_ = 0;
    1173        8749 :   EXPECT_TOKEN(TOK(do));
    1174             :   //       BODY
    1175        8749 :   RECURSE(ValidateStatement());
    1176        8749 :   EXPECT_TOKEN(TOK(while));
    1177             :   End();
    1178             :   //     }  // end c
    1179        8749 :   EXPECT_TOKEN('(');
    1180        8749 :   RECURSE(Expression(AsmType::Int()));
    1181             :   //     if (!CONDITION) break a;
    1182        8737 :   current_function_builder_->Emit(kExprI32Eqz);
    1183        8737 :   current_function_builder_->EmitWithU8(kExprBrIf, 1);
    1184             :   //     continue b;
    1185        8737 :   current_function_builder_->EmitWithU8(kExprBr, 0);
    1186        8737 :   EXPECT_TOKEN(')');
    1187             :   //   }  // end b
    1188             :   End();
    1189             :   // }  // end a
    1190             :   End();
    1191        8737 :   SkipSemicolon();
    1192             : }
    1193             : 
    1194             : // 6.5.6 IterationStatement - for
    1195         145 : void AsmJsParser::ForStatement() {
    1196         145 :   EXPECT_TOKEN(TOK(for));
    1197         145 :   EXPECT_TOKEN('(');
    1198         145 :   if (!Peek(';')) {
    1199             :     AsmType* ret;
    1200         120 :     RECURSE(ret = Expression(nullptr));
    1201         112 :     if (!ret->IsA(AsmType::Void())) {
    1202         112 :       current_function_builder_->Emit(kExprDrop);
    1203             :     }
    1204             :   }
    1205         137 :   EXPECT_TOKEN(';');
    1206             :   // a: block {
    1207         137 :   Begin(pending_label_);
    1208             :   //   b: loop {
    1209         137 :   Loop();
    1210             :   //     c: block {  // but treated like loop so continue works
    1211         137 :   BareBegin(BlockKind::kLoop, pending_label_);
    1212         137 :   current_function_builder_->EmitWithU8(kExprBlock, kLocalVoid);
    1213         137 :   pending_label_ = 0;
    1214         137 :   if (!Peek(';')) {
    1215             :     //       if (!CONDITION) break a;
    1216         116 :     RECURSE(Expression(AsmType::Int()));
    1217         104 :     current_function_builder_->Emit(kExprI32Eqz);
    1218         104 :     current_function_builder_->EmitWithU8(kExprBrIf, 2);
    1219             :   }
    1220         125 :   EXPECT_TOKEN(';');
    1221             :   // Race past INCREMENT
    1222             :   size_t increment_position = scanner_.Position();
    1223         125 :   ScanToClosingParenthesis();
    1224         125 :   EXPECT_TOKEN(')');
    1225             :   //       BODY
    1226         125 :   RECURSE(ValidateStatement());
    1227             :   //     }  // end c
    1228             :   End();
    1229             :   //     INCREMENT
    1230             :   size_t end_position = scanner_.Position();
    1231         121 :   scanner_.Seek(increment_position);
    1232         121 :   if (!Peek(')')) {
    1233         100 :     RECURSE(Expression(nullptr));
    1234             :     // NOTE: No explicit drop because below break is an implicit drop.
    1235             :   }
    1236             :   //     continue b;
    1237         121 :   current_function_builder_->EmitWithU8(kExprBr, 0);
    1238         121 :   scanner_.Seek(end_position);
    1239             :   //   }  // end b
    1240             :   End();
    1241             :   // }  // end a
    1242             :   End();
    1243             : }
    1244             : 
    1245             : // 6.5.7 BreakStatement
    1246       24930 : void AsmJsParser::BreakStatement() {
    1247       24930 :   EXPECT_TOKEN(TOK(break));
    1248             :   AsmJsScanner::token_t label_name = kTokenNone;
    1249       24930 :   if (scanner_.IsGlobal() || scanner_.IsLocal()) {
    1250             :     // NOTE: Currently using globals/locals for labels too.
    1251             :     label_name = Consume();
    1252             :   }
    1253             :   int depth = FindBreakLabelDepth(label_name);
    1254       24930 :   if (depth < 0) {
    1255           4 :     FAIL("Illegal break");
    1256             :   }
    1257       24926 :   current_function_builder_->Emit(kExprBr);
    1258       24926 :   current_function_builder_->EmitI32V(depth);
    1259       24926 :   SkipSemicolon();
    1260             : }
    1261             : 
    1262             : // 6.5.8 ContinueStatement
    1263        1082 : void AsmJsParser::ContinueStatement() {
    1264        1082 :   EXPECT_TOKEN(TOK(continue));
    1265             :   AsmJsScanner::token_t label_name = kTokenNone;
    1266        1082 :   if (scanner_.IsGlobal() || scanner_.IsLocal()) {
    1267             :     // NOTE: Currently using globals/locals for labels too.
    1268             :     label_name = Consume();
    1269             :   }
    1270             :   int depth = FindContinueLabelDepth(label_name);
    1271        1082 :   if (depth < 0) {
    1272           0 :     FAIL("Illegal continue");
    1273             :   }
    1274        1082 :   current_function_builder_->EmitWithI32V(kExprBr, depth);
    1275        1082 :   SkipSemicolon();
    1276             : }
    1277             : 
    1278             : // 6.5.9 LabelledStatement
    1279        2529 : void AsmJsParser::LabelledStatement() {
    1280             :   DCHECK(scanner_.IsGlobal() || scanner_.IsLocal());
    1281             :   // NOTE: Currently using globals/locals for labels too.
    1282        2529 :   if (pending_label_ != 0) {
    1283           0 :     FAIL("Double label unsupported");
    1284             :   }
    1285        2529 :   pending_label_ = scanner_.Token();
    1286        2529 :   scanner_.Next();
    1287        2529 :   EXPECT_TOKEN(':');
    1288        2529 :   RECURSE(ValidateStatement());
    1289             : }
    1290             : 
    1291             : // 6.5.10 SwitchStatement
    1292         617 : void AsmJsParser::SwitchStatement() {
    1293         634 :   EXPECT_TOKEN(TOK(switch));
    1294         617 :   EXPECT_TOKEN('(');
    1295             :   AsmType* test;
    1296         617 :   RECURSE(test = Expression(nullptr));
    1297         612 :   if (!test->IsA(AsmType::Signed())) {
    1298           0 :     FAIL("Expected signed for switch value");
    1299             :   }
    1300         612 :   EXPECT_TOKEN(')');
    1301             :   uint32_t tmp = TempVariable(0);
    1302         612 :   current_function_builder_->EmitSetLocal(tmp);
    1303         612 :   Begin(pending_label_);
    1304         612 :   pending_label_ = 0;
    1305             :   // TODO(bradnelson): Make less weird.
    1306         612 :   CachedVector<int32_t> cases(cached_int_vectors_);
    1307         612 :   GatherCases(&cases);
    1308         612 :   EXPECT_TOKEN('{');
    1309         612 :   size_t count = cases.size() + 1;
    1310       41816 :   for (size_t i = 0; i < count; ++i) {
    1311             :     BareBegin(BlockKind::kOther);
    1312       20602 :     current_function_builder_->EmitWithU8(kExprBlock, kLocalVoid);
    1313             :   }
    1314             :   int table_pos = 0;
    1315       20602 :   for (auto c : cases) {
    1316       19990 :     current_function_builder_->EmitGetLocal(tmp);
    1317       19990 :     current_function_builder_->EmitI32Const(c);
    1318       19990 :     current_function_builder_->Emit(kExprI32Eq);
    1319       19990 :     current_function_builder_->EmitWithI32V(kExprBrIf, table_pos++);
    1320             :   }
    1321         612 :   current_function_builder_->EmitWithI32V(kExprBr, table_pos++);
    1322       20594 :   while (!failed_ && Peek(TOK(case))) {
    1323       19994 :     current_function_builder_->Emit(kExprEnd);
    1324             :     BareEnd();
    1325       19994 :     RECURSE(ValidateCase());
    1326             :   }
    1327         600 :   current_function_builder_->Emit(kExprEnd);
    1328             :   BareEnd();
    1329         600 :   if (Peek(TOK(default))) {
    1330         584 :     RECURSE(ValidateDefault());
    1331             :   }
    1332         600 :   EXPECT_TOKEN('}');
    1333             :   End();
    1334             : }
    1335             : 
    1336             : // 6.6. ValidateCase
    1337       19994 : void AsmJsParser::ValidateCase() {
    1338       19994 :   EXPECT_TOKEN(TOK(case));
    1339             :   bool negate = false;
    1340       19994 :   if (Check('-')) {
    1341             :     negate = true;
    1342             :   }
    1343             :   uint32_t uvalue;
    1344       19994 :   if (!CheckForUnsigned(&uvalue)) {
    1345           4 :     FAIL("Expected numeric literal");
    1346             :   }
    1347             :   // TODO(bradnelson): Share negation plumbing.
    1348       19990 :   if ((negate && uvalue > 0x80000000) || (!negate && uvalue > 0x7FFFFFFF)) {
    1349           0 :     FAIL("Numeric literal out of range");
    1350             :   }
    1351             :   int32_t value = static_cast<int32_t>(uvalue);
    1352             :   DCHECK_IMPLIES(negate && uvalue == 0x80000000, value == kMinInt);
    1353             :   if (negate && value != kMinInt) {
    1354             :     value = -value;
    1355             :   }
    1356       19990 :   EXPECT_TOKEN(':');
    1357       39907 :   while (!failed_ && !Peek('}') && !Peek(TOK(case)) && !Peek(TOK(default))) {
    1358       19925 :     RECURSE(ValidateStatement());
    1359             :   }
    1360             : }
    1361             : 
    1362             : // 6.7 ValidateDefault
    1363         584 : void AsmJsParser::ValidateDefault() {
    1364         584 :   EXPECT_TOKEN(TOK(default));
    1365         584 :   EXPECT_TOKEN(':');
    1366        1182 :   while (!failed_ && !Peek('}')) {
    1367         598 :     RECURSE(ValidateStatement());
    1368             :   }
    1369             : }
    1370             : 
    1371             : // 6.8 ValidateExpression
    1372      293266 : AsmType* AsmJsParser::ValidateExpression() {
    1373             :   AsmType* ret;
    1374      293266 :   RECURSEn(ret = Expression(nullptr));
    1375      293113 :   return ret;
    1376             : }
    1377             : 
    1378             : // 6.8.1 Expression
    1379      542532 : AsmType* AsmJsParser::Expression(AsmType* expected) {
    1380             :   AsmType* a;
    1381        3159 :   for (;;) {
    1382      545691 :     RECURSEn(a = AssignmentExpression());
    1383      545237 :     if (Peek(',')) {
    1384        3159 :       if (a->IsA(AsmType::None())) {
    1385           0 :         FAILn("Expected actual type");
    1386             :       }
    1387        3159 :       if (!a->IsA(AsmType::Void())) {
    1388        3094 :         current_function_builder_->Emit(kExprDrop);
    1389             :       }
    1390        3159 :       EXPECT_TOKENn(',');
    1391             :       continue;
    1392             :     }
    1393             :     break;
    1394             :   }
    1395      542078 :   if (expected != nullptr && !a->IsA(expected)) {
    1396           8 :     FAILn("Unexpected type");
    1397             :   }
    1398             :   return a;
    1399             : }
    1400             : 
    1401             : // 6.8.2 NumericLiteral
    1402      726122 : AsmType* AsmJsParser::NumericLiteral() {
    1403      726122 :   call_coercion_ = nullptr;
    1404             :   double dvalue = 0.0;
    1405             :   uint32_t uvalue = 0;
    1406      726122 :   if (CheckForDouble(&dvalue)) {
    1407        5584 :     current_function_builder_->EmitF64Const(dvalue);
    1408        5584 :     return AsmType::Double();
    1409      720538 :   } else if (CheckForUnsigned(&uvalue)) {
    1410      720499 :     if (uvalue <= 0x7FFFFFFF) {
    1411      720353 :       current_function_builder_->EmitI32Const(static_cast<int32_t>(uvalue));
    1412      720353 :       return AsmType::FixNum();
    1413             :     } else {
    1414         146 :       current_function_builder_->EmitI32Const(static_cast<int32_t>(uvalue));
    1415         146 :       return AsmType::Unsigned();
    1416             :     }
    1417             :   } else {
    1418          39 :     FAILn("Expected numeric literal.");
    1419             :   }
    1420             : }
    1421             : 
    1422             : // 6.8.3 Identifier
    1423      496294 : AsmType* AsmJsParser::Identifier() {
    1424      496294 :   call_coercion_ = nullptr;
    1425      496294 :   if (scanner_.IsLocal()) {
    1426      477510 :     VarInfo* info = GetVarInfo(Consume());
    1427      477510 :     if (info->kind != VarKind::kLocal) {
    1428           0 :       FAILn("Undefined local variable");
    1429             :     }
    1430      477510 :     current_function_builder_->EmitGetLocal(info->index);
    1431      477510 :     return info->type;
    1432       18784 :   } else if (scanner_.IsGlobal()) {
    1433       18784 :     VarInfo* info = GetVarInfo(Consume());
    1434       18784 :     if (info->kind != VarKind::kGlobal) {
    1435          51 :       FAILn("Undefined global variable");
    1436             :     }
    1437       18733 :     current_function_builder_->EmitWithI32V(kExprGetGlobal, VarIndex(info));
    1438       18733 :     return info->type;
    1439             :   }
    1440           0 :   UNREACHABLE();
    1441             : }
    1442             : 
    1443             : // 6.8.4 CallExpression
    1444     1570431 : AsmType* AsmJsParser::CallExpression() {
    1445             :   AsmType* ret;
    1446     1806700 :   if (scanner_.IsGlobal() &&
    1447      236269 :       GetVarInfo(scanner_.Token())->type->IsA(stdlib_fround_)) {
    1448         437 :     ValidateFloatCoercion();
    1449         437 :     return AsmType::Float();
    1450     1805826 :   } else if (scanner_.IsGlobal() &&
    1451      235832 :              GetVarInfo(scanner_.Token())->type->IsA(AsmType::Heap())) {
    1452      169661 :     RECURSEn(ret = MemberExpression());
    1453     1400333 :   } else if (Peek('(')) {
    1454      130530 :     RECURSEn(ret = ParenthesizedExpression());
    1455     1269803 :   } else if (PeekCall()) {
    1456       47387 :     RECURSEn(ret = ValidateCall());
    1457     1222416 :   } else if (scanner_.IsLocal() || scanner_.IsGlobal()) {
    1458      496294 :     RECURSEn(ret = Identifier());
    1459             :   } else {
    1460      726122 :     RECURSEn(ret = NumericLiteral());
    1461             :   }
    1462             :   return ret;
    1463             : }
    1464             : 
    1465             : // 6.8.5 MemberExpression
    1466      169661 : AsmType* AsmJsParser::MemberExpression() {
    1467      169661 :   call_coercion_ = nullptr;
    1468      169661 :   RECURSEn(ValidateHeapAccess());
    1469             :   DCHECK_NOT_NULL(heap_access_type_);
    1470      169633 :   if (Peek('=')) {
    1471       65900 :     inside_heap_assignment_ = true;
    1472       65900 :     return heap_access_type_->StoreType();
    1473             :   } else {
    1474             : #define V(array_type, wasmload, wasmstore, type)                       \
    1475             :   if (heap_access_type_->IsA(AsmType::array_type())) {                 \
    1476             :     current_function_builder_->Emit(kExpr##type##AsmjsLoad##wasmload); \
    1477             :     return heap_access_type_->LoadType();                              \
    1478             :   }
    1479      103733 :     STDLIB_ARRAY_TYPE_LIST(V)
    1480             : #undef V
    1481           0 :     FAILn("Expected valid heap load");
    1482             :   }
    1483             : }
    1484             : 
    1485             : // 6.8.6 AssignmentExpression
    1486      929690 : AsmType* AsmJsParser::AssignmentExpression() {
    1487             :   AsmType* ret;
    1488     1170376 :   if (scanner_.IsGlobal() &&
    1489      240686 :       GetVarInfo(scanner_.Token())->type->IsA(AsmType::Heap())) {
    1490      156014 :     RECURSEn(ret = ConditionalExpression());
    1491      155981 :     if (Peek('=')) {
    1492       65900 :       if (!inside_heap_assignment_) {
    1493           0 :         FAILn("Invalid assignment target");
    1494             :       }
    1495       65900 :       inside_heap_assignment_ = false;
    1496             :       DCHECK_NOT_NULL(heap_access_type_);
    1497       65900 :       AsmType* heap_type = heap_access_type_;
    1498       65900 :       EXPECT_TOKENn('=');
    1499             :       AsmType* value;
    1500       65900 :       RECURSEn(value = AssignmentExpression());
    1501       65896 :       if (!value->IsA(ret)) {
    1502           0 :         FAILn("Illegal type stored to heap view");
    1503             :       }
    1504       69396 :       if (heap_type->IsA(AsmType::Float32Array()) &&
    1505        3500 :           value->IsA(AsmType::DoubleQ())) {
    1506             :         // Assignment to a float32 heap can be used to convert doubles.
    1507        3496 :         current_function_builder_->Emit(kExprF32ConvertF64);
    1508             :       }
    1509       68514 :       if (heap_type->IsA(AsmType::Float64Array()) &&
    1510        2618 :           value->IsA(AsmType::FloatQ())) {
    1511             :         // Assignment to a float64 heap can be used to convert floats.
    1512           8 :         current_function_builder_->Emit(kExprF64ConvertF32);
    1513             :       }
    1514             :       ret = value;
    1515             : #define V(array_type, wasmload, wasmstore, type)                         \
    1516             :   if (heap_type->IsA(AsmType::array_type())) {                           \
    1517             :     current_function_builder_->Emit(kExpr##type##AsmjsStore##wasmstore); \
    1518             :     return ret;                                                          \
    1519             :   }
    1520       65896 :       STDLIB_ARRAY_TYPE_LIST(V)
    1521             : #undef V
    1522             :     }
    1523      773676 :   } else if (scanner_.IsLocal() || scanner_.IsGlobal()) {
    1524             :     bool is_local = scanner_.IsLocal();
    1525      564006 :     VarInfo* info = GetVarInfo(scanner_.Token());
    1526             :     USE(is_local);
    1527      564006 :     ret = info->type;
    1528      564006 :     scanner_.Next();
    1529      564006 :     if (Check('=')) {
    1530             :       // NOTE: Before this point, this might have been VarKind::kUnused even in
    1531             :       // valid code, as it might be a label.
    1532      201151 :       if (info->kind == VarKind::kUnused) {
    1533          13 :         FAILn("Undeclared assignment target");
    1534             :       }
    1535      201138 :       if (!info->mutable_variable) {
    1536          33 :         FAILn("Expected mutable variable in assignment");
    1537             :       }
    1538             :       DCHECK(is_local ? info->kind == VarKind::kLocal
    1539             :                       : info->kind == VarKind::kGlobal);
    1540             :       AsmType* value;
    1541      201105 :       RECURSEn(value = AssignmentExpression());
    1542      201064 :       if (!value->IsA(ret)) {
    1543          12 :         FAILn("Type mismatch in assignment");
    1544             :       }
    1545      201052 :       if (info->kind == VarKind::kLocal) {
    1546      179425 :         current_function_builder_->EmitTeeLocal(info->index);
    1547       21627 :       } else if (info->kind == VarKind::kGlobal) {
    1548       21627 :         current_function_builder_->EmitWithU32V(kExprSetGlobal, VarIndex(info));
    1549       21627 :         current_function_builder_->EmitWithU32V(kExprGetGlobal, VarIndex(info));
    1550             :       } else {
    1551           0 :         UNREACHABLE();
    1552             :       }
    1553             :       return ret;
    1554             :     }
    1555      362855 :     scanner_.Rewind();
    1556      362855 :     RECURSEn(ret = ConditionalExpression());
    1557             :   } else {
    1558      209670 :     RECURSEn(ret = ConditionalExpression());
    1559             :   }
    1560             :   return ret;
    1561             : }
    1562             : 
    1563             : // 6.8.7 UnaryExpression
    1564     1596025 : AsmType* AsmJsParser::UnaryExpression() {
    1565             :   AsmType* ret;
    1566     1596025 :   if (Check('-')) {
    1567             :     uint32_t uvalue;
    1568        5619 :     if (CheckForUnsigned(&uvalue)) {
    1569             :       // TODO(bradnelson): was supposed to be 0x7FFFFFFF, check errata.
    1570        4625 :       if (uvalue <= 0x80000000) {
    1571        9250 :         current_function_builder_->EmitI32Const(
    1572        4625 :             base::NegateWithWraparound(static_cast<int32_t>(uvalue)));
    1573             :       } else {
    1574           0 :         FAILn("Integer numeric literal out of range.");
    1575             :       }
    1576             :       ret = AsmType::Signed();
    1577             :     } else {
    1578         994 :       RECURSEn(ret = UnaryExpression());
    1579         994 :       if (ret->IsA(AsmType::Int())) {
    1580             :         TemporaryVariableScope tmp(this);
    1581           5 :         current_function_builder_->EmitSetLocal(tmp.get());
    1582           5 :         current_function_builder_->EmitI32Const(0);
    1583           5 :         current_function_builder_->EmitGetLocal(tmp.get());
    1584           5 :         current_function_builder_->Emit(kExprI32Sub);
    1585             :         ret = AsmType::Intish();
    1586         989 :       } else if (ret->IsA(AsmType::DoubleQ())) {
    1587         984 :         current_function_builder_->Emit(kExprF64Neg);
    1588             :         ret = AsmType::Double();
    1589           5 :       } else if (ret->IsA(AsmType::FloatQ())) {
    1590           5 :         current_function_builder_->Emit(kExprF32Neg);
    1591             :         ret = AsmType::Floatish();
    1592             :       } else {
    1593           0 :         FAILn("expected int/double?/float?");
    1594             :       }
    1595             :     }
    1596     1590406 :   } else if (Peek('+')) {
    1597       14607 :     call_coercion_ = AsmType::Double();
    1598       14607 :     call_coercion_position_ = scanner_.Position();
    1599       14607 :     scanner_.Next();  // Done late for correct position.
    1600       14607 :     RECURSEn(ret = UnaryExpression());
    1601             :     // TODO(bradnelson): Generalize.
    1602       14580 :     if (ret->IsA(AsmType::Signed())) {
    1603         972 :       current_function_builder_->Emit(kExprF64SConvertI32);
    1604             :       ret = AsmType::Double();
    1605       13608 :     } else if (ret->IsA(AsmType::Unsigned())) {
    1606         202 :       current_function_builder_->Emit(kExprF64UConvertI32);
    1607             :       ret = AsmType::Double();
    1608       13406 :     } else if (ret->IsA(AsmType::DoubleQ())) {
    1609             :       ret = AsmType::Double();
    1610        5937 :     } else if (ret->IsA(AsmType::FloatQ())) {
    1611        5929 :       current_function_builder_->Emit(kExprF64ConvertF32);
    1612             :       ret = AsmType::Double();
    1613             :     } else {
    1614           8 :       FAILn("expected signed/unsigned/double?/float?");
    1615             :     }
    1616     1575799 :   } else if (Check('!')) {
    1617        4223 :     RECURSEn(ret = UnaryExpression());
    1618        4223 :     if (!ret->IsA(AsmType::Int())) {
    1619           0 :       FAILn("expected int");
    1620             :     }
    1621        4223 :     current_function_builder_->Emit(kExprI32Eqz);
    1622     1571576 :   } else if (Check('~')) {
    1623        1145 :     if (Check('~')) {
    1624         383 :       RECURSEn(ret = UnaryExpression());
    1625         383 :       if (ret->IsA(AsmType::Double())) {
    1626         375 :         current_function_builder_->Emit(kExprI32AsmjsSConvertF64);
    1627           8 :       } else if (ret->IsA(AsmType::FloatQ())) {
    1628           8 :         current_function_builder_->Emit(kExprI32AsmjsSConvertF32);
    1629             :       } else {
    1630           0 :         FAILn("expected double or float?");
    1631             :       }
    1632             :       ret = AsmType::Signed();
    1633             :     } else {
    1634         762 :       RECURSEn(ret = UnaryExpression());
    1635         762 :       if (!ret->IsA(AsmType::Intish())) {
    1636           0 :         FAILn("operator ~ expects intish");
    1637             :       }
    1638         762 :       current_function_builder_->EmitI32Const(0xFFFFFFFF);
    1639         762 :       current_function_builder_->Emit(kExprI32Xor);
    1640             :       ret = AsmType::Signed();
    1641             :     }
    1642             :   } else {
    1643     1570431 :     RECURSEn(ret = CallExpression());
    1644             :   }
    1645             :   return ret;
    1646             : }
    1647             : 
    1648             : // 6.8.8 MultiplicativeExpression
    1649     1582111 : AsmType* AsmJsParser::MultiplicativeExpression() {
    1650             :   AsmType* a;
    1651             :   uint32_t uvalue;
    1652     1582111 :   if (CheckForUnsignedBelow(0x100000, &uvalue)) {
    1653      713682 :     if (Check('*')) {
    1654             :       AsmType* a;
    1655           9 :       RECURSEn(a = UnaryExpression());
    1656           9 :       if (!a->IsA(AsmType::Int())) {
    1657           0 :         FAILn("Expected int");
    1658             :       }
    1659           9 :       int32_t value = static_cast<int32_t>(uvalue);
    1660           9 :       current_function_builder_->EmitI32Const(value);
    1661           9 :       current_function_builder_->Emit(kExprI32Mul);
    1662           9 :       return AsmType::Intish();
    1663             :     } else {
    1664      713673 :       scanner_.Rewind();
    1665      713673 :       RECURSEn(a = UnaryExpression());
    1666             :     }
    1667      868429 :   } else if (Check('-')) {
    1668       22001 :     if (CheckForUnsignedBelow(0x100000, &uvalue)) {
    1669       16721 :       int32_t value = -static_cast<int32_t>(uvalue);
    1670       16721 :       current_function_builder_->EmitI32Const(value);
    1671       16721 :       if (Check('*')) {
    1672             :         AsmType* a;
    1673           0 :         RECURSEn(a = UnaryExpression());
    1674           0 :         if (!a->IsA(AsmType::Int())) {
    1675           0 :           FAILn("Expected int");
    1676             :         }
    1677           0 :         current_function_builder_->Emit(kExprI32Mul);
    1678           0 :         return AsmType::Intish();
    1679             :       }
    1680             :       a = AsmType::Signed();
    1681             :     } else {
    1682        5280 :       scanner_.Rewind();
    1683        5280 :       RECURSEn(a = UnaryExpression());
    1684             :     }
    1685             :   } else {
    1686      846428 :     RECURSEn(a = UnaryExpression());
    1687             :   }
    1688             :   for (;;) {
    1689     1591484 :     if (Check('*')) {
    1690             :       uint32_t uvalue;
    1691       12776 :       if (Check('-')) {
    1692          49 :         if (CheckForUnsigned(&uvalue)) {
    1693           8 :           if (uvalue >= 0x100000) {
    1694           0 :             FAILn("Constant multiple out of range");
    1695             :           }
    1696           8 :           if (!a->IsA(AsmType::Int())) {
    1697           4 :             FAILn("Integer multiply of expects int");
    1698             :           }
    1699           4 :           int32_t value = -static_cast<int32_t>(uvalue);
    1700           4 :           current_function_builder_->EmitI32Const(value);
    1701           4 :           current_function_builder_->Emit(kExprI32Mul);
    1702           4 :           return AsmType::Intish();
    1703             :         }
    1704          41 :         scanner_.Rewind();
    1705       12727 :       } else if (CheckForUnsigned(&uvalue)) {
    1706        5021 :         if (uvalue >= 0x100000) {
    1707           0 :           FAILn("Constant multiple out of range");
    1708             :         }
    1709        5021 :         if (!a->IsA(AsmType::Int())) {
    1710           4 :           FAILn("Integer multiply of expects int");
    1711             :         }
    1712        5017 :         int32_t value = static_cast<int32_t>(uvalue);
    1713        5017 :         current_function_builder_->EmitI32Const(value);
    1714        5017 :         current_function_builder_->Emit(kExprI32Mul);
    1715        5017 :         return AsmType::Intish();
    1716             :       }
    1717             :       AsmType* b;
    1718        7747 :       RECURSEn(b = UnaryExpression());
    1719        7747 :       if (a->IsA(AsmType::DoubleQ()) && b->IsA(AsmType::DoubleQ())) {
    1720        7742 :         current_function_builder_->Emit(kExprF64Mul);
    1721             :         a = AsmType::Double();
    1722           5 :       } else if (a->IsA(AsmType::FloatQ()) && b->IsA(AsmType::FloatQ())) {
    1723           5 :         current_function_builder_->Emit(kExprF32Mul);
    1724             :         a = AsmType::Floatish();
    1725             :       } else {
    1726           0 :         FAILn("expected doubles or floats");
    1727             :       }
    1728     1578708 :     } else if (Check('/')) {
    1729             :       AsmType* b;
    1730        1291 :       RECURSEn(b = UnaryExpression());
    1731        1291 :       if (a->IsA(AsmType::DoubleQ()) && b->IsA(AsmType::DoubleQ())) {
    1732         511 :         current_function_builder_->Emit(kExprF64Div);
    1733             :         a = AsmType::Double();
    1734         780 :       } else if (a->IsA(AsmType::FloatQ()) && b->IsA(AsmType::FloatQ())) {
    1735           5 :         current_function_builder_->Emit(kExprF32Div);
    1736             :         a = AsmType::Floatish();
    1737         775 :       } else if (a->IsA(AsmType::Signed()) && b->IsA(AsmType::Signed())) {
    1738         591 :         current_function_builder_->Emit(kExprI32AsmjsDivS);
    1739             :         a = AsmType::Intish();
    1740         184 :       } else if (a->IsA(AsmType::Unsigned()) && b->IsA(AsmType::Unsigned())) {
    1741         184 :         current_function_builder_->Emit(kExprI32AsmjsDivU);
    1742             :         a = AsmType::Intish();
    1743             :       } else {
    1744           0 :         FAILn("expected doubles or floats");
    1745             :       }
    1746     1577417 :     } else if (Check('%')) {
    1747             :       AsmType* b;
    1748         628 :       RECURSEn(b = UnaryExpression());
    1749         628 :       if (a->IsA(AsmType::DoubleQ()) && b->IsA(AsmType::DoubleQ())) {
    1750          20 :         current_function_builder_->Emit(kExprF64Mod);
    1751             :         a = AsmType::Double();
    1752         608 :       } else if (a->IsA(AsmType::Signed()) && b->IsA(AsmType::Signed())) {
    1753         392 :         current_function_builder_->Emit(kExprI32AsmjsRemS);
    1754             :         a = AsmType::Intish();
    1755         216 :       } else if (a->IsA(AsmType::Unsigned()) && b->IsA(AsmType::Unsigned())) {
    1756         216 :         current_function_builder_->Emit(kExprI32AsmjsRemU);
    1757             :         a = AsmType::Intish();
    1758             :       } else {
    1759           0 :         FAILn("expected doubles or floats");
    1760             :       }
    1761             :     } else {
    1762             :       break;
    1763             :     }
    1764             :   }
    1765             :   return a;
    1766             : }
    1767             : 
    1768             : // 6.8.9 AdditiveExpression
    1769     1419642 : AsmType* AsmJsParser::AdditiveExpression() {
    1770             :   AsmType* a;
    1771     1419642 :   RECURSEn(a = MultiplicativeExpression());
    1772             :   int n = 0;
    1773             :   for (;;) {
    1774     1581795 :     if (Check('+')) {
    1775             :       AsmType* b;
    1776      152275 :       RECURSEn(b = MultiplicativeExpression());
    1777      152270 :       if (a->IsA(AsmType::Double()) && b->IsA(AsmType::Double())) {
    1778        4538 :         current_function_builder_->Emit(kExprF64Add);
    1779             :         a = AsmType::Double();
    1780      147732 :       } else if (a->IsA(AsmType::FloatQ()) && b->IsA(AsmType::FloatQ())) {
    1781          21 :         current_function_builder_->Emit(kExprF32Add);
    1782             :         a = AsmType::Floatish();
    1783      147711 :       } else if (a->IsA(AsmType::Int()) && b->IsA(AsmType::Int())) {
    1784      134233 :         current_function_builder_->Emit(kExprI32Add);
    1785             :         a = AsmType::Intish();
    1786             :         n = 2;
    1787       13478 :       } else if (a->IsA(AsmType::Intish()) && b->IsA(AsmType::Intish())) {
    1788             :         // TODO(bradnelson): b should really only be Int.
    1789             :         // specialize intish to capture count.
    1790       13454 :         ++n;
    1791       13454 :         if (n > (1 << 20)) {
    1792           0 :           FAILn("more than 2^20 additive values");
    1793             :         }
    1794       13454 :         current_function_builder_->Emit(kExprI32Add);
    1795             :       } else {
    1796          24 :         FAILn("illegal types for +");
    1797             :       }
    1798     1429520 :     } else if (Check('-')) {
    1799             :       AsmType* b;
    1800       10194 :       RECURSEn(b = MultiplicativeExpression());
    1801       10194 :       if (a->IsA(AsmType::Double()) && b->IsA(AsmType::Double())) {
    1802        3400 :         current_function_builder_->Emit(kExprF64Sub);
    1803             :         a = AsmType::Double();
    1804        6794 :       } else if (a->IsA(AsmType::FloatQ()) && b->IsA(AsmType::FloatQ())) {
    1805           5 :         current_function_builder_->Emit(kExprF32Sub);
    1806             :         a = AsmType::Floatish();
    1807        6789 :       } else if (a->IsA(AsmType::Int()) && b->IsA(AsmType::Int())) {
    1808        6479 :         current_function_builder_->Emit(kExprI32Sub);
    1809             :         a = AsmType::Intish();
    1810             :         n = 2;
    1811         310 :       } else if (a->IsA(AsmType::Intish()) && b->IsA(AsmType::Intish())) {
    1812             :         // TODO(bradnelson): b should really only be Int.
    1813             :         // specialize intish to capture count.
    1814         310 :         ++n;
    1815         310 :         if (n > (1 << 20)) {
    1816           0 :           FAILn("more than 2^20 additive values");
    1817             :         }
    1818         310 :         current_function_builder_->Emit(kExprI32Sub);
    1819             :       } else {
    1820           0 :         FAILn("illegal types for +");
    1821             :       }
    1822             :     } else {
    1823             :       break;
    1824             :     }
    1825             :   }
    1826             :   return a;
    1827             : }
    1828             : 
    1829             : // 6.8.10 ShiftExpression
    1830     1219603 : AsmType* AsmJsParser::ShiftExpression() {
    1831             :   AsmType* a = nullptr;
    1832     1219603 :   RECURSEn(a = AdditiveExpression());
    1833     1219287 :   heap_access_shift_position_ = kNoHeapAccessShift;
    1834             :   // TODO(bradnelson): Implement backtracking to avoid emitting code
    1835             :   // for the x >>> 0 case (similar to what's there for |0).
    1836             :   for (;;) {
    1837     1419326 :     switch (scanner_.Token()) {
    1838             :       case TOK(SAR): {
    1839      154764 :         EXPECT_TOKENn(TOK(SAR));
    1840      154764 :         heap_access_shift_position_ = kNoHeapAccessShift;
    1841             :         // Remember position allowing this shift-expression to be used as part
    1842             :         // of a heap access operation expecting `a >> n:NumericLiteral`.
    1843             :         bool imm = false;
    1844             :         size_t old_pos;
    1845             :         size_t old_code;
    1846             :         uint32_t shift_imm;
    1847      309528 :         if (a->IsA(AsmType::Intish()) && CheckForUnsigned(&shift_imm)) {
    1848             :           old_pos = scanner_.Position();
    1849      154681 :           old_code = current_function_builder_->GetPosition();
    1850      154681 :           scanner_.Rewind();
    1851             :           imm = true;
    1852             :         }
    1853             :         AsmType* b = nullptr;
    1854      154764 :         RECURSEn(b = AdditiveExpression());
    1855             :         // Check for `a >> n:NumericLiteral` pattern.
    1856      154764 :         if (imm && old_pos == scanner_.Position()) {
    1857      154673 :           heap_access_shift_position_ = old_code;
    1858      154673 :           heap_access_shift_value_ = shift_imm;
    1859             :         }
    1860      154764 :         if (!(a->IsA(AsmType::Intish()) && b->IsA(AsmType::Intish()))) {
    1861           0 :           FAILn("Expected intish for operator >>.");
    1862             :         }
    1863      154764 :         current_function_builder_->Emit(kExprI32ShrS);
    1864             :         a = AsmType::Signed();
    1865             :         continue;
    1866             :       }
    1867             : #define HANDLE_CASE(op, opcode, name, result)                        \
    1868             :   case TOK(op): {                                                    \
    1869             :     EXPECT_TOKENn(TOK(op));                                          \
    1870             :     heap_access_shift_position_ = kNoHeapAccessShift;                \
    1871             :     AsmType* b = nullptr;                                            \
    1872             :     RECURSEn(b = AdditiveExpression());                              \
    1873             :     if (!(a->IsA(AsmType::Intish()) && b->IsA(AsmType::Intish()))) { \
    1874             :       FAILn("Expected intish for operator " #name ".");              \
    1875             :     }                                                                \
    1876             :     current_function_builder_->Emit(kExpr##opcode);                  \
    1877             :     a = AsmType::result();                                           \
    1878             :     continue;                                                        \
    1879             :   }
    1880       21621 :         HANDLE_CASE(SHL, I32Shl, "<<", Signed);
    1881       23654 :         HANDLE_CASE(SHR, I32ShrU, ">>>", Unsigned);
    1882             : #undef HANDLE_CASE
    1883             :       default:
    1884             :         return a;
    1885             :     }
    1886             :   }
    1887             : }
    1888             : 
    1889             : // 6.8.11 RelationalExpression
    1890     1044420 : AsmType* AsmJsParser::RelationalExpression() {
    1891             :   AsmType* a = nullptr;
    1892     1044420 :   RECURSEn(a = ShiftExpression());
    1893             :   for (;;) {
    1894     1068862 :     switch (scanner_.Token()) {
    1895             : #define HANDLE_CASE(op, sop, uop, dop, fop, name)                             \
    1896             :   case op: {                                                                  \
    1897             :     EXPECT_TOKENn(op);                                                        \
    1898             :     AsmType* b = nullptr;                                                     \
    1899             :     RECURSEn(b = ShiftExpression());                                          \
    1900             :     if (a->IsA(AsmType::Signed()) && b->IsA(AsmType::Signed())) {             \
    1901             :       current_function_builder_->Emit(kExpr##sop);                            \
    1902             :     } else if (a->IsA(AsmType::Unsigned()) && b->IsA(AsmType::Unsigned())) {  \
    1903             :       current_function_builder_->Emit(kExpr##uop);                            \
    1904             :     } else if (a->IsA(AsmType::Double()) && b->IsA(AsmType::Double())) {      \
    1905             :       current_function_builder_->Emit(kExpr##dop);                            \
    1906             :     } else if (a->IsA(AsmType::Float()) && b->IsA(AsmType::Float())) {        \
    1907             :       current_function_builder_->Emit(kExpr##fop);                            \
    1908             :     } else {                                                                  \
    1909             :       FAILn("Expected signed, unsigned, double, or float for operator " #name \
    1910             :             ".");                                                             \
    1911             :     }                                                                         \
    1912             :     a = AsmType::Int();                                                       \
    1913             :     continue;                                                                 \
    1914             :   }
    1915       12006 :       HANDLE_CASE('<', I32LtS, I32LtU, F64Lt, F32Lt, "<");
    1916        2320 :       HANDLE_CASE(TOK(LE), I32LeS, I32LeU, F64Le, F32Le, "<=");
    1917        7836 :       HANDLE_CASE('>', I32GtS, I32GtU, F64Gt, F32Gt, ">");
    1918        2636 :       HANDLE_CASE(TOK(GE), I32GeS, I32GeU, F64Ge, F32Ge, ">=");
    1919             : #undef HANDLE_CASE
    1920             :       default:
    1921             :         return a;
    1922             :     }
    1923             :   }
    1924             : }
    1925             : 
    1926             : // 6.8.12 EqualityExpression
    1927     1000581 : AsmType* AsmJsParser::EqualityExpression() {
    1928             :   AsmType* a = nullptr;
    1929     1000581 :   RECURSEn(a = RelationalExpression());
    1930             :   for (;;) {
    1931     1044048 :     switch (scanner_.Token()) {
    1932             : #define HANDLE_CASE(op, sop, uop, dop, fop, name)                             \
    1933             :   case op: {                                                                  \
    1934             :     EXPECT_TOKENn(op);                                                        \
    1935             :     AsmType* b = nullptr;                                                     \
    1936             :     RECURSEn(b = RelationalExpression());                                     \
    1937             :     if (a->IsA(AsmType::Signed()) && b->IsA(AsmType::Signed())) {             \
    1938             :       current_function_builder_->Emit(kExpr##sop);                            \
    1939             :     } else if (a->IsA(AsmType::Unsigned()) && b->IsA(AsmType::Unsigned())) {  \
    1940             :       current_function_builder_->Emit(kExpr##uop);                            \
    1941             :     } else if (a->IsA(AsmType::Double()) && b->IsA(AsmType::Double())) {      \
    1942             :       current_function_builder_->Emit(kExpr##dop);                            \
    1943             :     } else if (a->IsA(AsmType::Float()) && b->IsA(AsmType::Float())) {        \
    1944             :       current_function_builder_->Emit(kExpr##fop);                            \
    1945             :     } else {                                                                  \
    1946             :       FAILn("Expected signed, unsigned, double, or float for operator " #name \
    1947             :             ".");                                                             \
    1948             :     }                                                                         \
    1949             :     a = AsmType::Int();                                                       \
    1950             :     continue;                                                                 \
    1951             :   }
    1952       30955 :       HANDLE_CASE(TOK(EQ), I32Eq, I32Eq, F64Eq, F32Eq, "==");
    1953       12884 :       HANDLE_CASE(TOK(NE), I32Ne, I32Ne, F64Ne, F32Ne, "!=");
    1954             : #undef HANDLE_CASE
    1955             :       default:
    1956             :         return a;
    1957             :     }
    1958             :   }
    1959             : }
    1960             : 
    1961             : // 6.8.13 BitwiseANDExpression
    1962      980673 : AsmType* AsmJsParser::BitwiseANDExpression() {
    1963             :   AsmType* a = nullptr;
    1964      980673 :   RECURSEn(a = EqualityExpression());
    1965     1011851 :   while (Check('&')) {
    1966             :     AsmType* b = nullptr;
    1967       15779 :     RECURSEn(b = EqualityExpression());
    1968       15779 :     if (a->IsA(AsmType::Intish()) && b->IsA(AsmType::Intish())) {
    1969       15775 :       current_function_builder_->Emit(kExprI32And);
    1970             :       a = AsmType::Signed();
    1971             :     } else {
    1972           4 :       FAILn("Expected intish for operator &.");
    1973             :     }
    1974             :   }
    1975             :   return a;
    1976             : }
    1977             : 
    1978             : // 6.8.14 BitwiseXORExpression
    1979      979605 : AsmType* AsmJsParser::BitwiseXORExpression() {
    1980             :   AsmType* a = nullptr;
    1981      979605 :   RECURSEn(a = BitwiseANDExpression());
    1982      981365 :   while (Check('^')) {
    1983             :     AsmType* b = nullptr;
    1984        1068 :     RECURSEn(b = BitwiseANDExpression());
    1985        1068 :     if (a->IsA(AsmType::Intish()) && b->IsA(AsmType::Intish())) {
    1986        1068 :       current_function_builder_->Emit(kExprI32Xor);
    1987             :       a = AsmType::Signed();
    1988             :     } else {
    1989           0 :       FAILn("Expected intish for operator &.");
    1990             :     }
    1991             :   }
    1992             :   return a;
    1993             : }
    1994             : 
    1995             : // 6.8.15 BitwiseORExpression
    1996      728539 : AsmType* AsmJsParser::BitwiseORExpression() {
    1997             :   AsmType* a = nullptr;
    1998      728539 :   call_coercion_deferred_position_ = scanner_.Position();
    1999      728539 :   RECURSEn(a = BitwiseXORExpression());
    2000      979209 :   while (Check('|')) {
    2001             :     AsmType* b = nullptr;
    2002             :     // Remember whether the first operand to this OR-expression has requested
    2003             :     // deferred validation of the |0 annotation.
    2004             :     // NOTE: This has to happen here to work recursively.
    2005             :     bool requires_zero =
    2006      251066 :         AsmType::IsExactly(call_coercion_deferred_, AsmType::Signed());
    2007      251066 :     call_coercion_deferred_ = nullptr;
    2008             :     // TODO(bradnelson): Make it prettier.
    2009             :     bool zero = false;
    2010             :     size_t old_pos;
    2011             :     size_t old_code;
    2012      502128 :     if (a->IsA(AsmType::Intish()) && CheckForZero()) {
    2013             :       old_pos = scanner_.Position();
    2014      242622 :       old_code = current_function_builder_->GetPosition();
    2015      242622 :       scanner_.Rewind();
    2016             :       zero = true;
    2017             :     }
    2018      251066 :     RECURSEn(b = BitwiseXORExpression());
    2019             :     // Handle |0 specially.
    2020      251066 :     if (zero && old_pos == scanner_.Position()) {
    2021      242544 :       current_function_builder_->DeleteCodeAfter(old_code);
    2022             :       a = AsmType::Signed();
    2023      242544 :       continue;
    2024             :     }
    2025             :     // Anything not matching |0 breaks the lookahead in {ValidateCall}.
    2026        8522 :     if (requires_zero) {
    2027          12 :       FAILn("Expected |0 type annotation for call");
    2028             :     }
    2029        8510 :     if (a->IsA(AsmType::Intish()) && b->IsA(AsmType::Intish())) {
    2030        8502 :       current_function_builder_->Emit(kExprI32Ior);
    2031             :       a = AsmType::Signed();
    2032             :     } else {
    2033           8 :       FAILn("Expected intish for operator |.");
    2034             :     }
    2035             :   }
    2036             :   DCHECK_NULL(call_coercion_deferred_);
    2037             :   return a;
    2038             : }
    2039             : 
    2040             : // 6.8.16 ConditionalExpression
    2041      728539 : AsmType* AsmJsParser::ConditionalExpression() {
    2042             :   AsmType* test = nullptr;
    2043      728539 :   RECURSEn(test = BitwiseORExpression());
    2044      728143 :   if (Check('?')) {
    2045        7320 :     if (!test->IsA(AsmType::Int())) {
    2046           0 :       FAILn("Expected int in condition of ternary operator.");
    2047             :     }
    2048        7320 :     current_function_builder_->EmitWithU8(kExprIf, kLocalI32);
    2049        7320 :     size_t fixup = current_function_builder_->GetPosition() -
    2050        7320 :                    1;  // Assumes encoding knowledge.
    2051             :     AsmType* cons = nullptr;
    2052        7320 :     RECURSEn(cons = AssignmentExpression());
    2053        7320 :     current_function_builder_->Emit(kExprElse);
    2054        7320 :     EXPECT_TOKENn(':');
    2055             :     AsmType* alt = nullptr;
    2056        7320 :     RECURSEn(alt = AssignmentExpression());
    2057        7320 :     current_function_builder_->Emit(kExprEnd);
    2058        7320 :     if (cons->IsA(AsmType::Int()) && alt->IsA(AsmType::Int())) {
    2059        6714 :       current_function_builder_->FixupByte(fixup, kLocalI32);
    2060        6714 :       return AsmType::Int();
    2061         606 :     } else if (cons->IsA(AsmType::Double()) && alt->IsA(AsmType::Double())) {
    2062         606 :       current_function_builder_->FixupByte(fixup, kLocalF64);
    2063         606 :       return AsmType::Double();
    2064           0 :     } else if (cons->IsA(AsmType::Float()) && alt->IsA(AsmType::Float())) {
    2065           0 :       current_function_builder_->FixupByte(fixup, kLocalF32);
    2066           0 :       return AsmType::Float();
    2067             :     } else {
    2068           0 :       FAILn("Type mismatch in ternary operator.");
    2069             :     }
    2070             :   } else {
    2071             :     return test;
    2072             :   }
    2073             : }
    2074             : 
    2075             : // 6.8.17 ParenthesiedExpression
    2076      130530 : AsmType* AsmJsParser::ParenthesizedExpression() {
    2077      130530 :   call_coercion_ = nullptr;
    2078             :   AsmType* ret;
    2079      130530 :   EXPECT_TOKENn('(');
    2080      130530 :   RECURSEn(ret = Expression(nullptr));
    2081      130433 :   EXPECT_TOKENn(')');
    2082      130433 :   return ret;
    2083             : }
    2084             : 
    2085             : // 6.9 ValidateCall
    2086       47387 : AsmType* AsmJsParser::ValidateCall() {
    2087       47387 :   AsmType* return_type = call_coercion_;
    2088       47387 :   call_coercion_ = nullptr;
    2089             :   size_t call_pos = scanner_.Position();
    2090       47387 :   size_t to_number_pos = call_coercion_position_;
    2091       47387 :   bool allow_peek = (call_coercion_deferred_position_ == scanner_.Position());
    2092             :   AsmJsScanner::token_t function_name = Consume();
    2093             : 
    2094             :   // Distinguish between ordinary function calls and function table calls. In
    2095             :   // both cases we might be seeing the {function_name} for the first time and
    2096             :   // hence allocate a {VarInfo} here, all subsequent uses of the same name then
    2097             :   // need to match the information stored at this point.
    2098             :   base::Optional<TemporaryVariableScope> tmp;
    2099       47387 :   if (Check('[')) {
    2100        4129 :     RECURSEn(EqualityExpression());
    2101        4129 :     EXPECT_TOKENn('&');
    2102             :     uint32_t mask = 0;
    2103        4129 :     if (!CheckForUnsigned(&mask)) {
    2104           0 :       FAILn("Expected mask literal");
    2105             :     }
    2106        8258 :     if (!base::bits::IsPowerOfTwo(mask + 1)) {
    2107           5 :       FAILn("Expected power of 2 mask");
    2108             :     }
    2109        4124 :     current_function_builder_->EmitI32Const(mask);
    2110        4124 :     current_function_builder_->Emit(kExprI32And);
    2111        4124 :     EXPECT_TOKENn(']');
    2112        4124 :     VarInfo* function_info = GetVarInfo(function_name);
    2113        4124 :     if (function_info->kind == VarKind::kUnused) {
    2114         219 :       uint32_t index = module_builder_->AllocateIndirectFunctions(mask + 1);
    2115         219 :       if (index == std::numeric_limits<uint32_t>::max()) {
    2116          10 :         FAILn("Exceeded maximum function table size");
    2117             :       }
    2118         209 :       function_info->kind = VarKind::kTable;
    2119         209 :       function_info->mask = mask;
    2120         209 :       function_info->index = index;
    2121         209 :       function_info->mutable_variable = false;
    2122             :     } else {
    2123        3905 :       if (function_info->kind != VarKind::kTable) {
    2124          12 :         FAILn("Expected call table");
    2125             :       }
    2126        3893 :       if (function_info->mask != mask) {
    2127           0 :         FAILn("Mask size mismatch");
    2128             :       }
    2129             :     }
    2130        4102 :     current_function_builder_->EmitI32Const(function_info->index);
    2131        4102 :     current_function_builder_->Emit(kExprI32Add);
    2132             :     // We have to use a temporary for the correct order of evaluation.
    2133             :     tmp.emplace(this);
    2134        4102 :     current_function_builder_->EmitSetLocal(tmp->get());
    2135             :     // The position of function table calls is after the table lookup.
    2136             :     call_pos = scanner_.Position();
    2137             :   } else {
    2138       43258 :     VarInfo* function_info = GetVarInfo(function_name);
    2139       43258 :     if (function_info->kind == VarKind::kUnused) {
    2140        2932 :       function_info->kind = VarKind::kFunction;
    2141        2932 :       function_info->function_builder = module_builder_->AddFunction();
    2142        2932 :       function_info->index = function_info->function_builder->func_index();
    2143        2932 :       function_info->mutable_variable = false;
    2144             :     } else {
    2145       40326 :       if (function_info->kind != VarKind::kFunction &&
    2146             :           function_info->kind < VarKind::kImportedFunction) {
    2147           4 :         FAILn("Expected function as call target");
    2148             :       }
    2149             :     }
    2150             :   }
    2151             : 
    2152             :   // Parse argument list and gather types.
    2153       47356 :   CachedVector<AsmType*> param_types(cached_asm_type_p_vectors_);
    2154       47356 :   CachedVector<AsmType*> param_specific_types(cached_asm_type_p_vectors_);
    2155       47356 :   EXPECT_TOKENn('(');
    2156      252060 :   while (!failed_ && !Peek(')')) {
    2157             :     AsmType* t;
    2158      102354 :     RECURSEn(t = AssignmentExpression());
    2159      102354 :     param_specific_types.push_back(t);
    2160      102354 :     if (t->IsA(AsmType::Int())) {
    2161      199298 :       param_types.push_back(AsmType::Int());
    2162        2705 :     } else if (t->IsA(AsmType::Float())) {
    2163         384 :       param_types.push_back(AsmType::Float());
    2164        2513 :     } else if (t->IsA(AsmType::Double())) {
    2165        5026 :       param_types.push_back(AsmType::Double());
    2166             :     } else {
    2167           0 :       FAILn("Bad function argument type");
    2168             :     }
    2169      102354 :     if (!Peek(')')) {
    2170       59430 :       EXPECT_TOKENn(',');
    2171             :     }
    2172             :   }
    2173       47352 :   EXPECT_TOKENn(')');
    2174             : 
    2175             :   // Reload {VarInfo} after parsing arguments as table might have grown.
    2176       47352 :   VarInfo* function_info = GetVarInfo(function_name);
    2177             : 
    2178             :   // We potentially use lookahead in order to determine the return type in case
    2179             :   // it is not yet clear from the call context. Special care has to be taken to
    2180             :   // ensure the non-contextual lookahead is valid. The following restrictions
    2181             :   // substantiate the validity of the lookahead implemented below:
    2182             :   //  - All calls (except stdlib calls) require some sort of type annotation.
    2183             :   //  - The coercion to "signed" is part of the {BitwiseORExpression}, any
    2184             :   //    intermittent expressions like parenthesis in `(callsite(..))|0` are
    2185             :   //    syntactically not considered coercions.
    2186             :   //  - The coercion to "double" as part of the {UnaryExpression} has higher
    2187             :   //    precedence and wins in `+callsite(..)|0` cases. Only "float" return
    2188             :   //    types are overridden in `fround(callsite(..)|0)` expressions.
    2189             :   //  - Expected coercions to "signed" are flagged via {call_coercion_deferred}
    2190             :   //    and later on validated as part of {BitwiseORExpression} to ensure they
    2191             :   //    indeed apply to the current call expression.
    2192             :   //  - The deferred validation is only allowed if {BitwiseORExpression} did
    2193             :   //    promise to fulfill the request via {call_coercion_deferred_position}.
    2194      115649 :   if (allow_peek && Peek('|') &&
    2195       91309 :       function_info->kind <= VarKind::kImportedFunction &&
    2196           4 :       (return_type == nullptr || return_type->IsA(AsmType::Float()))) {
    2197             :     DCHECK_NULL(call_coercion_deferred_);
    2198       21520 :     call_coercion_deferred_ = AsmType::Signed();
    2199             :     to_number_pos = scanner_.Position();
    2200             :     return_type = AsmType::Signed();
    2201       25832 :   } else if (return_type == nullptr) {
    2202             :     to_number_pos = call_pos;  // No conversion.
    2203             :     return_type = AsmType::Void();
    2204             :   }
    2205             : 
    2206             :   // Compute function type and signature based on gathered types.
    2207             :   AsmType* function_type = AsmType::Function(zone(), return_type);
    2208      149706 :   for (auto t : param_types) {
    2209             :     function_type->AsFunctionType()->AddArgument(t);
    2210             :   }
    2211       47352 :   FunctionSig* sig = ConvertSignature(return_type, param_types);
    2212       47352 :   uint32_t signature_index = module_builder_->AddSignature(sig);
    2213             : 
    2214             :   // Emit actual function invocation depending on the kind. At this point we
    2215             :   // also determined the complete function type and can perform checking against
    2216             :   // the expected type or update the expected type in case of first occurrence.
    2217       47352 :   if (function_info->kind == VarKind::kImportedFunction) {
    2218       15856 :     for (auto t : param_specific_types) {
    2219        7965 :       if (!t->IsA(AsmType::Extern())) {
    2220           0 :         FAILn("Imported function args must be type extern");
    2221             :       }
    2222             :     }
    2223        7891 :     if (return_type->IsA(AsmType::Float())) {
    2224           0 :       FAILn("Imported function can't be called as float");
    2225             :     }
    2226             :     DCHECK_NOT_NULL(function_info->import);
    2227             :     // TODO(bradnelson): Factor out.
    2228             :     uint32_t index;
    2229        7891 :     auto it = function_info->import->cache.find(*sig);
    2230        7891 :     if (it != function_info->import->cache.end()) {
    2231        7027 :       index = it->second;
    2232             :       DCHECK(function_info->function_defined);
    2233             :     } else {
    2234             :       index =
    2235         864 :           module_builder_->AddImport(function_info->import->function_name, sig);
    2236        1728 :       function_info->import->cache[*sig] = index;
    2237         864 :       function_info->function_defined = true;
    2238             :     }
    2239        7891 :     current_function_builder_->AddAsmWasmOffset(call_pos, to_number_pos);
    2240        7891 :     current_function_builder_->EmitWithU32V(kExprCallFunction, index);
    2241       39461 :   } else if (function_info->kind > VarKind::kImportedFunction) {
    2242        2083 :     AsmCallableType* callable = function_info->type->AsCallableType();
    2243        2083 :     if (!callable) {
    2244           0 :       FAILn("Expected callable function");
    2245             :     }
    2246             :     // TODO(bradnelson): Refactor AsmType to not need this.
    2247        2083 :     if (callable->CanBeInvokedWith(return_type, param_specific_types)) {
    2248             :       // Return type ok.
    2249        1091 :     } else if (callable->CanBeInvokedWith(AsmType::Float(),
    2250        1091 :                                           param_specific_types)) {
    2251             :       return_type = AsmType::Float();
    2252        1083 :     } else if (callable->CanBeInvokedWith(AsmType::Floatish(),
    2253        1083 :                                           param_specific_types)) {
    2254             :       return_type = AsmType::Floatish();
    2255         995 :     } else if (callable->CanBeInvokedWith(AsmType::Double(),
    2256         995 :                                           param_specific_types)) {
    2257             :       return_type = AsmType::Double();
    2258         995 :     } else if (callable->CanBeInvokedWith(AsmType::Signed(),
    2259         995 :                                           param_specific_types)) {
    2260             :       return_type = AsmType::Signed();
    2261          30 :     } else if (callable->CanBeInvokedWith(AsmType::Unsigned(),
    2262          30 :                                           param_specific_types)) {
    2263             :       return_type = AsmType::Unsigned();
    2264             :     } else {
    2265          18 :       FAILn("Function use doesn't match definition");
    2266             :     }
    2267        2065 :     switch (function_info->kind) {
    2268             : #define V(name, Name, op, sig)           \
    2269             :   case VarKind::kMath##Name:             \
    2270             :     current_function_builder_->Emit(op); \
    2271             :     break;
    2272          19 :       STDLIB_MATH_FUNCTION_MONOMORPHIC_LIST(V)
    2273             : #undef V
    2274             : #define V(name, Name, op, sig)                                    \
    2275             :   case VarKind::kMath##Name:                                      \
    2276             :     if (param_specific_types[0]->IsA(AsmType::DoubleQ())) {       \
    2277             :       current_function_builder_->Emit(kExprF64##Name);            \
    2278             :     } else if (param_specific_types[0]->IsA(AsmType::FloatQ())) { \
    2279             :       current_function_builder_->Emit(kExprF32##Name);            \
    2280             :     } else {                                                      \
    2281             :       UNREACHABLE();                                              \
    2282             :     }                                                             \
    2283             :     break;
    2284          62 :       STDLIB_MATH_FUNCTION_CEIL_LIKE_LIST(V)
    2285             : #undef V
    2286             :       case VarKind::kMathMin:
    2287             :       case VarKind::kMathMax:
    2288         108 :         if (param_specific_types[0]->IsA(AsmType::Double())) {
    2289         120 :           for (size_t i = 1; i < param_specific_types.size(); ++i) {
    2290          40 :             if (function_info->kind == VarKind::kMathMin) {
    2291          20 :               current_function_builder_->Emit(kExprF64Min);
    2292             :             } else {
    2293          20 :               current_function_builder_->Emit(kExprF64Max);
    2294             :             }
    2295             :           }
    2296          68 :         } else if (param_specific_types[0]->IsA(AsmType::Float())) {
    2297             :           // NOTE: Not technically part of the asm.js spec, but Firefox
    2298             :           // accepts it.
    2299         156 :           for (size_t i = 1; i < param_specific_types.size(); ++i) {
    2300          52 :             if (function_info->kind == VarKind::kMathMin) {
    2301          26 :               current_function_builder_->Emit(kExprF32Min);
    2302             :             } else {
    2303          26 :               current_function_builder_->Emit(kExprF32Max);
    2304             :             }
    2305             :           }
    2306          16 :         } else if (param_specific_types[0]->IsA(AsmType::Signed())) {
    2307             :           TemporaryVariableScope tmp_x(this);
    2308             :           TemporaryVariableScope tmp_y(this);
    2309          48 :           for (size_t i = 1; i < param_specific_types.size(); ++i) {
    2310          16 :             current_function_builder_->EmitSetLocal(tmp_x.get());
    2311          16 :             current_function_builder_->EmitTeeLocal(tmp_y.get());
    2312          16 :             current_function_builder_->EmitGetLocal(tmp_x.get());
    2313          16 :             if (function_info->kind == VarKind::kMathMin) {
    2314           8 :               current_function_builder_->Emit(kExprI32GeS);
    2315             :             } else {
    2316           8 :               current_function_builder_->Emit(kExprI32LeS);
    2317             :             }
    2318          16 :             current_function_builder_->EmitWithU8(kExprIf, kLocalI32);
    2319          16 :             current_function_builder_->EmitGetLocal(tmp_x.get());
    2320          16 :             current_function_builder_->Emit(kExprElse);
    2321          16 :             current_function_builder_->EmitGetLocal(tmp_y.get());
    2322          16 :             current_function_builder_->Emit(kExprEnd);
    2323             :           }
    2324             :         } else {
    2325           0 :           UNREACHABLE();
    2326             :         }
    2327             :         break;
    2328             : 
    2329             :       case VarKind::kMathAbs:
    2330         104 :         if (param_specific_types[0]->IsA(AsmType::Signed())) {
    2331             :           TemporaryVariableScope tmp(this);
    2332          12 :           current_function_builder_->EmitTeeLocal(tmp.get());
    2333          12 :           current_function_builder_->EmitGetLocal(tmp.get());
    2334          12 :           current_function_builder_->EmitI32Const(31);
    2335          12 :           current_function_builder_->Emit(kExprI32ShrS);
    2336          12 :           current_function_builder_->EmitTeeLocal(tmp.get());
    2337          12 :           current_function_builder_->Emit(kExprI32Xor);
    2338          12 :           current_function_builder_->EmitGetLocal(tmp.get());
    2339          12 :           current_function_builder_->Emit(kExprI32Sub);
    2340          92 :         } else if (param_specific_types[0]->IsA(AsmType::DoubleQ())) {
    2341          70 :           current_function_builder_->Emit(kExprF64Abs);
    2342          22 :         } else if (param_specific_types[0]->IsA(AsmType::FloatQ())) {
    2343          22 :           current_function_builder_->Emit(kExprF32Abs);
    2344             :         } else {
    2345           0 :           UNREACHABLE();
    2346             :         }
    2347             :         break;
    2348             : 
    2349             :       case VarKind::kMathFround:
    2350             :         // NOTE: Handled in {AsmJsParser::CallExpression} specially and treated
    2351             :         // as a coercion to "float" type. Cannot be reached as a call here.
    2352           0 :         UNREACHABLE();
    2353             : 
    2354             :       default:
    2355           0 :         UNREACHABLE();
    2356             :     }
    2357             :   } else {
    2358             :     DCHECK(function_info->kind == VarKind::kFunction ||
    2359             :            function_info->kind == VarKind::kTable);
    2360       37378 :     if (function_info->type->IsA(AsmType::None())) {
    2361        3204 :       function_info->type = function_type;
    2362             :     } else {
    2363       34174 :       AsmCallableType* callable = function_info->type->AsCallableType();
    2364       68348 :       if (!callable ||
    2365       34174 :           !callable->CanBeInvokedWith(return_type, param_specific_types)) {
    2366           8 :         FAILn("Function use doesn't match definition");
    2367             :       }
    2368             :     }
    2369       37370 :     if (function_info->kind == VarKind::kTable) {
    2370        4098 :       current_function_builder_->EmitGetLocal(tmp->get());
    2371        4098 :       current_function_builder_->AddAsmWasmOffset(call_pos, to_number_pos);
    2372        4098 :       current_function_builder_->Emit(kExprCallIndirect);
    2373        4098 :       current_function_builder_->EmitU32V(signature_index);
    2374        4098 :       current_function_builder_->EmitU32V(0);  // table index
    2375             :     } else {
    2376       33272 :       current_function_builder_->AddAsmWasmOffset(call_pos, to_number_pos);
    2377       33272 :       current_function_builder_->Emit(kExprCallFunction);
    2378       33272 :       current_function_builder_->EmitDirectCallIndex(function_info->index);
    2379             :     }
    2380             :   }
    2381             : 
    2382             :   return return_type;
    2383             : }
    2384             : 
    2385             : // 6.9 ValidateCall - helper
    2386     1269803 : bool AsmJsParser::PeekCall() {
    2387     1269803 :   if (!scanner_.IsGlobal()) {
    2388             :     return false;
    2389             :   }
    2390       66171 :   if (GetVarInfo(scanner_.Token())->kind == VarKind::kFunction) {
    2391             :     return true;
    2392             :   }
    2393       35815 :   if (GetVarInfo(scanner_.Token())->kind >= VarKind::kImportedFunction) {
    2394             :     return true;
    2395             :   }
    2396       48467 :   if (GetVarInfo(scanner_.Token())->kind == VarKind::kUnused ||
    2397       22630 :       GetVarInfo(scanner_.Token())->kind == VarKind::kTable) {
    2398        7104 :     scanner_.Next();
    2399        7104 :     if (Peek('(') || Peek('[')) {
    2400        7053 :       scanner_.Rewind();
    2401        7053 :       return true;
    2402             :     }
    2403          51 :     scanner_.Rewind();
    2404             :   }
    2405             :   return false;
    2406             : }
    2407             : 
    2408             : // 6.10 ValidateHeapAccess
    2409      169661 : void AsmJsParser::ValidateHeapAccess() {
    2410      169661 :   VarInfo* info = GetVarInfo(Consume());
    2411      169661 :   int32_t size = info->type->ElementSizeInBytes();
    2412      169661 :   EXPECT_TOKEN('[');
    2413             :   uint32_t offset;
    2414      169661 :   if (CheckForUnsigned(&offset)) {
    2415             :     // TODO(bradnelson): Check more things.
    2416             :     // TODO(mstarzinger): Clarify and explain where this limit is coming from,
    2417             :     // as it is not mandated by the spec directly.
    2418       17892 :     if (offset > 0x7FFFFFFF ||
    2419        8944 :         static_cast<uint64_t>(offset) * static_cast<uint64_t>(size) >
    2420             :             0x7FFFFFFF) {
    2421           4 :       FAIL("Heap access out of range");
    2422             :     }
    2423        8944 :     if (Check(']')) {
    2424        2129 :       current_function_builder_->EmitI32Const(
    2425        4258 :           static_cast<uint32_t>(offset * size));
    2426             :       // NOTE: This has to happen here to work recursively.
    2427        2129 :       heap_access_type_ = info->type;
    2428        2129 :       return;
    2429             :     } else {
    2430        6815 :       scanner_.Rewind();
    2431             :     }
    2432             :   }
    2433             :   AsmType* index_type;
    2434      322266 :   if (info->type->IsA(AsmType::Int8Array()) ||
    2435      154738 :       info->type->IsA(AsmType::Uint8Array())) {
    2436       17143 :     RECURSE(index_type = Expression(nullptr));
    2437             :   } else {
    2438      150385 :     RECURSE(index_type = ShiftExpression());
    2439      150385 :     if (heap_access_shift_position_ == kNoHeapAccessShift) {
    2440          16 :       FAIL("Expected shift of word size");
    2441             :     }
    2442      150369 :     if (heap_access_shift_value_ > 3) {
    2443           8 :       FAIL("Expected valid heap access shift");
    2444             :     }
    2445      150361 :     if ((1 << heap_access_shift_value_) != size) {
    2446           0 :       FAIL("Expected heap access shift to match heap view");
    2447             :     }
    2448             :     // Delete the code of the actual shift operation.
    2449      150361 :     current_function_builder_->DeleteCodeAfter(heap_access_shift_position_);
    2450             :     // Mask bottom bits to match asm.js behavior.
    2451      150361 :     current_function_builder_->EmitI32Const(~(size - 1));
    2452      150361 :     current_function_builder_->Emit(kExprI32And);
    2453             :   }
    2454      167504 :   if (!index_type->IsA(AsmType::Intish())) {
    2455           0 :     FAIL("Expected intish index");
    2456             :   }
    2457      167504 :   EXPECT_TOKEN(']');
    2458             :   // NOTE: This has to happen here to work recursively.
    2459      167504 :   heap_access_type_ = info->type;
    2460             : }
    2461             : 
    2462             : // 6.11 ValidateFloatCoercion
    2463         437 : void AsmJsParser::ValidateFloatCoercion() {
    2464         874 :   if (!scanner_.IsGlobal() ||
    2465         437 :       !GetVarInfo(scanner_.Token())->type->IsA(stdlib_fround_)) {
    2466           0 :     FAIL("Expected fround");
    2467             :   }
    2468         437 :   scanner_.Next();
    2469         437 :   EXPECT_TOKEN('(');
    2470         437 :   call_coercion_ = AsmType::Float();
    2471             :   // NOTE: The coercion position to float is not observable from JavaScript,
    2472             :   // because imported functions are not allowed to have float return type.
    2473         437 :   call_coercion_position_ = scanner_.Position();
    2474             :   AsmType* ret;
    2475         437 :   RECURSE(ret = ValidateExpression());
    2476         437 :   if (ret->IsA(AsmType::Floatish())) {
    2477             :     // Do nothing, as already a float.
    2478         108 :   } else if (ret->IsA(AsmType::DoubleQ())) {
    2479          84 :     current_function_builder_->Emit(kExprF32ConvertF64);
    2480          24 :   } else if (ret->IsA(AsmType::Signed())) {
    2481          16 :     current_function_builder_->Emit(kExprF32SConvertI32);
    2482           8 :   } else if (ret->IsA(AsmType::Unsigned())) {
    2483           8 :     current_function_builder_->Emit(kExprF32UConvertI32);
    2484             :   } else {
    2485           0 :     FAIL("Illegal conversion to float");
    2486             :   }
    2487         437 :   EXPECT_TOKEN(')');
    2488             : }
    2489             : 
    2490         125 : void AsmJsParser::ScanToClosingParenthesis() {
    2491             :   int depth = 0;
    2492         462 :   for (;;) {
    2493         587 :     if (Peek('(')) {
    2494          64 :       ++depth;
    2495         523 :     } else if (Peek(')')) {
    2496         189 :       --depth;
    2497         189 :       if (depth < 0) {
    2498             :         break;
    2499             :       }
    2500         334 :     } else if (Peek(AsmJsScanner::kEndOfInput)) {
    2501             :       break;
    2502             :     }
    2503         462 :     scanner_.Next();
    2504             :   }
    2505         125 : }
    2506             : 
    2507         612 : void AsmJsParser::GatherCases(ZoneVector<int32_t>* cases) {
    2508             :   size_t start = scanner_.Position();
    2509             :   int depth = 0;
    2510      464216 :   for (;;) {
    2511      464828 :     if (Peek('{')) {
    2512       12034 :       ++depth;
    2513      452794 :     } else if (Peek('}')) {
    2514       12026 :       --depth;
    2515       12026 :       if (depth <= 0) {
    2516             :         break;
    2517             :       }
    2518      440768 :     } else if (depth == 1 && Peek(TOK(case))) {
    2519       19994 :       scanner_.Next();
    2520             :       uint32_t uvalue;
    2521             :       bool negate = false;
    2522       19994 :       if (Check('-')) negate = true;
    2523       19994 :       if (!CheckForUnsigned(&uvalue)) {
    2524             :         break;
    2525             :       }
    2526       19990 :       int32_t value = static_cast<int32_t>(uvalue);
    2527             :       DCHECK_IMPLIES(negate && uvalue == 0x80000000, value == kMinInt);
    2528       19990 :       if (negate && value != kMinInt) {
    2529        4362 :         value = -value;
    2530             :       }
    2531       19990 :       cases->push_back(value);
    2532      420774 :     } else if (Peek(AsmJsScanner::kEndOfInput) ||
    2533             :                Peek(AsmJsScanner::kParseError)) {
    2534             :       break;
    2535             :     }
    2536      464216 :     scanner_.Next();
    2537             :   }
    2538         612 :   scanner_.Seek(start);
    2539         612 : }
    2540             : 
    2541             : }  // namespace wasm
    2542             : }  // namespace internal
    2543      120216 : }  // namespace v8
    2544             : 
    2545             : #undef RECURSE

Generated by: LCOV version 1.10