LCOV - code coverage report
Current view: top level - src/asmjs - asm-parser.cc (source / functions) Hit Total Coverage
Test: app.info Lines: 1205 1305 92.3 %
Date: 2019-04-18 Functions: 64 73 87.7 %

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

Generated by: LCOV version 1.10