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