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