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