LCOV - code coverage report
Current view: top level - src/asmjs - asm-parser.cc (source / functions) Hit Total Coverage
Test: app.info Lines: 1209 1305 92.6 %
Date: 2017-10-20 Functions: 62 72 86.1 %

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

Generated by: LCOV version 1.10