LCOV - code coverage report
Current view: top level - src/asmjs - asm-parser.cc (source / functions) Hit Total Coverage
Test: app.info Lines: 1177 1279 92.0 %
Date: 2017-04-26 Functions: 62 73 84.9 %

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

Generated by: LCOV version 1.10