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