LCOV - code coverage report
Current view: top level - src/asmjs - asm-parser.cc (source / functions) Hit Total Coverage
Test: app.info Lines: 1216 1315 92.5 %
Date: 2019-01-20 Functions: 64 74 86.5 %

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

Generated by: LCOV version 1.10