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