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