1 // Copyright 2016 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-typer.h"
6 
7 #include <algorithm>
8 #include <limits>
9 #include <memory>
10 #include <string>
11 
12 #include "src/v8.h"
13 
14 #include "src/asmjs/asm-types.h"
15 #include "src/ast/ast.h"
16 #include "src/ast/scopes.h"
17 #include "src/base/bits.h"
18 #include "src/codegen.h"
19 #include "src/globals.h"
20 #include "src/utils.h"
21 
22 #define FAIL(node, msg)                                        \
23   do {                                                         \
24     int line = node->position() == kNoSourcePosition           \
25                    ? -1                                        \
26                    : script_->GetLineNumber(node->position()); \
27     base::OS::SNPrintF(error_message_, sizeof(error_message_), \
28                        "asm: line %d: %s\n", line + 1, msg);   \
29     return AsmType::None();                                    \
30   } while (false)
31 
32 #define RECURSE(call)                                             \
33   do {                                                            \
34     if (GetCurrentStackPosition() < stack_limit_) {               \
35       stack_overflow_ = true;                                     \
36       FAIL(root_, "Stack overflow while parsing asm.js module."); \
37     }                                                             \
38                                                                   \
39     AsmType* result = (call);                                     \
40     if (stack_overflow_) {                                        \
41       return AsmType::None();                                     \
42     }                                                             \
43                                                                   \
44     if (result == AsmType::None()) {                              \
45       return AsmType::None();                                     \
46     }                                                             \
47   } while (false)
48 
49 namespace v8 {
50 namespace internal {
51 namespace wasm {
52 namespace {
53 static const uint32_t LargestFixNum = std::numeric_limits<int32_t>::max();
54 }  // namespace
55 
56 using v8::internal::AstNode;
57 using v8::internal::GetCurrentStackPosition;
58 
59 // ----------------------------------------------------------------------------
60 // Implementation of AsmTyper::FlattenedStatements
61 
FlattenedStatements(Zone * zone,ZoneList<Statement * > * s)62 AsmTyper::FlattenedStatements::FlattenedStatements(Zone* zone,
63                                                    ZoneList<Statement*>* s)
64     : context_stack_(zone) {
65   context_stack_.emplace_back(Context(s));
66 }
67 
Next()68 Statement* AsmTyper::FlattenedStatements::Next() {
69   for (;;) {
70     if (context_stack_.empty()) {
71       return nullptr;
72     }
73 
74     Context* current = &context_stack_.back();
75 
76     if (current->statements_->length() <= current->next_index_) {
77       context_stack_.pop_back();
78       continue;
79     }
80 
81     Statement* current_statement =
82         current->statements_->at(current->next_index_++);
83     if (current_statement->IsBlock()) {
84       context_stack_.emplace_back(
85           Context(current_statement->AsBlock()->statements()));
86       continue;
87     }
88 
89     return current_statement;
90   }
91 }
92 
93 // ----------------------------------------------------------------------------
94 // Implementation of AsmTyper::VariableInfo
95 
ForSpecialSymbol(Zone * zone,StandardMember standard_member)96 AsmTyper::VariableInfo* AsmTyper::VariableInfo::ForSpecialSymbol(
97     Zone* zone, StandardMember standard_member) {
98   DCHECK(standard_member == kStdlib || standard_member == kFFI ||
99          standard_member == kHeap || standard_member == kModule);
100   auto* new_var_info = new (zone) VariableInfo(AsmType::None());
101   new_var_info->standard_member_ = standard_member;
102   new_var_info->mutability_ = kImmutableGlobal;
103   return new_var_info;
104 }
105 
Clone(Zone * zone) const106 AsmTyper::VariableInfo* AsmTyper::VariableInfo::Clone(Zone* zone) const {
107   CHECK(standard_member_ != kNone);
108   CHECK(!type_->IsA(AsmType::None()));
109   auto* new_var_info = new (zone) VariableInfo(type_);
110   new_var_info->standard_member_ = standard_member_;
111   new_var_info->mutability_ = mutability_;
112   return new_var_info;
113 }
114 
FirstForwardUseIs(VariableProxy * var)115 void AsmTyper::VariableInfo::FirstForwardUseIs(VariableProxy* var) {
116   DCHECK(first_forward_use_ == nullptr);
117   missing_definition_ = true;
118   first_forward_use_ = var;
119 }
120 
121 // ----------------------------------------------------------------------------
122 // Implementation of AsmTyper
123 
AsmTyper(Isolate * isolate,Zone * zone,Script * script,FunctionLiteral * root)124 AsmTyper::AsmTyper(Isolate* isolate, Zone* zone, Script* script,
125                    FunctionLiteral* root)
126     : isolate_(isolate),
127       zone_(zone),
128       script_(script),
129       root_(root),
130       forward_definitions_(zone),
131       ffi_use_signatures_(zone),
132       stdlib_types_(zone),
133       stdlib_math_types_(zone),
134       module_info_(VariableInfo::ForSpecialSymbol(zone_, kModule)),
135       global_scope_(ZoneHashMap::kDefaultHashMapCapacity,
136                     ZoneAllocationPolicy(zone)),
137       local_scope_(ZoneHashMap::kDefaultHashMapCapacity,
138                    ZoneAllocationPolicy(zone)),
139       stack_limit_(isolate->stack_guard()->real_climit()),
140       node_types_(zone_),
141       fround_type_(AsmType::FroundType(zone_)),
142       ffi_type_(AsmType::FFIType(zone_)) {
143   InitializeStdlib();
144 }
145 
146 namespace {
ValidAsmIdentifier(Handle<String> name)147 bool ValidAsmIdentifier(Handle<String> name) {
148   static const char* kInvalidAsmNames[] = {"eval", "arguments"};
149 
150   for (size_t ii = 0; ii < arraysize(kInvalidAsmNames); ++ii) {
151     if (strcmp(name->ToCString().get(), kInvalidAsmNames[ii]) == 0) {
152       return false;
153     }
154   }
155   return true;
156 }
157 }  // namespace
158 
InitializeStdlib()159 void AsmTyper::InitializeStdlib() {
160   auto* d = AsmType::Double();
161   auto* dq = AsmType::DoubleQ();
162   auto* dq2d = AsmType::Function(zone_, d);
163   dq2d->AsFunctionType()->AddArgument(dq);
164 
165   auto* dqdq2d = AsmType::Function(zone_, d);
166   dqdq2d->AsFunctionType()->AddArgument(dq);
167   dqdq2d->AsFunctionType()->AddArgument(dq);
168 
169   auto* f = AsmType::Float();
170   auto* fq = AsmType::FloatQ();
171   auto* fq2f = AsmType::Function(zone_, f);
172   fq2f->AsFunctionType()->AddArgument(fq);
173 
174   auto* s = AsmType::Signed();
175   auto* s2s = AsmType::Function(zone_, s);
176   s2s->AsFunctionType()->AddArgument(s);
177 
178   auto* i = AsmType::Int();
179   auto* i2s = AsmType::Function(zone_, s);
180   i2s->AsFunctionType()->AddArgument(i);
181 
182   auto* ii2s = AsmType::Function(zone_, s);
183   ii2s->AsFunctionType()->AddArgument(i);
184   ii2s->AsFunctionType()->AddArgument(i);
185 
186   auto* minmax_d = AsmType::MinMaxType(zone_, d, d);
187   // *VIOLATION* The float variant is not part of the spec, but firefox accepts
188   // it.
189   auto* minmax_f = AsmType::MinMaxType(zone_, f, f);
190   auto* minmax_i = AsmType::MinMaxType(zone_, s, i);
191   auto* minmax = AsmType::OverloadedFunction(zone_);
192   minmax->AsOverloadedFunctionType()->AddOverload(minmax_i);
193   minmax->AsOverloadedFunctionType()->AddOverload(minmax_f);
194   minmax->AsOverloadedFunctionType()->AddOverload(minmax_d);
195 
196   auto* fround = fround_type_;
197 
198   auto* abs = AsmType::OverloadedFunction(zone_);
199   abs->AsOverloadedFunctionType()->AddOverload(s2s);
200   abs->AsOverloadedFunctionType()->AddOverload(dq2d);
201   abs->AsOverloadedFunctionType()->AddOverload(fq2f);
202 
203   auto* ceil = AsmType::OverloadedFunction(zone_);
204   ceil->AsOverloadedFunctionType()->AddOverload(dq2d);
205   ceil->AsOverloadedFunctionType()->AddOverload(fq2f);
206 
207   auto* floor = ceil;
208   auto* sqrt = ceil;
209 
210   struct StandardMemberInitializer {
211     const char* name;
212     StandardMember standard_member;
213     AsmType* type;
214   };
215 
216   const StandardMemberInitializer stdlib[] = {{"Infinity", kInfinity, d},
217                                               {"NaN", kNaN, d},
218 #define ASM_TYPED_ARRAYS(V) \
219   V(Uint8)                  \
220   V(Int8)                   \
221   V(Uint16)                 \
222   V(Int16)                  \
223   V(Uint32)                 \
224   V(Int32)                  \
225   V(Float32)                \
226   V(Float64)
227 
228 #define ASM_TYPED_ARRAY(TypeName) \
229   {#TypeName "Array", kNone, AsmType::TypeName##Array()},
230                                               ASM_TYPED_ARRAYS(ASM_TYPED_ARRAY)
231 #undef ASM_TYPED_ARRAY
232   };
233   for (size_t ii = 0; ii < arraysize(stdlib); ++ii) {
234     stdlib_types_[stdlib[ii].name] = new (zone_) VariableInfo(stdlib[ii].type);
235     stdlib_types_[stdlib[ii].name]->set_standard_member(
236         stdlib[ii].standard_member);
237     stdlib_types_[stdlib[ii].name]->set_mutability(
238         VariableInfo::kImmutableGlobal);
239   }
240 
241   const StandardMemberInitializer math[] = {
242       {"PI", kMathPI, d},
243       {"E", kMathE, d},
244       {"LN2", kMathLN2, d},
245       {"LN10", kMathLN10, d},
246       {"LOG2E", kMathLOG2E, d},
247       {"LOG10E", kMathLOG10E, d},
248       {"SQRT2", kMathSQRT2, d},
249       {"SQRT1_2", kMathSQRT1_2, d},
250       {"imul", kMathImul, ii2s},
251       {"abs", kMathAbs, abs},
252       // NOTE: clz32 should return fixnum. The current typer can only return
253       // Signed, Float, or Double, so it returns Signed in our version of
254       // asm.js.
255       {"clz32", kMathClz32, i2s},
256       {"ceil", kMathCeil, ceil},
257       {"floor", kMathFloor, floor},
258       {"fround", kMathFround, fround},
259       {"pow", kMathPow, dqdq2d},
260       {"exp", kMathExp, dq2d},
261       {"log", kMathLog, dq2d},
262       {"min", kMathMin, minmax},
263       {"max", kMathMax, minmax},
264       {"sqrt", kMathSqrt, sqrt},
265       {"cos", kMathCos, dq2d},
266       {"sin", kMathSin, dq2d},
267       {"tan", kMathTan, dq2d},
268       {"acos", kMathAcos, dq2d},
269       {"asin", kMathAsin, dq2d},
270       {"atan", kMathAtan, dq2d},
271       {"atan2", kMathAtan2, dqdq2d},
272   };
273   for (size_t ii = 0; ii < arraysize(math); ++ii) {
274     stdlib_math_types_[math[ii].name] = new (zone_) VariableInfo(math[ii].type);
275     stdlib_math_types_[math[ii].name]->set_standard_member(
276         math[ii].standard_member);
277     stdlib_math_types_[math[ii].name]->set_mutability(
278         VariableInfo::kImmutableGlobal);
279   }
280 }
281 
282 // Used for 5.5 GlobalVariableTypeAnnotations
ImportLookup(Property * import)283 AsmTyper::VariableInfo* AsmTyper::ImportLookup(Property* import) {
284   auto* obj = import->obj();
285   auto* key = import->key()->AsLiteral();
286 
287   ObjectTypeMap* stdlib = &stdlib_types_;
288   if (auto* obj_as_property = obj->AsProperty()) {
289     // This can only be stdlib.Math
290     auto* math_name = obj_as_property->key()->AsLiteral();
291     if (math_name == nullptr || !math_name->IsPropertyName()) {
292       return nullptr;
293     }
294 
295     if (!math_name->AsPropertyName()->IsUtf8EqualTo(CStrVector("Math"))) {
296       return nullptr;
297     }
298 
299     auto* stdlib_var_proxy = obj_as_property->obj()->AsVariableProxy();
300     if (stdlib_var_proxy == nullptr) {
301       return nullptr;
302     }
303     obj = stdlib_var_proxy;
304     stdlib = &stdlib_math_types_;
305   }
306 
307   auto* obj_as_var_proxy = obj->AsVariableProxy();
308   if (obj_as_var_proxy == nullptr) {
309     return nullptr;
310   }
311 
312   auto* obj_info = Lookup(obj_as_var_proxy->var());
313   if (obj_info == nullptr) {
314     return nullptr;
315   }
316 
317   if (obj_info->IsFFI()) {
318     // For FFI we can't validate import->key, so assume this is OK.
319     return obj_info;
320   }
321 
322   std::unique_ptr<char[]> aname = key->AsPropertyName()->ToCString();
323   ObjectTypeMap::iterator i = stdlib->find(std::string(aname.get()));
324   if (i == stdlib->end()) {
325     return nullptr;
326   }
327   stdlib_uses_.insert(i->second->standard_member());
328   return i->second;
329 }
330 
Lookup(Variable * variable) const331 AsmTyper::VariableInfo* AsmTyper::Lookup(Variable* variable) const {
332   const ZoneHashMap* scope = in_function_ ? &local_scope_ : &global_scope_;
333   ZoneHashMap::Entry* entry =
334       scope->Lookup(variable, ComputePointerHash(variable));
335   if (entry == nullptr && in_function_) {
336     entry = global_scope_.Lookup(variable, ComputePointerHash(variable));
337   }
338 
339   if (entry == nullptr && !module_name_.is_null() &&
340       module_name_->Equals(*variable->name())) {
341     return module_info_;
342   }
343 
344   return entry ? reinterpret_cast<VariableInfo*>(entry->value) : nullptr;
345 }
346 
AddForwardReference(VariableProxy * proxy,VariableInfo * info)347 void AsmTyper::AddForwardReference(VariableProxy* proxy, VariableInfo* info) {
348   info->FirstForwardUseIs(proxy);
349   forward_definitions_.push_back(info);
350 }
351 
AddGlobal(Variable * variable,VariableInfo * info)352 bool AsmTyper::AddGlobal(Variable* variable, VariableInfo* info) {
353   // We can't DCHECK(!in_function_) because function may actually install global
354   // names (forward defined functions and function tables.)
355   DCHECK(info->mutability() != VariableInfo::kInvalidMutability);
356   DCHECK(info->IsGlobal());
357   DCHECK(ValidAsmIdentifier(variable->name()));
358 
359   if (!module_name_.is_null() && module_name_->Equals(*variable->name())) {
360     return false;
361   }
362 
363   ZoneHashMap::Entry* entry = global_scope_.LookupOrInsert(
364       variable, ComputePointerHash(variable), ZoneAllocationPolicy(zone_));
365 
366   if (entry->value != nullptr) {
367     return false;
368   }
369 
370   entry->value = info;
371   return true;
372 }
373 
AddLocal(Variable * variable,VariableInfo * info)374 bool AsmTyper::AddLocal(Variable* variable, VariableInfo* info) {
375   DCHECK(in_function_);
376   DCHECK(info->mutability() != VariableInfo::kInvalidMutability);
377   DCHECK(!info->IsGlobal());
378   DCHECK(ValidAsmIdentifier(variable->name()));
379 
380   ZoneHashMap::Entry* entry = local_scope_.LookupOrInsert(
381       variable, ComputePointerHash(variable), ZoneAllocationPolicy(zone_));
382 
383   if (entry->value != nullptr) {
384     return false;
385   }
386 
387   entry->value = info;
388   return true;
389 }
390 
SetTypeOf(AstNode * node,AsmType * type)391 void AsmTyper::SetTypeOf(AstNode* node, AsmType* type) {
392   DCHECK_NE(type, AsmType::None());
393   DCHECK(node_types_.find(node) == node_types_.end());
394   node_types_.insert(std::make_pair(node, type));
395 }
396 
TypeOf(AstNode * node) const397 AsmType* AsmTyper::TypeOf(AstNode* node) const {
398   auto node_type_iter = node_types_.find(node);
399   if (node_type_iter != node_types_.end()) {
400     return node_type_iter->second;
401   }
402 
403   // Sometimes literal nodes are not added to the node_type_ map simply because
404   // their are not visited with ValidateExpression().
405   if (auto* literal = node->AsLiteral()) {
406     if (literal->raw_value()->ContainsDot()) {
407       return AsmType::Double();
408     }
409     uint32_t u;
410     if (literal->value()->ToUint32(&u)) {
411       if (u > LargestFixNum) {
412         return AsmType::Unsigned();
413       }
414       return AsmType::FixNum();
415     }
416     int32_t i;
417     if (literal->value()->ToInt32(&i)) {
418       return AsmType::Signed();
419     }
420   }
421 
422   return AsmType::None();
423 }
424 
TypeOf(Variable * v) const425 AsmType* AsmTyper::TypeOf(Variable* v) const { return Lookup(v)->type(); }
426 
VariableAsStandardMember(Variable * var)427 AsmTyper::StandardMember AsmTyper::VariableAsStandardMember(Variable* var) {
428   auto* var_info = Lookup(var);
429   if (var_info == nullptr) {
430     return kNone;
431   }
432   StandardMember member = var_info->standard_member();
433   return member;
434 }
435 
Validate()436 bool AsmTyper::Validate() {
437   if (!AsmType::None()->IsExactly(ValidateModule(root_))) {
438     return true;
439   }
440   return false;
441 }
442 
443 namespace {
IsUseAsmDirective(Statement * first_statement)444 bool IsUseAsmDirective(Statement* first_statement) {
445   ExpressionStatement* use_asm = first_statement->AsExpressionStatement();
446   if (use_asm == nullptr) {
447     return false;
448   }
449 
450   Literal* use_asm_literal = use_asm->expression()->AsLiteral();
451 
452   if (use_asm_literal == nullptr) {
453     return false;
454   }
455 
456   return use_asm_literal->raw_value()->AsString()->IsOneByteEqualTo("use asm");
457 }
458 
ExtractInitializerExpression(Statement * statement)459 Assignment* ExtractInitializerExpression(Statement* statement) {
460   auto* expr_stmt = statement->AsExpressionStatement();
461   if (expr_stmt == nullptr) {
462     // Done with initializers.
463     return nullptr;
464   }
465   auto* assign = expr_stmt->expression()->AsAssignment();
466   if (assign == nullptr) {
467     // Done with initializers.
468     return nullptr;
469   }
470   if (assign->op() != Token::INIT) {
471     // Done with initializers.
472     return nullptr;
473   }
474   return assign;
475 }
476 
477 }  // namespace
478 
479 // 6.1 ValidateModule
480 namespace {
481 // SourceLayoutTracker keeps track of the start and end positions of each
482 // section in the asm.js source. The sections should not overlap, otherwise the
483 // asm.js source is invalid.
484 class SourceLayoutTracker {
485  public:
486   SourceLayoutTracker() = default;
487 
IsValid() const488   bool IsValid() const {
489     const Section* kAllSections[] = {&use_asm_, &globals_, &functions_,
490                                      &tables_, &exports_};
491     for (size_t ii = 0; ii < arraysize(kAllSections); ++ii) {
492       const auto& curr_section = *kAllSections[ii];
493       for (size_t jj = ii + 1; jj < arraysize(kAllSections); ++jj) {
494         if (curr_section.OverlapsWith(*kAllSections[jj])) {
495           return false;
496         }
497       }
498     }
499     return true;
500   }
501 
AddUseAsm(const AstNode & node)502   void AddUseAsm(const AstNode& node) { use_asm_.AddNewElement(node); }
503 
AddGlobal(const AstNode & node)504   void AddGlobal(const AstNode& node) { globals_.AddNewElement(node); }
505 
AddFunction(const AstNode & node)506   void AddFunction(const AstNode& node) { functions_.AddNewElement(node); }
507 
AddTable(const AstNode & node)508   void AddTable(const AstNode& node) { tables_.AddNewElement(node); }
509 
AddExport(const AstNode & node)510   void AddExport(const AstNode& node) { exports_.AddNewElement(node); }
511 
512  private:
513   class Section {
514    public:
515     Section() = default;
516     Section(const Section&) = default;
517     Section& operator=(const Section&) = default;
518 
AddNewElement(const AstNode & node)519     void AddNewElement(const AstNode& node) {
520       const int node_pos = node.position();
521       if (start_ == kNoSourcePosition) {
522         start_ = node_pos;
523       } else {
524         start_ = std::max(start_, node_pos);
525       }
526       if (end_ == kNoSourcePosition) {
527         end_ = node_pos;
528       } else {
529         end_ = std::max(end_, node_pos);
530       }
531     }
532 
OverlapsWith(const Section & other) const533     bool OverlapsWith(const Section& other) const {
534       if (start_ == kNoSourcePosition) {
535         DCHECK_EQ(end_, kNoSourcePosition);
536         return false;
537       }
538       if (other.start_ == kNoSourcePosition) {
539         DCHECK_EQ(other.end_, kNoSourcePosition);
540         return false;
541       }
542       return other.start_ < end_ || other.end_ < start_;
543     }
544 
545    private:
546     int start_ = kNoSourcePosition;
547     int end_ = kNoSourcePosition;
548   };
549 
550   Section use_asm_;
551   Section globals_;
552   Section functions_;
553   Section tables_;
554   Section exports_;
555 
556   DISALLOW_COPY_AND_ASSIGN(SourceLayoutTracker);
557 };
558 }  // namespace
559 
ValidateModule(FunctionLiteral * fun)560 AsmType* AsmTyper::ValidateModule(FunctionLiteral* fun) {
561   SourceLayoutTracker source_layout;
562 
563   DeclarationScope* scope = fun->scope();
564   if (!scope->is_function_scope()) FAIL(fun, "Not at function scope.");
565   if (!ValidAsmIdentifier(fun->name()))
566     FAIL(fun, "Invalid asm.js identifier in module name.");
567   module_name_ = fun->name();
568 
569   // Allowed parameters: Stdlib, FFI, Mem
570   static const int MaxModuleParameters = 3;
571   if (scope->num_parameters() > MaxModuleParameters) {
572     FAIL(fun, "asm.js modules may not have more than three parameters.");
573   }
574 
575   struct {
576     StandardMember standard_member;
577   } kModuleParamInfo[3] = {
578       {kStdlib}, {kFFI}, {kHeap},
579   };
580 
581   for (int ii = 0; ii < scope->num_parameters(); ++ii) {
582     Variable* param = scope->parameter(ii);
583     DCHECK(param);
584 
585     if (!ValidAsmIdentifier(param->name())) {
586       FAIL(fun, "Invalid asm.js identifier in module parameter.");
587     }
588 
589     auto* param_info = VariableInfo::ForSpecialSymbol(
590         zone_, kModuleParamInfo[ii].standard_member);
591 
592     if (!AddGlobal(param, param_info)) {
593       FAIL(fun, "Redeclared identifier in module parameter.");
594     }
595   }
596 
597   ZoneVector<Assignment*> function_pointer_tables(zone_);
598   FlattenedStatements iter(zone_, fun->body());
599   auto* use_asm_directive = iter.Next();
600   if (use_asm_directive == nullptr) {
601     FAIL(fun, "Missing \"use asm\".");
602   }
603   // Check for extra assignment inserted by the parser when in this form:
604   // (function Module(a, b, c) {... })
605   ExpressionStatement* estatement = use_asm_directive->AsExpressionStatement();
606   if (estatement != nullptr) {
607     Assignment* assignment = estatement->expression()->AsAssignment();
608     if (assignment != nullptr && assignment->target()->IsVariableProxy() &&
609         assignment->target()
610             ->AsVariableProxy()
611             ->var()
612             ->is_sloppy_function_name()) {
613       use_asm_directive = iter.Next();
614     }
615   }
616   if (!IsUseAsmDirective(use_asm_directive)) {
617     FAIL(fun, "Missing \"use asm\".");
618   }
619   source_layout.AddUseAsm(*use_asm_directive);
620   ReturnStatement* module_return = nullptr;
621 
622   // *VIOLATION* The spec states that globals should be followed by function
623   // declarations, which should be followed by function pointer tables, followed
624   // by the module export (return) statement. Our AST might be rearraged by the
625   // parser, so we can't rely on it being in source code order.
626   while (Statement* current = iter.Next()) {
627     if (auto* assign = ExtractInitializerExpression(current)) {
628       if (assign->value()->IsArrayLiteral()) {
629         // Save function tables for later validation.
630         function_pointer_tables.push_back(assign);
631       } else {
632         RECURSE(ValidateGlobalDeclaration(assign));
633         source_layout.AddGlobal(*assign);
634       }
635       continue;
636     }
637 
638     if (auto* current_as_return = current->AsReturnStatement()) {
639       if (module_return != nullptr) {
640         FAIL(fun, "Multiple export statements.");
641       }
642       module_return = current_as_return;
643       source_layout.AddExport(*module_return);
644       continue;
645     }
646 
647     FAIL(current, "Invalid top-level statement in asm.js module.");
648   }
649 
650   Declaration::List* decls = scope->declarations();
651   for (Declaration* decl : *decls) {
652     if (FunctionDeclaration* fun_decl = decl->AsFunctionDeclaration()) {
653       RECURSE(ValidateFunction(fun_decl));
654       source_layout.AddFunction(*fun_decl);
655       continue;
656     }
657   }
658 
659   for (auto* function_table : function_pointer_tables) {
660     RECURSE(ValidateFunctionTable(function_table));
661     source_layout.AddTable(*function_table);
662   }
663 
664   for (Declaration* decl : *decls) {
665     if (decl->IsFunctionDeclaration()) {
666       continue;
667     }
668 
669     VariableDeclaration* var_decl = decl->AsVariableDeclaration();
670     if (var_decl == nullptr) {
671       FAIL(decl, "Invalid asm.js declaration.");
672     }
673 
674     auto* var_proxy = var_decl->proxy();
675     if (var_proxy == nullptr) {
676       FAIL(decl, "Invalid asm.js declaration.");
677     }
678 
679     if (Lookup(var_proxy->var()) == nullptr) {
680       FAIL(decl, "Global variable missing initializer in asm.js module.");
681     }
682   }
683 
684   // 6.2 ValidateExport
685   if (module_return == nullptr) {
686     FAIL(fun, "Missing asm.js module export.");
687   }
688 
689   for (auto* forward_def : forward_definitions_) {
690     if (forward_def->missing_definition()) {
691       FAIL(forward_def->first_forward_use(),
692            "Missing definition for forward declared identifier.");
693     }
694   }
695 
696   RECURSE(ValidateExport(module_return));
697 
698   if (!source_layout.IsValid()) {
699     FAIL(fun, "Invalid asm.js source code layout.");
700   }
701 
702   return AsmType::Int();  // Any type that is not AsmType::None();
703 }
704 
705 namespace {
IsDoubleAnnotation(BinaryOperation * binop)706 bool IsDoubleAnnotation(BinaryOperation* binop) {
707   // *VIOLATION* The parser replaces uses of +x with x*1.0.
708   if (binop->op() != Token::MUL) {
709     return false;
710   }
711 
712   auto* right_as_literal = binop->right()->AsLiteral();
713   if (right_as_literal == nullptr) {
714     return false;
715   }
716 
717   return right_as_literal->raw_value()->ContainsDot() &&
718          right_as_literal->raw_value()->AsNumber() == 1.0;
719 }
720 
IsIntAnnotation(BinaryOperation * binop)721 bool IsIntAnnotation(BinaryOperation* binop) {
722   if (binop->op() != Token::BIT_OR) {
723     return false;
724   }
725 
726   auto* right_as_literal = binop->right()->AsLiteral();
727   if (right_as_literal == nullptr) {
728     return false;
729   }
730 
731   return !right_as_literal->raw_value()->ContainsDot() &&
732          right_as_literal->raw_value()->AsNumber() == 0.0;
733 }
734 }  // namespace
735 
ValidateGlobalDeclaration(Assignment * assign)736 AsmType* AsmTyper::ValidateGlobalDeclaration(Assignment* assign) {
737   DCHECK(!assign->is_compound());
738   if (assign->is_compound()) {
739     FAIL(assign,
740          "Compound assignment not supported when declaring global variables.");
741   }
742 
743   auto* target = assign->target();
744   if (!target->IsVariableProxy()) {
745     FAIL(target, "Module assignments may only assign to globals.");
746   }
747   auto* target_variable = target->AsVariableProxy()->var();
748   auto* target_info = Lookup(target_variable);
749 
750   if (target_info != nullptr) {
751     FAIL(target, "Redefined global variable.");
752   }
753 
754   auto* value = assign->value();
755   // Not all types of assignment are allowed by asm.js. See
756   // 5.5 Global Variable Type Annotations.
757   bool global_variable = false;
758   if (value->IsLiteral() || value->IsCall()) {
759     AsmType* type = nullptr;
760     VariableInfo::Mutability mutability;
761     if (target_variable->mode() == CONST) {
762       mutability = VariableInfo::kConstGlobal;
763     } else {
764       mutability = VariableInfo::kMutableGlobal;
765     }
766     RECURSE(type = VariableTypeAnnotations(value, mutability));
767     target_info = new (zone_) VariableInfo(type);
768     target_info->set_mutability(mutability);
769     global_variable = true;
770   } else if (value->IsProperty()) {
771     target_info = ImportLookup(value->AsProperty());
772     if (target_info == nullptr) {
773       FAIL(assign, "Invalid import.");
774     }
775     CHECK(target_info->mutability() == VariableInfo::kImmutableGlobal);
776     if (target_info->IsFFI()) {
777       // create a new target info that represents a foreign variable.
778       target_info = new (zone_) VariableInfo(ffi_type_);
779       target_info->set_mutability(VariableInfo::kImmutableGlobal);
780     } else if (target_info->type()->IsA(AsmType::Heap())) {
781       FAIL(assign, "Heap view types can not be aliased.");
782     } else {
783       target_info = target_info->Clone(zone_);
784     }
785   } else if (value->IsBinaryOperation()) {
786     // This should either be:
787     //
788     // var <> = ffi.<>|0
789     //
790     // or
791     //
792     // var <> = +ffi.<>
793     auto* value_binop = value->AsBinaryOperation();
794     auto* left = value_binop->left();
795     AsmType* import_type = nullptr;
796 
797     if (IsDoubleAnnotation(value_binop)) {
798       import_type = AsmType::Double();
799     } else if (IsIntAnnotation(value_binop)) {
800       import_type = AsmType::Int();
801     } else {
802       FAIL(value,
803            "Invalid initializer for foreign import - unrecognized annotation.");
804     }
805 
806     if (!left->IsProperty()) {
807       FAIL(value,
808            "Invalid initializer for foreign import - must import member.");
809     }
810     target_info = ImportLookup(left->AsProperty());
811     if (target_info == nullptr) {
812       // TODO(jpp): this error message is innacurate: this may fail if the
813       // object lookup fails, or if the property lookup fails, or even if the
814       // import is bogus like a().c.
815       FAIL(value,
816            "Invalid initializer for foreign import - object lookup failed.");
817     }
818     CHECK(target_info->mutability() == VariableInfo::kImmutableGlobal);
819     if (!target_info->IsFFI()) {
820       FAIL(value,
821            "Invalid initializer for foreign import - object is not the ffi.");
822     }
823 
824     // Create a new target info that represents the foreign import.
825     target_info = new (zone_) VariableInfo(import_type);
826     target_info->set_mutability(VariableInfo::kMutableGlobal);
827   } else if (value->IsCallNew()) {
828     AsmType* type = nullptr;
829     RECURSE(type = NewHeapView(value->AsCallNew()));
830     target_info = new (zone_) VariableInfo(type);
831     target_info->set_mutability(VariableInfo::kImmutableGlobal);
832   } else if (auto* proxy = value->AsVariableProxy()) {
833     auto* var_info = Lookup(proxy->var());
834 
835     if (var_info == nullptr) {
836       FAIL(value, "Undeclared identifier in global initializer");
837     }
838 
839     if (var_info->mutability() != VariableInfo::kConstGlobal) {
840       FAIL(value, "Identifier used to initialize a global must be a const");
841     }
842 
843     target_info = new (zone_) VariableInfo(var_info->type());
844     if (target_variable->mode() == CONST) {
845       target_info->set_mutability(VariableInfo::kConstGlobal);
846     } else {
847       target_info->set_mutability(VariableInfo::kMutableGlobal);
848     }
849   }
850 
851   if (target_info == nullptr) {
852     FAIL(assign, "Invalid global variable initializer.");
853   }
854 
855   if (!ValidAsmIdentifier(target_variable->name())) {
856     FAIL(target, "Invalid asm.js identifier in global variable.");
857   }
858 
859   if (!AddGlobal(target_variable, target_info)) {
860     FAIL(assign, "Redeclared global identifier.");
861   }
862 
863   DCHECK(target_info->type() != AsmType::None());
864   if (!global_variable) {
865     // Global variables have their types set in VariableTypeAnnotations.
866     SetTypeOf(value, target_info->type());
867   }
868   SetTypeOf(assign, target_info->type());
869   SetTypeOf(target, target_info->type());
870   return target_info->type();
871 }
872 
873 // 6.2 ValidateExport
ExportType(VariableProxy * fun_export)874 AsmType* AsmTyper::ExportType(VariableProxy* fun_export) {
875   auto* fun_info = Lookup(fun_export->var());
876   if (fun_info == nullptr) {
877     FAIL(fun_export, "Undefined identifier in asm.js module export.");
878   }
879 
880   if (fun_info->standard_member() != kNone) {
881     FAIL(fun_export, "Module cannot export standard library functions.");
882   }
883 
884   auto* type = fun_info->type();
885   if (type->AsFFIType() != nullptr) {
886     FAIL(fun_export, "Module cannot export foreign functions.");
887   }
888 
889   if (type->AsFunctionTableType() != nullptr) {
890     FAIL(fun_export, "Module cannot export function tables.");
891   }
892 
893   if (fun_info->type()->AsFunctionType() == nullptr) {
894     FAIL(fun_export, "Module export is not an asm.js function.");
895   }
896 
897   return type;
898 }
899 
ValidateExport(ReturnStatement * exports)900 AsmType* AsmTyper::ValidateExport(ReturnStatement* exports) {
901   // asm.js modules can export single functions, or multiple functions in an
902   // object literal.
903   if (auto* fun_export = exports->expression()->AsVariableProxy()) {
904     // Exporting single function.
905     AsmType* export_type;
906     RECURSE(export_type = ExportType(fun_export));
907     return export_type;
908   }
909 
910   if (auto* obj_export = exports->expression()->AsObjectLiteral()) {
911     // Exporting object literal.
912     for (auto* prop : *obj_export->properties()) {
913       if (!prop->key()->IsLiteral()) {
914         FAIL(prop->key(),
915              "Only normal object properties may be used in the export object "
916              "literal.");
917       }
918 
919       auto* export_obj = prop->value()->AsVariableProxy();
920       if (export_obj == nullptr) {
921         FAIL(prop->value(), "Exported value must be an asm.js function name.");
922       }
923 
924       RECURSE(ExportType(export_obj));
925     }
926 
927     return AsmType::Int();
928   }
929 
930   FAIL(exports, "Unrecognized expression in asm.js module export expression.");
931 }
932 
933 // 6.3 ValidateFunctionTable
ValidateFunctionTable(Assignment * assign)934 AsmType* AsmTyper::ValidateFunctionTable(Assignment* assign) {
935   if (assign->is_compound()) {
936     FAIL(assign,
937          "Compound assignment not supported when declaring global variables.");
938   }
939 
940   auto* target = assign->target();
941   if (!target->IsVariableProxy()) {
942     FAIL(target, "Module assignments may only assign to globals.");
943   }
944   auto* target_variable = target->AsVariableProxy()->var();
945 
946   auto* value = assign->value()->AsArrayLiteral();
947   CHECK(value != nullptr);
948   ZoneList<Expression*>* pointers = value->values();
949 
950   // The function table size must be n = 2 ** m, for m >= 0;
951   // TODO(jpp): should this be capped?
952   if (!base::bits::IsPowerOfTwo32(pointers->length())) {
953     FAIL(assign, "Invalid length for function pointer table.");
954   }
955 
956   AsmType* table_element_type = nullptr;
957   for (auto* initializer : *pointers) {
958     auto* var_proxy = initializer->AsVariableProxy();
959     if (var_proxy == nullptr) {
960       FAIL(initializer,
961            "Function pointer table initializer must be a function name.");
962     }
963 
964     auto* var_info = Lookup(var_proxy->var());
965     if (var_info == nullptr) {
966       FAIL(var_proxy,
967            "Undefined identifier in function pointer table initializer.");
968     }
969 
970     if (var_info->standard_member() != kNone) {
971       FAIL(initializer,
972            "Function pointer table must not be a member of the standard "
973            "library.");
974     }
975 
976     auto* initializer_type = var_info->type();
977     if (initializer_type->AsFunctionType() == nullptr) {
978       FAIL(initializer,
979            "Function pointer table initializer must be an asm.js function.");
980     }
981 
982     DCHECK(var_info->type()->AsFFIType() == nullptr);
983     DCHECK(var_info->type()->AsFunctionTableType() == nullptr);
984 
985     if (table_element_type == nullptr) {
986       table_element_type = initializer_type;
987     } else if (!initializer_type->IsA(table_element_type)) {
988       FAIL(initializer, "Type mismatch in function pointer table initializer.");
989     }
990   }
991 
992   auto* target_info = Lookup(target_variable);
993   if (target_info == nullptr) {
994     // Function pointer tables are the last entities to be validates, so this is
995     // unlikely to happen: only unreferenced function tables will not already
996     // have an entry in the global scope.
997     target_info = new (zone_) VariableInfo(AsmType::FunctionTableType(
998         zone_, pointers->length(), table_element_type));
999     target_info->set_mutability(VariableInfo::kImmutableGlobal);
1000     if (!ValidAsmIdentifier(target_variable->name())) {
1001       FAIL(target, "Invalid asm.js identifier in function table name.");
1002     }
1003     if (!AddGlobal(target_variable, target_info)) {
1004       DCHECK(false);
1005       FAIL(assign, "Redeclared global identifier in function table name.");
1006     }
1007     SetTypeOf(value, target_info->type());
1008     return target_info->type();
1009   }
1010 
1011   auto* target_info_table = target_info->type()->AsFunctionTableType();
1012   if (target_info_table == nullptr) {
1013     FAIL(assign, "Identifier redefined as function pointer table.");
1014   }
1015 
1016   if (!target_info->missing_definition()) {
1017     FAIL(assign, "Identifier redefined (function table name).");
1018   }
1019 
1020   if (static_cast<int>(target_info_table->length()) != pointers->length()) {
1021     FAIL(assign, "Function table size mismatch.");
1022   }
1023 
1024   DCHECK(target_info_table->signature()->AsFunctionType());
1025   if (!table_element_type->IsA(target_info_table->signature())) {
1026     FAIL(assign, "Function table initializer does not match previous type.");
1027   }
1028 
1029   target_info->MarkDefined();
1030   DCHECK(target_info->type() != AsmType::None());
1031   SetTypeOf(value, target_info->type());
1032 
1033   return target_info->type();
1034 }
1035 
1036 // 6.4 ValidateFunction
ValidateFunction(FunctionDeclaration * fun_decl)1037 AsmType* AsmTyper::ValidateFunction(FunctionDeclaration* fun_decl) {
1038   FunctionScope _(this);
1039 
1040   // Extract parameter types.
1041   auto* fun = fun_decl->fun();
1042 
1043   auto* fun_decl_proxy = fun_decl->proxy();
1044   if (fun_decl_proxy == nullptr) {
1045     FAIL(fun_decl, "Anonymous functions are not support in asm.js.");
1046   }
1047 
1048   Statement* current;
1049   FlattenedStatements iter(zone_, fun->body());
1050 
1051   size_t annotated_parameters = 0;
1052 
1053   // 5.3 Function type annotations
1054   //     * parameters
1055   ZoneVector<AsmType*> parameter_types(zone_);
1056   for (; (current = iter.Next()) != nullptr; ++annotated_parameters) {
1057     auto* stmt = current->AsExpressionStatement();
1058     if (stmt == nullptr) {
1059       // Done with parameters.
1060       break;
1061     }
1062     auto* expr = stmt->expression()->AsAssignment();
1063     if (expr == nullptr || expr->is_compound()) {
1064       // Done with parameters.
1065       break;
1066     }
1067     auto* proxy = expr->target()->AsVariableProxy();
1068     if (proxy == nullptr) {
1069       // Done with parameters.
1070       break;
1071     }
1072     auto* param = proxy->var();
1073     if (param->location() != VariableLocation::PARAMETER ||
1074         param->index() != static_cast<int>(annotated_parameters)) {
1075       // Done with parameters.
1076       break;
1077     }
1078 
1079     AsmType* type;
1080     RECURSE(type = ParameterTypeAnnotations(param, expr->value()));
1081     DCHECK(type->IsParameterType());
1082     auto* param_info = new (zone_) VariableInfo(type);
1083     param_info->set_mutability(VariableInfo::kLocal);
1084     if (!ValidAsmIdentifier(proxy->name())) {
1085       FAIL(proxy, "Invalid asm.js identifier in parameter name.");
1086     }
1087 
1088     if (!AddLocal(param, param_info)) {
1089       FAIL(proxy, "Redeclared parameter.");
1090     }
1091     parameter_types.push_back(type);
1092     SetTypeOf(proxy, type);
1093     SetTypeOf(expr, type);
1094   }
1095 
1096   if (static_cast<int>(annotated_parameters) != fun->parameter_count()) {
1097     FAIL(fun_decl, "Incorrect parameter type annotations.");
1098   }
1099 
1100   // 5.3 Function type annotations
1101   //     * locals
1102   for (; current; current = iter.Next()) {
1103     auto* initializer = ExtractInitializerExpression(current);
1104     if (initializer == nullptr) {
1105       // Done with locals.
1106       break;
1107     }
1108 
1109     auto* local = initializer->target()->AsVariableProxy();
1110     if (local == nullptr) {
1111       // Done with locals. It should never happen. Even if it does, the asm.js
1112       // code should not declare any other locals after this point, so we assume
1113       // this is OK. If any other variable declaration is found we report a
1114       // validation error.
1115       DCHECK(false);
1116       break;
1117     }
1118 
1119     AsmType* type;
1120     RECURSE(type = VariableTypeAnnotations(initializer->value()));
1121     auto* local_info = new (zone_) VariableInfo(type);
1122     local_info->set_mutability(VariableInfo::kLocal);
1123     if (!ValidAsmIdentifier(local->name())) {
1124       FAIL(local, "Invalid asm.js identifier in local variable.");
1125     }
1126 
1127     if (!AddLocal(local->var(), local_info)) {
1128       FAIL(initializer, "Redeclared local.");
1129     }
1130 
1131     SetTypeOf(local, type);
1132     SetTypeOf(initializer, type);
1133   }
1134 
1135   // 5.2 Return Type Annotations
1136   // *VIOLATION* we peel blocks to find the last statement in the asm module
1137   // because the parser may introduce synthetic blocks.
1138   ZoneList<Statement*>* statements = fun->body();
1139 
1140   do {
1141     if (statements->length() == 0) {
1142       return_type_ = AsmType::Void();
1143     } else {
1144       auto* last_statement = statements->last();
1145       auto* as_block = last_statement->AsBlock();
1146       if (as_block != nullptr) {
1147         statements = as_block->statements();
1148       } else {
1149         // We don't check whether AsReturnStatement() below returns non-null --
1150         // we leave that to the ReturnTypeAnnotations method.
1151         RECURSE(return_type_ =
1152                     ReturnTypeAnnotations(last_statement->AsReturnStatement()));
1153       }
1154     }
1155   } while (return_type_ == AsmType::None());
1156 
1157   DCHECK(return_type_->IsReturnType());
1158 
1159   for (Declaration* decl : *fun->scope()->declarations()) {
1160     auto* var_decl = decl->AsVariableDeclaration();
1161     if (var_decl == nullptr) {
1162       FAIL(decl, "Functions may only define inner variables.");
1163     }
1164 
1165     auto* var_proxy = var_decl->proxy();
1166     if (var_proxy == nullptr) {
1167       FAIL(decl, "Invalid local declaration declaration.");
1168     }
1169 
1170     auto* var_info = Lookup(var_proxy->var());
1171     if (var_info == nullptr || var_info->IsGlobal()) {
1172       FAIL(decl, "Local variable missing initializer in asm.js module.");
1173     }
1174   }
1175 
1176   for (; current; current = iter.Next()) {
1177     AsmType* current_type;
1178     RECURSE(current_type = ValidateStatement(current));
1179   }
1180 
1181   auto* fun_type = AsmType::Function(zone_, return_type_);
1182   auto* fun_type_as_function = fun_type->AsFunctionType();
1183   for (auto* param_type : parameter_types) {
1184     fun_type_as_function->AddArgument(param_type);
1185   }
1186 
1187   auto* fun_var = fun_decl_proxy->var();
1188   auto* fun_info = new (zone_) VariableInfo(fun_type);
1189   fun_info->set_mutability(VariableInfo::kImmutableGlobal);
1190   auto* old_fun_info = Lookup(fun_var);
1191   if (old_fun_info == nullptr) {
1192     if (!ValidAsmIdentifier(fun_var->name())) {
1193       FAIL(fun_decl_proxy, "Invalid asm.js identifier in function name.");
1194     }
1195     if (!AddGlobal(fun_var, fun_info)) {
1196       DCHECK(false);
1197       FAIL(fun_decl, "Redeclared global identifier.");
1198     }
1199 
1200     SetTypeOf(fun, fun_type);
1201     return fun_type;
1202   }
1203 
1204   // Not necessarily an error -- fun_decl might have been used before being
1205   // defined. If that's the case, then the type in the global environment must
1206   // be the same as the type inferred by the parameter/return type annotations.
1207   auto* old_fun_type = old_fun_info->type();
1208   if (old_fun_type->AsFunctionType() == nullptr) {
1209     FAIL(fun_decl, "Identifier redefined as function.");
1210   }
1211 
1212   if (!old_fun_info->missing_definition()) {
1213     FAIL(fun_decl, "Identifier redefined (function name).");
1214   }
1215 
1216   if (!fun_type->IsA(old_fun_type)) {
1217     FAIL(fun_decl, "Signature mismatch when defining function.");
1218   }
1219 
1220   old_fun_info->MarkDefined();
1221   SetTypeOf(fun, fun_type);
1222 
1223   return fun_type;
1224 }
1225 
1226 // 6.5 ValidateStatement
ValidateStatement(Statement * statement)1227 AsmType* AsmTyper::ValidateStatement(Statement* statement) {
1228   switch (statement->node_type()) {
1229     default:
1230       FAIL(statement, "Statement type invalid for asm.js.");
1231     case AstNode::kBlock:
1232       return ValidateBlockStatement(statement->AsBlock());
1233     case AstNode::kExpressionStatement:
1234       return ValidateExpressionStatement(statement->AsExpressionStatement());
1235     case AstNode::kEmptyStatement:
1236       return ValidateEmptyStatement(statement->AsEmptyStatement());
1237     case AstNode::kIfStatement:
1238       return ValidateIfStatement(statement->AsIfStatement());
1239     case AstNode::kReturnStatement:
1240       return ValidateReturnStatement(statement->AsReturnStatement());
1241     case AstNode::kWhileStatement:
1242       return ValidateWhileStatement(statement->AsWhileStatement());
1243     case AstNode::kDoWhileStatement:
1244       return ValidateDoWhileStatement(statement->AsDoWhileStatement());
1245     case AstNode::kForStatement:
1246       return ValidateForStatement(statement->AsForStatement());
1247     case AstNode::kBreakStatement:
1248       return ValidateBreakStatement(statement->AsBreakStatement());
1249     case AstNode::kContinueStatement:
1250       return ValidateContinueStatement(statement->AsContinueStatement());
1251     case AstNode::kSwitchStatement:
1252       return ValidateSwitchStatement(statement->AsSwitchStatement());
1253   }
1254 
1255   return AsmType::Void();
1256 }
1257 
1258 // 6.5.1 BlockStatement
ValidateBlockStatement(Block * block)1259 AsmType* AsmTyper::ValidateBlockStatement(Block* block) {
1260   FlattenedStatements iter(zone_, block->statements());
1261 
1262   while (auto* current = iter.Next()) {
1263     RECURSE(ValidateStatement(current));
1264   }
1265 
1266   return AsmType::Void();
1267 }
1268 
1269 // 6.5.2 ExpressionStatement
ValidateExpressionStatement(ExpressionStatement * expr)1270 AsmType* AsmTyper::ValidateExpressionStatement(ExpressionStatement* expr) {
1271   auto* expression = expr->expression();
1272   if (auto* call = expression->AsCall()) {
1273     RECURSE(ValidateCall(AsmType::Void(), call));
1274   } else {
1275     RECURSE(ValidateExpression(expression));
1276   }
1277 
1278   return AsmType::Void();
1279 }
1280 
1281 // 6.5.3 EmptyStatement
ValidateEmptyStatement(EmptyStatement * empty)1282 AsmType* AsmTyper::ValidateEmptyStatement(EmptyStatement* empty) {
1283   return AsmType::Void();
1284 }
1285 
1286 // 6.5.4 IfStatement
ValidateIfStatement(IfStatement * if_stmt)1287 AsmType* AsmTyper::ValidateIfStatement(IfStatement* if_stmt) {
1288   AsmType* cond_type;
1289   RECURSE(cond_type = ValidateExpression(if_stmt->condition()));
1290   if (!cond_type->IsA(AsmType::Int())) {
1291     FAIL(if_stmt->condition(), "If condition must be type int.");
1292   }
1293   RECURSE(ValidateStatement(if_stmt->then_statement()));
1294   RECURSE(ValidateStatement(if_stmt->else_statement()));
1295   return AsmType::Void();
1296 }
1297 
1298 // 6.5.5 ReturnStatement
ValidateReturnStatement(ReturnStatement * ret_stmt)1299 AsmType* AsmTyper::ValidateReturnStatement(ReturnStatement* ret_stmt) {
1300   AsmType* ret_expr_type = AsmType::Void();
1301   if (auto* ret_expr = ret_stmt->expression()) {
1302     RECURSE(ret_expr_type = ValidateExpression(ret_expr));
1303     if (ret_expr_type == AsmType::Void()) {
1304       // *VIOLATION* The parser modifies the source code so that expressionless
1305       // returns will return undefined, so we need to allow that.
1306       if (!ret_expr->IsUndefinedLiteral()) {
1307         FAIL(ret_stmt, "Return statement expression can't be void.");
1308       }
1309     }
1310   }
1311 
1312   if (!ret_expr_type->IsA(return_type_)) {
1313     FAIL(ret_stmt, "Type mismatch in return statement.");
1314   }
1315 
1316   return ret_expr_type;
1317 }
1318 
1319 // 6.5.6 IterationStatement
1320 // 6.5.6.a WhileStatement
ValidateWhileStatement(WhileStatement * while_stmt)1321 AsmType* AsmTyper::ValidateWhileStatement(WhileStatement* while_stmt) {
1322   AsmType* cond_type;
1323   RECURSE(cond_type = ValidateExpression(while_stmt->cond()));
1324   if (!cond_type->IsA(AsmType::Int())) {
1325     FAIL(while_stmt->cond(), "While condition must be type int.");
1326   }
1327 
1328   if (auto* body = while_stmt->body()) {
1329     RECURSE(ValidateStatement(body));
1330   }
1331   return AsmType::Void();
1332 }
1333 
1334 // 6.5.6.b DoWhileStatement
ValidateDoWhileStatement(DoWhileStatement * do_while)1335 AsmType* AsmTyper::ValidateDoWhileStatement(DoWhileStatement* do_while) {
1336   AsmType* cond_type;
1337   RECURSE(cond_type = ValidateExpression(do_while->cond()));
1338   if (!cond_type->IsA(AsmType::Int())) {
1339     FAIL(do_while->cond(), "Do {} While condition must be type int.");
1340   }
1341 
1342   if (auto* body = do_while->body()) {
1343     RECURSE(ValidateStatement(body));
1344   }
1345   return AsmType::Void();
1346 }
1347 
1348 // 6.5.6.c ForStatement
ValidateForStatement(ForStatement * for_stmt)1349 AsmType* AsmTyper::ValidateForStatement(ForStatement* for_stmt) {
1350   if (auto* init = for_stmt->init()) {
1351     RECURSE(ValidateStatement(init));
1352   }
1353 
1354   if (auto* cond = for_stmt->cond()) {
1355     AsmType* cond_type;
1356     RECURSE(cond_type = ValidateExpression(cond));
1357     if (!cond_type->IsA(AsmType::Int())) {
1358       FAIL(cond, "For condition must be type int.");
1359     }
1360   }
1361 
1362   if (auto* next = for_stmt->next()) {
1363     RECURSE(ValidateStatement(next));
1364   }
1365 
1366   if (auto* body = for_stmt->body()) {
1367     RECURSE(ValidateStatement(body));
1368   }
1369 
1370   return AsmType::Void();
1371 }
1372 
1373 // 6.5.7 BreakStatement
ValidateBreakStatement(BreakStatement * brk_stmt)1374 AsmType* AsmTyper::ValidateBreakStatement(BreakStatement* brk_stmt) {
1375   return AsmType::Void();
1376 }
1377 
1378 // 6.5.8 ContinueStatement
ValidateContinueStatement(ContinueStatement * cont_stmt)1379 AsmType* AsmTyper::ValidateContinueStatement(ContinueStatement* cont_stmt) {
1380   return AsmType::Void();
1381 }
1382 
1383 // 6.5.9 LabelledStatement
1384 // No need to handle these here -- see the AsmTyper's definition.
1385 
1386 // 6.5.10 SwitchStatement
ValidateSwitchStatement(SwitchStatement * stmt)1387 AsmType* AsmTyper::ValidateSwitchStatement(SwitchStatement* stmt) {
1388   AsmType* cond_type;
1389   RECURSE(cond_type = ValidateExpression(stmt->tag()));
1390   if (!cond_type->IsA(AsmType::Signed())) {
1391     FAIL(stmt, "Switch tag must be signed.");
1392   }
1393 
1394   int default_pos = kNoSourcePosition;
1395   int last_case_pos = kNoSourcePosition;
1396   ZoneSet<int32_t> cases_seen(zone_);
1397   for (auto* a_case : *stmt->cases()) {
1398     if (a_case->is_default()) {
1399       CHECK(default_pos == kNoSourcePosition);
1400       RECURSE(ValidateDefault(a_case));
1401       default_pos = a_case->position();
1402       continue;
1403     }
1404 
1405     if (last_case_pos == kNoSourcePosition) {
1406       last_case_pos = a_case->position();
1407     } else {
1408       last_case_pos = std::max(last_case_pos, a_case->position());
1409     }
1410 
1411     int32_t case_lbl;
1412     RECURSE(ValidateCase(a_case, &case_lbl));
1413     auto case_lbl_pos = cases_seen.find(case_lbl);
1414     if (case_lbl_pos != cases_seen.end() && *case_lbl_pos == case_lbl) {
1415       FAIL(a_case, "Duplicated case label.");
1416     }
1417     cases_seen.insert(case_lbl);
1418   }
1419 
1420   if (!cases_seen.empty()) {
1421     const int64_t max_lbl = *cases_seen.rbegin();
1422     const int64_t min_lbl = *cases_seen.begin();
1423     if (max_lbl - min_lbl > std::numeric_limits<int32_t>::max()) {
1424       FAIL(stmt, "Out-of-bounds case label range.");
1425     }
1426   }
1427 
1428   if (last_case_pos != kNoSourcePosition && default_pos != kNoSourcePosition &&
1429       default_pos < last_case_pos) {
1430     FAIL(stmt, "Switch default must appear last.");
1431   }
1432 
1433   return AsmType::Void();
1434 }
1435 
1436 // 6.6 ValidateCase
1437 namespace {
ExtractInt32CaseLabel(CaseClause * clause,int32_t * lbl)1438 bool ExtractInt32CaseLabel(CaseClause* clause, int32_t* lbl) {
1439   auto* lbl_expr = clause->label()->AsLiteral();
1440 
1441   if (lbl_expr == nullptr) {
1442     return false;
1443   }
1444 
1445   if (lbl_expr->raw_value()->ContainsDot()) {
1446     return false;
1447   }
1448 
1449   return lbl_expr->value()->ToInt32(lbl);
1450 }
1451 }  // namespace
1452 
ValidateCase(CaseClause * label,int32_t * case_lbl)1453 AsmType* AsmTyper::ValidateCase(CaseClause* label, int32_t* case_lbl) {
1454   if (!ExtractInt32CaseLabel(label, case_lbl)) {
1455     FAIL(label, "Case label must be a 32-bit signed integer.");
1456   }
1457 
1458   FlattenedStatements iter(zone_, label->statements());
1459   while (auto* current = iter.Next()) {
1460     RECURSE(ValidateStatement(current));
1461   }
1462   return AsmType::Void();
1463 }
1464 
1465 // 6.7 ValidateDefault
ValidateDefault(CaseClause * label)1466 AsmType* AsmTyper::ValidateDefault(CaseClause* label) {
1467   FlattenedStatements iter(zone_, label->statements());
1468   while (auto* current = iter.Next()) {
1469     RECURSE(ValidateStatement(current));
1470   }
1471   return AsmType::Void();
1472 }
1473 
1474 // 6.8 ValidateExpression
ValidateExpression(Expression * expr)1475 AsmType* AsmTyper::ValidateExpression(Expression* expr) {
1476   AsmType* expr_ty = AsmType::None();
1477 
1478   switch (expr->node_type()) {
1479     default:
1480       FAIL(expr, "Invalid asm.js expression.");
1481     case AstNode::kLiteral:
1482       RECURSE(expr_ty = ValidateNumericLiteral(expr->AsLiteral()));
1483       break;
1484     case AstNode::kVariableProxy:
1485       RECURSE(expr_ty = ValidateIdentifier(expr->AsVariableProxy()));
1486       break;
1487     case AstNode::kCall:
1488       RECURSE(expr_ty = ValidateCallExpression(expr->AsCall()));
1489       break;
1490     case AstNode::kProperty:
1491       RECURSE(expr_ty = ValidateMemberExpression(expr->AsProperty()));
1492       break;
1493     case AstNode::kAssignment:
1494       RECURSE(expr_ty = ValidateAssignmentExpression(expr->AsAssignment()));
1495       break;
1496     case AstNode::kUnaryOperation:
1497       RECURSE(expr_ty = ValidateUnaryExpression(expr->AsUnaryOperation()));
1498       break;
1499     case AstNode::kConditional:
1500       RECURSE(expr_ty = ValidateConditionalExpression(expr->AsConditional()));
1501       break;
1502     case AstNode::kCompareOperation:
1503       RECURSE(expr_ty = ValidateCompareOperation(expr->AsCompareOperation()));
1504       break;
1505     case AstNode::kBinaryOperation:
1506       RECURSE(expr_ty = ValidateBinaryOperation(expr->AsBinaryOperation()));
1507       break;
1508   }
1509 
1510   SetTypeOf(expr, expr_ty);
1511   return expr_ty;
1512 }
1513 
ValidateCompareOperation(CompareOperation * cmp)1514 AsmType* AsmTyper::ValidateCompareOperation(CompareOperation* cmp) {
1515   switch (cmp->op()) {
1516     default:
1517       FAIL(cmp, "Invalid asm.js comparison operator.");
1518     case Token::LT:
1519     case Token::LTE:
1520     case Token::GT:
1521     case Token::GTE:
1522       return ValidateRelationalExpression(cmp);
1523     case Token::EQ:
1524     case Token::NE:
1525       return ValidateEqualityExpression(cmp);
1526   }
1527 
1528   UNREACHABLE();
1529 }
1530 
1531 namespace {
IsInvert(BinaryOperation * binop)1532 bool IsInvert(BinaryOperation* binop) {
1533   if (binop->op() != Token::BIT_XOR) {
1534     return false;
1535   }
1536 
1537   auto* right_as_literal = binop->right()->AsLiteral();
1538   if (right_as_literal == nullptr) {
1539     return false;
1540   }
1541 
1542   return !right_as_literal->raw_value()->ContainsDot() &&
1543          right_as_literal->raw_value()->AsNumber() == -1.0;
1544 }
1545 
IsUnaryMinus(BinaryOperation * binop)1546 bool IsUnaryMinus(BinaryOperation* binop) {
1547   // *VIOLATION* The parser replaces uses of -x with x*-1.
1548   if (binop->op() != Token::MUL) {
1549     return false;
1550   }
1551 
1552   auto* right_as_literal = binop->right()->AsLiteral();
1553   if (right_as_literal == nullptr) {
1554     return false;
1555   }
1556 
1557   return !right_as_literal->raw_value()->ContainsDot() &&
1558          right_as_literal->raw_value()->AsNumber() == -1.0;
1559 }
1560 }  // namespace
1561 
ValidateBinaryOperation(BinaryOperation * expr)1562 AsmType* AsmTyper::ValidateBinaryOperation(BinaryOperation* expr) {
1563 #define UNOP_OVERLOAD(Src, Dest)          \
1564   do {                                    \
1565     if (left_type->IsA(AsmType::Src())) { \
1566       return AsmType::Dest();             \
1567     }                                     \
1568   } while (0)
1569 
1570   switch (expr->op()) {
1571     default:
1572       FAIL(expr, "Invalid asm.js binary expression.");
1573     case Token::COMMA:
1574       return ValidateCommaExpression(expr);
1575     case Token::MUL:
1576       if (IsDoubleAnnotation(expr)) {
1577         // *VIOLATION* We can't be 100% sure this really IS a unary + in the asm
1578         // source so we have to be lenient, and treat this as a unary +.
1579         if (auto* Call = expr->left()->AsCall()) {
1580           return ValidateCall(AsmType::Double(), Call);
1581         }
1582         AsmType* left_type;
1583         RECURSE(left_type = ValidateExpression(expr->left()));
1584         SetTypeOf(expr->right(), AsmType::Double());
1585         UNOP_OVERLOAD(Signed, Double);
1586         UNOP_OVERLOAD(Unsigned, Double);
1587         UNOP_OVERLOAD(DoubleQ, Double);
1588         UNOP_OVERLOAD(FloatQ, Double);
1589         FAIL(expr, "Invalid type for conversion to double.");
1590       }
1591 
1592       if (IsUnaryMinus(expr)) {
1593         // *VIOLATION* the parser converts -x to x * -1.
1594         AsmType* left_type;
1595         RECURSE(left_type = ValidateExpression(expr->left()));
1596         SetTypeOf(expr->right(), left_type);
1597         UNOP_OVERLOAD(Int, Intish);
1598         UNOP_OVERLOAD(DoubleQ, Double);
1599         UNOP_OVERLOAD(FloatQ, Floatish);
1600         FAIL(expr, "Invalid type for unary -.");
1601       }
1602     // FALTHROUGH
1603     case Token::DIV:
1604     case Token::MOD:
1605       return ValidateMultiplicativeExpression(expr);
1606     case Token::ADD:
1607     case Token::SUB: {
1608       static const uint32_t kInitialIntishCount = 0;
1609       return ValidateAdditiveExpression(expr, kInitialIntishCount);
1610     }
1611     case Token::SAR:
1612     case Token::SHL:
1613     case Token::SHR:
1614       return ValidateShiftExpression(expr);
1615     case Token::BIT_AND:
1616       return ValidateBitwiseANDExpression(expr);
1617     case Token::BIT_XOR:
1618       if (IsInvert(expr)) {
1619         auto* left = expr->left();
1620         auto* left_as_binop = left->AsBinaryOperation();
1621 
1622         if (left_as_binop != nullptr && IsInvert(left_as_binop)) {
1623           // This is the special ~~ operator.
1624           AsmType* left_type;
1625           RECURSE(left_type = ValidateExpression(left_as_binop->left()));
1626           SetTypeOf(left_as_binop->right(), AsmType::FixNum());
1627           SetTypeOf(left_as_binop, AsmType::Signed());
1628           SetTypeOf(expr->right(), AsmType::FixNum());
1629           UNOP_OVERLOAD(Double, Signed);
1630           UNOP_OVERLOAD(FloatQ, Signed);
1631           FAIL(left_as_binop, "Invalid type for conversion to signed.");
1632         }
1633 
1634         AsmType* left_type;
1635         RECURSE(left_type = ValidateExpression(left));
1636         UNOP_OVERLOAD(Intish, Signed);
1637         FAIL(left, "Invalid type for ~.");
1638       }
1639 
1640       return ValidateBitwiseXORExpression(expr);
1641     case Token::BIT_OR:
1642       return ValidateBitwiseORExpression(expr);
1643   }
1644 #undef UNOP_OVERLOAD
1645   UNREACHABLE();
1646 }
1647 
1648 // 6.8.1 Expression
ValidateCommaExpression(BinaryOperation * comma)1649 AsmType* AsmTyper::ValidateCommaExpression(BinaryOperation* comma) {
1650   // The AST looks like:
1651   // (expr COMMA (expr COMMA (expr COMMA (... ))))
1652 
1653   auto* left = comma->left();
1654   if (auto* left_as_call = left->AsCall()) {
1655     RECURSE(ValidateCall(AsmType::Void(), left_as_call));
1656   } else {
1657     RECURSE(ValidateExpression(left));
1658   }
1659 
1660   auto* right = comma->right();
1661   AsmType* right_type = nullptr;
1662   if (auto* right_as_call = right->AsCall()) {
1663     RECURSE(right_type = ValidateFloatCoercion(right_as_call));
1664     if (right_type != AsmType::Float()) {
1665       // right_type == nullptr <-> right_as_call is not a call to fround.
1666       DCHECK(right_type == nullptr);
1667       RECURSE(right_type = ValidateCall(AsmType::Void(), right_as_call));
1668       // Unnanotated function call to something that's not fround must be a call
1669       // to a void function.
1670       DCHECK_EQ(right_type, AsmType::Void());
1671     }
1672   } else {
1673     RECURSE(right_type = ValidateExpression(right));
1674   }
1675 
1676   return right_type;
1677 }
1678 
1679 // 6.8.2 NumericLiteral
ValidateNumericLiteral(Literal * literal)1680 AsmType* AsmTyper::ValidateNumericLiteral(Literal* literal) {
1681   // *VIOLATION* asm.js does not allow the use of undefined, but our parser
1682   // inserts them, so we have to handle them.
1683   if (literal->IsUndefinedLiteral()) {
1684     return AsmType::Void();
1685   }
1686 
1687   if (literal->raw_value()->ContainsDot()) {
1688     return AsmType::Double();
1689   }
1690 
1691   // The parser collapses expressions like !0 and !123 to true/false.
1692   // We therefore need to permit these as alternate versions of 0 / 1.
1693   if (literal->raw_value()->IsTrue() || literal->raw_value()->IsFalse()) {
1694     return AsmType::Int();
1695   }
1696 
1697   uint32_t value;
1698   if (!literal->value()->ToUint32(&value)) {
1699     int32_t value;
1700     if (!literal->value()->ToInt32(&value)) {
1701       FAIL(literal, "Integer literal is out of range.");
1702     }
1703     // *VIOLATION* Not really a violation, but rather a difference in
1704     // validation. The spec handles -NumericLiteral in ValidateUnaryExpression,
1705     // but V8's AST represents the negative literals as Literals.
1706     return AsmType::Signed();
1707   }
1708 
1709   if (value <= LargestFixNum) {
1710     return AsmType::FixNum();
1711   }
1712 
1713   return AsmType::Unsigned();
1714 }
1715 
1716 // 6.8.3 Identifier
ValidateIdentifier(VariableProxy * proxy)1717 AsmType* AsmTyper::ValidateIdentifier(VariableProxy* proxy) {
1718   auto* proxy_info = Lookup(proxy->var());
1719   if (proxy_info == nullptr) {
1720     FAIL(proxy, "Undeclared identifier.");
1721   }
1722   auto* type = proxy_info->type();
1723   if (type->IsA(AsmType::None()) || type->AsCallableType() != nullptr) {
1724     FAIL(proxy, "Identifier may not be accessed by ordinary expressions.");
1725   }
1726   return type;
1727 }
1728 
1729 // 6.8.4 CallExpression
ValidateCallExpression(Call * call)1730 AsmType* AsmTyper::ValidateCallExpression(Call* call) {
1731   AsmType* return_type;
1732   RECURSE(return_type = ValidateFloatCoercion(call));
1733   if (return_type == nullptr) {
1734     FAIL(call, "Unanotated call to a function must be a call to fround.");
1735   }
1736   return return_type;
1737 }
1738 
1739 // 6.8.5 MemberExpression
ValidateMemberExpression(Property * prop)1740 AsmType* AsmTyper::ValidateMemberExpression(Property* prop) {
1741   AsmType* return_type;
1742   RECURSE(return_type = ValidateHeapAccess(prop, LoadFromHeap));
1743   return return_type;
1744 }
1745 
1746 // 6.8.6 AssignmentExpression
ValidateAssignmentExpression(Assignment * assignment)1747 AsmType* AsmTyper::ValidateAssignmentExpression(Assignment* assignment) {
1748   AsmType* value_type;
1749   RECURSE(value_type = ValidateExpression(assignment->value()));
1750 
1751   if (assignment->op() == Token::INIT) {
1752     FAIL(assignment,
1753          "Local variable declaration must be at the top of the function.");
1754   }
1755 
1756   if (auto* target_as_proxy = assignment->target()->AsVariableProxy()) {
1757     auto* var = target_as_proxy->var();
1758     auto* target_info = Lookup(var);
1759 
1760     if (target_info == nullptr) {
1761       if (var->mode() != TEMPORARY) {
1762         FAIL(target_as_proxy, "Undeclared identifier.");
1763       }
1764       // Temporary variables are special: we add them to the local symbol table
1765       // as we see them, with the exact type of the variable's initializer. This
1766       // means that temporary variables might have nonsensical types (i.e.,
1767       // intish, float?, fixnum, and not just the "canonical" types.)
1768       auto* var_info = new (zone_) VariableInfo(value_type);
1769       var_info->set_mutability(VariableInfo::kLocal);
1770       if (!ValidAsmIdentifier(target_as_proxy->name())) {
1771         FAIL(target_as_proxy,
1772              "Invalid asm.js identifier in temporary variable.");
1773       }
1774 
1775       if (!AddLocal(var, var_info)) {
1776         FAIL(assignment, "Failed to add temporary variable to symbol table.");
1777       }
1778       return value_type;
1779     }
1780 
1781     if (!target_info->IsMutable()) {
1782       FAIL(assignment, "Can't assign to immutable symbol.");
1783     }
1784 
1785     DCHECK_NE(AsmType::None(), target_info->type());
1786     if (!value_type->IsA(target_info->type())) {
1787       FAIL(assignment, "Type mismatch in assignment.");
1788     }
1789 
1790     return value_type;
1791   }
1792 
1793   if (auto* target_as_property = assignment->target()->AsProperty()) {
1794     AsmType* allowed_store_types;
1795     RECURSE(allowed_store_types =
1796                 ValidateHeapAccess(target_as_property, StoreToHeap));
1797 
1798     if (!value_type->IsA(allowed_store_types)) {
1799       FAIL(assignment, "Type mismatch in heap assignment.");
1800     }
1801 
1802     return value_type;
1803   }
1804 
1805   FAIL(assignment, "Invalid asm.js assignment.");
1806 }
1807 
1808 // 6.8.7 UnaryExpression
ValidateUnaryExpression(UnaryOperation * unop)1809 AsmType* AsmTyper::ValidateUnaryExpression(UnaryOperation* unop) {
1810   // *VIOLATION* -NumericLiteral is validated in ValidateLiteral.
1811   // *VIOLATION* +UnaryExpression is validated in ValidateBinaryOperation.
1812   // *VIOLATION* ~UnaryOperation is validated in ValidateBinaryOperation.
1813   // *VIOLATION* ~~UnaryOperation is validated in ValidateBinaryOperation.
1814   DCHECK(unop->op() != Token::BIT_NOT);
1815   DCHECK(unop->op() != Token::ADD);
1816   AsmType* exp_type;
1817   RECURSE(exp_type = ValidateExpression(unop->expression()));
1818 #define UNOP_OVERLOAD(Src, Dest)         \
1819   do {                                   \
1820     if (exp_type->IsA(AsmType::Src())) { \
1821       return AsmType::Dest();            \
1822     }                                    \
1823   } while (0)
1824 
1825   // 8.1 Unary Operators
1826   switch (unop->op()) {
1827     default:
1828       FAIL(unop, "Invalid unary operator.");
1829     case Token::ADD:
1830       // We can't test this because of the +x -> x * 1.0 transformation.
1831       DCHECK(false);
1832       UNOP_OVERLOAD(Signed, Double);
1833       UNOP_OVERLOAD(Unsigned, Double);
1834       UNOP_OVERLOAD(DoubleQ, Double);
1835       UNOP_OVERLOAD(FloatQ, Double);
1836       FAIL(unop, "Invalid type for unary +.");
1837     case Token::SUB:
1838       // We can't test this because of the -x -> x * -1.0 transformation.
1839       DCHECK(false);
1840       UNOP_OVERLOAD(Int, Intish);
1841       UNOP_OVERLOAD(DoubleQ, Double);
1842       UNOP_OVERLOAD(FloatQ, Floatish);
1843       FAIL(unop, "Invalid type for unary -.");
1844     case Token::BIT_NOT:
1845       // We can't test this because of the ~x -> x ^ -1 transformation.
1846       DCHECK(false);
1847       UNOP_OVERLOAD(Intish, Signed);
1848       FAIL(unop, "Invalid type for ~.");
1849     case Token::NOT:
1850       UNOP_OVERLOAD(Int, Int);
1851       FAIL(unop, "Invalid type for !.");
1852   }
1853 
1854 #undef UNOP_OVERLOAD
1855 
1856   UNREACHABLE();
1857 }
1858 
1859 // 6.8.8 MultiplicativeExpression
1860 namespace {
IsIntishLiteralFactor(Expression * expr,int32_t * factor)1861 bool IsIntishLiteralFactor(Expression* expr, int32_t* factor) {
1862   auto* literal = expr->AsLiteral();
1863   if (literal == nullptr) {
1864     return false;
1865   }
1866 
1867   if (literal->raw_value()->ContainsDot()) {
1868     return false;
1869   }
1870 
1871   if (!literal->value()->ToInt32(factor)) {
1872     return false;
1873   }
1874   static const int32_t kIntishBound = 1 << 20;
1875   return -kIntishBound < *factor && *factor < kIntishBound;
1876 }
1877 }  // namespace
1878 
ValidateMultiplicativeExpression(BinaryOperation * binop)1879 AsmType* AsmTyper::ValidateMultiplicativeExpression(BinaryOperation* binop) {
1880   DCHECK(!IsDoubleAnnotation(binop));
1881 
1882   auto* left = binop->left();
1883   auto* right = binop->right();
1884 
1885   bool intish_mul_failed = false;
1886   if (binop->op() == Token::MUL) {
1887     int32_t factor;
1888     if (IsIntishLiteralFactor(left, &factor)) {
1889       AsmType* right_type;
1890       RECURSE(right_type = ValidateExpression(right));
1891       if (right_type->IsA(AsmType::Int())) {
1892         return AsmType::Intish();
1893       }
1894       // Can't fail here, because the rhs might contain a valid intish factor.
1895       //
1896       // The solution is to flag that there was an error, and later on -- when
1897       // both lhs and rhs are evaluated -- complain.
1898       intish_mul_failed = true;
1899     }
1900 
1901     if (IsIntishLiteralFactor(right, &factor)) {
1902       AsmType* left_type;
1903       RECURSE(left_type = ValidateExpression(left));
1904       if (left_type->IsA(AsmType::Int())) {
1905         // *VIOLATION* This will also (and correctly) handle -X, when X is an
1906         // integer. Therefore, we don't need to handle this case within the if
1907         // block below.
1908         return AsmType::Intish();
1909       }
1910       intish_mul_failed = true;
1911 
1912       if (factor == -1) {
1913         // *VIOLATION* The frontend transforms -x into x * -1 (not -1.0, because
1914         // consistency is overrated.)
1915         if (left_type->IsA(AsmType::DoubleQ())) {
1916           return AsmType::Double();
1917         } else if (left_type->IsA(AsmType::FloatQ())) {
1918           return AsmType::Floatish();
1919         }
1920       }
1921     }
1922   }
1923 
1924   if (intish_mul_failed) {
1925     FAIL(binop, "Invalid types for intish * (or unary -).");
1926   }
1927 
1928   AsmType* left_type;
1929   AsmType* right_type;
1930   RECURSE(left_type = ValidateExpression(left));
1931   RECURSE(right_type = ValidateExpression(right));
1932 
1933 #define BINOP_OVERLOAD(Src0, Src1, Dest)                                       \
1934   do {                                                                         \
1935     if (left_type->IsA(AsmType::Src0()) && right_type->IsA(AsmType::Src1())) { \
1936       return AsmType::Dest();                                                  \
1937     }                                                                          \
1938   } while (0)
1939   switch (binop->op()) {
1940     default:
1941       FAIL(binop, "Invalid multiplicative expression.");
1942     case Token::MUL:
1943       BINOP_OVERLOAD(DoubleQ, DoubleQ, Double);
1944       BINOP_OVERLOAD(FloatQ, FloatQ, Floatish);
1945       FAIL(binop, "Invalid operands for *.");
1946     case Token::DIV:
1947       BINOP_OVERLOAD(Signed, Signed, Intish);
1948       BINOP_OVERLOAD(Unsigned, Unsigned, Intish);
1949       BINOP_OVERLOAD(DoubleQ, DoubleQ, Double);
1950       BINOP_OVERLOAD(FloatQ, FloatQ, Floatish);
1951       FAIL(binop, "Invalid operands for /.");
1952     case Token::MOD:
1953       BINOP_OVERLOAD(Signed, Signed, Intish);
1954       BINOP_OVERLOAD(Unsigned, Unsigned, Intish);
1955       BINOP_OVERLOAD(DoubleQ, DoubleQ, Double);
1956       FAIL(binop, "Invalid operands for %.");
1957   }
1958 #undef BINOP_OVERLOAD
1959 
1960   UNREACHABLE();
1961 }
1962 
1963 // 6.8.9 AdditiveExpression
ValidateAdditiveExpression(BinaryOperation * binop,uint32_t intish_count)1964 AsmType* AsmTyper::ValidateAdditiveExpression(BinaryOperation* binop,
1965                                               uint32_t intish_count) {
1966   static const uint32_t kMaxIntish = 1 << 20;
1967 
1968   auto* left = binop->left();
1969   auto* left_as_binop = left->AsBinaryOperation();
1970   AsmType* left_type;
1971 
1972   // TODO(jpp): maybe use an iterative approach instead of the recursion to
1973   // ValidateAdditiveExpression.
1974   if (left_as_binop != nullptr && (left_as_binop->op() == Token::ADD ||
1975                                    left_as_binop->op() == Token::SUB)) {
1976     RECURSE(left_type =
1977                 ValidateAdditiveExpression(left_as_binop, intish_count + 1));
1978     SetTypeOf(left_as_binop, left_type);
1979   } else {
1980     RECURSE(left_type = ValidateExpression(left));
1981   }
1982 
1983   auto* right = binop->right();
1984   auto* right_as_binop = right->AsBinaryOperation();
1985   AsmType* right_type;
1986 
1987   if (right_as_binop != nullptr && (right_as_binop->op() == Token::ADD ||
1988                                     right_as_binop->op() == Token::SUB)) {
1989     RECURSE(right_type =
1990                 ValidateAdditiveExpression(right_as_binop, intish_count + 1));
1991     SetTypeOf(right_as_binop, right_type);
1992   } else {
1993     RECURSE(right_type = ValidateExpression(right));
1994   }
1995 
1996   if (left_type->IsA(AsmType::FloatQ()) && right_type->IsA(AsmType::FloatQ())) {
1997     return AsmType::Floatish();
1998   }
1999 
2000   if (left_type->IsA(AsmType::Int()) && right_type->IsA(AsmType::Int())) {
2001     if (intish_count == 0) {
2002       return AsmType::Intish();
2003     }
2004     if (intish_count < kMaxIntish) {
2005       return AsmType::Int();
2006     }
2007     FAIL(binop, "Too many uncoerced integer additive expressions.");
2008   }
2009 
2010   if (left_type->IsA(AsmType::Double()) && right_type->IsA(AsmType::Double())) {
2011     return AsmType::Double();
2012   }
2013 
2014   if (binop->op() == Token::SUB) {
2015     if (left_type->IsA(AsmType::DoubleQ()) &&
2016         right_type->IsA(AsmType::DoubleQ())) {
2017       return AsmType::Double();
2018     }
2019   }
2020 
2021   FAIL(binop, "Invalid operands for additive expression.");
2022 }
2023 
2024 // 6.8.10 ShiftExpression
ValidateShiftExpression(BinaryOperation * binop)2025 AsmType* AsmTyper::ValidateShiftExpression(BinaryOperation* binop) {
2026   auto* left = binop->left();
2027   auto* right = binop->right();
2028 
2029   AsmType* left_type;
2030   AsmType* right_type;
2031   RECURSE(left_type = ValidateExpression(left));
2032   RECURSE(right_type = ValidateExpression(right));
2033 
2034 #define BINOP_OVERLOAD(Src0, Src1, Dest)                                       \
2035   do {                                                                         \
2036     if (left_type->IsA(AsmType::Src0()) && right_type->IsA(AsmType::Src1())) { \
2037       return AsmType::Dest();                                                  \
2038     }                                                                          \
2039   } while (0)
2040   switch (binop->op()) {
2041     default:
2042       FAIL(binop, "Invalid shift expression.");
2043     case Token::SHL:
2044       BINOP_OVERLOAD(Intish, Intish, Signed);
2045       FAIL(binop, "Invalid operands for <<.");
2046     case Token::SAR:
2047       BINOP_OVERLOAD(Intish, Intish, Signed);
2048       FAIL(binop, "Invalid operands for >>.");
2049     case Token::SHR:
2050       BINOP_OVERLOAD(Intish, Intish, Unsigned);
2051       FAIL(binop, "Invalid operands for >>>.");
2052   }
2053 #undef BINOP_OVERLOAD
2054 
2055   UNREACHABLE();
2056 }
2057 
2058 // 6.8.11 RelationalExpression
ValidateRelationalExpression(CompareOperation * cmpop)2059 AsmType* AsmTyper::ValidateRelationalExpression(CompareOperation* cmpop) {
2060   auto* left = cmpop->left();
2061   auto* right = cmpop->right();
2062 
2063   AsmType* left_type;
2064   AsmType* right_type;
2065   RECURSE(left_type = ValidateExpression(left));
2066   RECURSE(right_type = ValidateExpression(right));
2067 
2068 #define CMPOP_OVERLOAD(Src0, Src1, Dest)                                       \
2069   do {                                                                         \
2070     if (left_type->IsA(AsmType::Src0()) && right_type->IsA(AsmType::Src1())) { \
2071       return AsmType::Dest();                                                  \
2072     }                                                                          \
2073   } while (0)
2074   switch (cmpop->op()) {
2075     default:
2076       FAIL(cmpop, "Invalid relational expression.");
2077     case Token::LT:
2078       CMPOP_OVERLOAD(Signed, Signed, Int);
2079       CMPOP_OVERLOAD(Unsigned, Unsigned, Int);
2080       CMPOP_OVERLOAD(Float, Float, Int);
2081       CMPOP_OVERLOAD(Double, Double, Int);
2082       FAIL(cmpop, "Invalid operands for <.");
2083     case Token::GT:
2084       CMPOP_OVERLOAD(Signed, Signed, Int);
2085       CMPOP_OVERLOAD(Unsigned, Unsigned, Int);
2086       CMPOP_OVERLOAD(Float, Float, Int);
2087       CMPOP_OVERLOAD(Double, Double, Int);
2088       FAIL(cmpop, "Invalid operands for >.");
2089     case Token::LTE:
2090       CMPOP_OVERLOAD(Signed, Signed, Int);
2091       CMPOP_OVERLOAD(Unsigned, Unsigned, Int);
2092       CMPOP_OVERLOAD(Float, Float, Int);
2093       CMPOP_OVERLOAD(Double, Double, Int);
2094       FAIL(cmpop, "Invalid operands for <=.");
2095     case Token::GTE:
2096       CMPOP_OVERLOAD(Signed, Signed, Int);
2097       CMPOP_OVERLOAD(Unsigned, Unsigned, Int);
2098       CMPOP_OVERLOAD(Float, Float, Int);
2099       CMPOP_OVERLOAD(Double, Double, Int);
2100       FAIL(cmpop, "Invalid operands for >=.");
2101   }
2102 #undef CMPOP_OVERLOAD
2103 
2104   UNREACHABLE();
2105 }
2106 
2107 // 6.8.12 EqualityExpression
ValidateEqualityExpression(CompareOperation * cmpop)2108 AsmType* AsmTyper::ValidateEqualityExpression(CompareOperation* cmpop) {
2109   auto* left = cmpop->left();
2110   auto* right = cmpop->right();
2111 
2112   AsmType* left_type;
2113   AsmType* right_type;
2114   RECURSE(left_type = ValidateExpression(left));
2115   RECURSE(right_type = ValidateExpression(right));
2116 
2117 #define CMPOP_OVERLOAD(Src0, Src1, Dest)                                       \
2118   do {                                                                         \
2119     if (left_type->IsA(AsmType::Src0()) && right_type->IsA(AsmType::Src1())) { \
2120       return AsmType::Dest();                                                  \
2121     }                                                                          \
2122   } while (0)
2123   switch (cmpop->op()) {
2124     default:
2125       FAIL(cmpop, "Invalid equality expression.");
2126     case Token::EQ:
2127       CMPOP_OVERLOAD(Signed, Signed, Int);
2128       CMPOP_OVERLOAD(Unsigned, Unsigned, Int);
2129       CMPOP_OVERLOAD(Float, Float, Int);
2130       CMPOP_OVERLOAD(Double, Double, Int);
2131       FAIL(cmpop, "Invalid operands for ==.");
2132     case Token::NE:
2133       CMPOP_OVERLOAD(Signed, Signed, Int);
2134       CMPOP_OVERLOAD(Unsigned, Unsigned, Int);
2135       CMPOP_OVERLOAD(Float, Float, Int);
2136       CMPOP_OVERLOAD(Double, Double, Int);
2137       FAIL(cmpop, "Invalid operands for !=.");
2138   }
2139 #undef CMPOP_OVERLOAD
2140 
2141   UNREACHABLE();
2142 }
2143 
2144 // 6.8.13 BitwiseANDExpression
ValidateBitwiseANDExpression(BinaryOperation * binop)2145 AsmType* AsmTyper::ValidateBitwiseANDExpression(BinaryOperation* binop) {
2146   auto* left = binop->left();
2147   auto* right = binop->right();
2148 
2149   AsmType* left_type;
2150   AsmType* right_type;
2151   RECURSE(left_type = ValidateExpression(left));
2152   RECURSE(right_type = ValidateExpression(right));
2153 
2154   if (binop->op() != Token::BIT_AND) {
2155     FAIL(binop, "Invalid & expression.");
2156   }
2157 
2158 #define BINOP_OVERLOAD(Src0, Src1, Dest)                                       \
2159   do {                                                                         \
2160     if (left_type->IsA(AsmType::Src0()) && right_type->IsA(AsmType::Src1())) { \
2161       return AsmType::Dest();                                                  \
2162     }                                                                          \
2163   } while (0)
2164   BINOP_OVERLOAD(Intish, Intish, Signed);
2165   FAIL(binop, "Invalid operands for &.");
2166 #undef BINOP_OVERLOAD
2167 
2168   UNREACHABLE();
2169 }
2170 
2171 // 6.8.14 BitwiseXORExpression
ValidateBitwiseXORExpression(BinaryOperation * binop)2172 AsmType* AsmTyper::ValidateBitwiseXORExpression(BinaryOperation* binop) {
2173   auto* left = binop->left();
2174   auto* right = binop->right();
2175 
2176   AsmType* left_type;
2177   AsmType* right_type;
2178   RECURSE(left_type = ValidateExpression(left));
2179   RECURSE(right_type = ValidateExpression(right));
2180 
2181   if (binop->op() != Token::BIT_XOR) {
2182     FAIL(binop, "Invalid ^ expression.");
2183   }
2184 
2185 #define BINOP_OVERLOAD(Src0, Src1, Dest)                                       \
2186   do {                                                                         \
2187     if (left_type->IsA(AsmType::Src0()) && right_type->IsA(AsmType::Src1())) { \
2188       return AsmType::Dest();                                                  \
2189     }                                                                          \
2190   } while (0)
2191   BINOP_OVERLOAD(Intish, Intish, Signed);
2192   FAIL(binop, "Invalid operands for ^.");
2193 #undef BINOP_OVERLOAD
2194 
2195   UNREACHABLE();
2196 }
2197 
2198 // 6.8.15 BitwiseORExpression
ValidateBitwiseORExpression(BinaryOperation * binop)2199 AsmType* AsmTyper::ValidateBitwiseORExpression(BinaryOperation* binop) {
2200   auto* left = binop->left();
2201   if (IsIntAnnotation(binop)) {
2202     if (auto* left_as_call = left->AsCall()) {
2203       AsmType* type;
2204       RECURSE(type = ValidateCall(AsmType::Signed(), left_as_call));
2205       return type;
2206     }
2207 
2208     // TODO(jpp): at this point we know that binop is expr|0. We could sinply
2209     //
2210     // RECURSE(t = ValidateExpression(left));
2211     // FAIL_IF(t->IsNotA(Intish));
2212     // return Signed;
2213   }
2214 
2215   auto* right = binop->right();
2216   AsmType* left_type;
2217   AsmType* right_type;
2218   RECURSE(left_type = ValidateExpression(left));
2219   RECURSE(right_type = ValidateExpression(right));
2220 
2221   if (binop->op() != Token::BIT_OR) {
2222     FAIL(binop, "Invalid | expression.");
2223   }
2224 
2225 #define BINOP_OVERLOAD(Src0, Src1, Dest)                                       \
2226   do {                                                                         \
2227     if (left_type->IsA(AsmType::Src0()) && right_type->IsA(AsmType::Src1())) { \
2228       return AsmType::Dest();                                                  \
2229     }                                                                          \
2230   } while (0)
2231   BINOP_OVERLOAD(Intish, Intish, Signed);
2232   FAIL(binop, "Invalid operands for |.");
2233 #undef BINOP_OVERLOAD
2234 
2235   UNREACHABLE();
2236 }
2237 
2238 // 6.8.16 ConditionalExpression
ValidateConditionalExpression(Conditional * cond)2239 AsmType* AsmTyper::ValidateConditionalExpression(Conditional* cond) {
2240   AsmType* cond_type;
2241   RECURSE(cond_type = ValidateExpression(cond->condition()));
2242   if (!cond_type->IsA(AsmType::Int())) {
2243     FAIL(cond, "Ternary operation condition should be int.");
2244   }
2245 
2246   AsmType* then_type;
2247   RECURSE(then_type = ValidateExpression(cond->then_expression()));
2248   AsmType* else_type;
2249   RECURSE(else_type = ValidateExpression(cond->else_expression()));
2250 
2251 #define SUCCEED_IF_BOTH_ARE(type)                                       \
2252   do {                                                                  \
2253     if (then_type->IsA(AsmType::type())) {                              \
2254       if (!else_type->IsA(AsmType::type())) {                           \
2255         FAIL(cond, "Type mismatch for ternary operation result type."); \
2256       }                                                                 \
2257       return AsmType::type();                                           \
2258     }                                                                   \
2259   } while (0)
2260   SUCCEED_IF_BOTH_ARE(Int);
2261   SUCCEED_IF_BOTH_ARE(Float);
2262   SUCCEED_IF_BOTH_ARE(Double);
2263 #undef SUCCEED_IF_BOTH_ARE
2264 
2265   FAIL(cond, "Ternary operator must return int, float, or double.");
2266 }
2267 
2268 // 6.9 ValidateCall
2269 namespace {
ExtractIndirectCallMask(Expression * expr,uint32_t * value)2270 bool ExtractIndirectCallMask(Expression* expr, uint32_t* value) {
2271   auto* as_literal = expr->AsLiteral();
2272   if (as_literal == nullptr) {
2273     return false;
2274   }
2275 
2276   if (as_literal->raw_value()->ContainsDot()) {
2277     return false;
2278   }
2279 
2280   if (!as_literal->value()->ToUint32(value)) {
2281     return false;
2282   }
2283 
2284   return base::bits::IsPowerOfTwo32(1 + *value);
2285 }
2286 }  // namespace
2287 
ValidateCall(AsmType * return_type,Call * call)2288 AsmType* AsmTyper::ValidateCall(AsmType* return_type, Call* call) {
2289   AsmType* float_coercion_type;
2290   RECURSE(float_coercion_type = ValidateFloatCoercion(call));
2291   if (float_coercion_type == AsmType::Float()) {
2292     SetTypeOf(call, AsmType::Float());
2293     return return_type;
2294   }
2295 
2296   // TODO(jpp): we should be able to reuse the args vector's storage space.
2297   ZoneVector<AsmType*> args(zone_);
2298   args.reserve(call->arguments()->length());
2299 
2300   for (auto* arg : *call->arguments()) {
2301     AsmType* arg_type;
2302     RECURSE(arg_type = ValidateExpression(arg));
2303     args.emplace_back(arg_type);
2304   }
2305 
2306   auto* call_expr = call->expression();
2307 
2308   // identifier(Expression...)
2309   if (auto* call_var_proxy = call_expr->AsVariableProxy()) {
2310     auto* call_var_info = Lookup(call_var_proxy->var());
2311 
2312     if (call_var_info == nullptr) {
2313       // We can't fail here: the validator performs a single pass over the AST,
2314       // so it is possible for some calls to be currently unresolved. We eagerly
2315       // add the function to the table of globals.
2316       auto* call_type = AsmType::Function(zone_, return_type)->AsFunctionType();
2317       for (auto* arg : args) {
2318         call_type->AddArgument(arg->ToParameterType());
2319       }
2320       auto* fun_info =
2321           new (zone_) VariableInfo(reinterpret_cast<AsmType*>(call_type));
2322       fun_info->set_mutability(VariableInfo::kImmutableGlobal);
2323       AddForwardReference(call_var_proxy, fun_info);
2324       if (!ValidAsmIdentifier(call_var_proxy->name())) {
2325         FAIL(call_var_proxy,
2326              "Invalid asm.js identifier in (forward) function name.");
2327       }
2328       if (!AddGlobal(call_var_proxy->var(), fun_info)) {
2329         DCHECK(false);
2330         FAIL(call, "Redeclared global identifier.");
2331       }
2332       SetTypeOf(call_var_proxy, reinterpret_cast<AsmType*>(call_type));
2333       SetTypeOf(call, return_type);
2334       return return_type;
2335     }
2336 
2337     auto* callee_type = call_var_info->type()->AsCallableType();
2338     if (callee_type == nullptr) {
2339       FAIL(call, "Calling something that's not a function.");
2340     }
2341 
2342     if (callee_type->AsFFIType() != nullptr) {
2343       if (return_type == AsmType::Float()) {
2344         FAIL(call, "Foreign functions can't return float.");
2345       }
2346       // Record FFI use signature, since the asm->wasm translator must know
2347       // all uses up-front.
2348       ffi_use_signatures_.emplace_back(
2349           FFIUseSignature(call_var_proxy->var(), zone_));
2350       FFIUseSignature* sig = &ffi_use_signatures_.back();
2351       sig->return_type_ = return_type;
2352       sig->arg_types_.reserve(args.size());
2353       for (size_t i = 0; i < args.size(); ++i) {
2354         sig->arg_types_.emplace_back(args[i]);
2355       }
2356     }
2357 
2358     if (!callee_type->CanBeInvokedWith(return_type, args)) {
2359       FAIL(call, "Function invocation does not match function type.");
2360     }
2361 
2362     SetTypeOf(call_var_proxy, call_var_info->type());
2363     SetTypeOf(call, return_type);
2364     return return_type;
2365   }
2366 
2367   // identifier[expr & n](Expression...)
2368   if (auto* call_property = call_expr->AsProperty()) {
2369     auto* index = call_property->key()->AsBinaryOperation();
2370     if (index == nullptr || index->op() != Token::BIT_AND) {
2371       FAIL(call_property->key(),
2372            "Indirect call index must be in the expr & mask form.");
2373     }
2374 
2375     auto* left = index->left();
2376     auto* right = index->right();
2377     uint32_t mask;
2378     if (!ExtractIndirectCallMask(right, &mask)) {
2379       if (!ExtractIndirectCallMask(left, &mask)) {
2380         FAIL(right, "Invalid indirect call mask.");
2381       } else {
2382         left = right;
2383       }
2384     }
2385     const uint32_t table_length = mask + 1;
2386 
2387     AsmType* left_type;
2388     RECURSE(left_type = ValidateExpression(left));
2389     if (!left_type->IsA(AsmType::Intish())) {
2390       FAIL(left, "Indirect call index should be an intish.");
2391     }
2392 
2393     auto* name_var = call_property->obj()->AsVariableProxy();
2394 
2395     if (name_var == nullptr) {
2396       FAIL(call_property, "Invalid call.");
2397     }
2398 
2399     auto* name_info = Lookup(name_var->var());
2400     if (name_info == nullptr) {
2401       // We can't fail here -- just like above.
2402       auto* call_type = AsmType::Function(zone_, return_type)->AsFunctionType();
2403       for (auto* arg : args) {
2404         call_type->AddArgument(arg->ToParameterType());
2405       }
2406       auto* table_type = AsmType::FunctionTableType(
2407           zone_, table_length, reinterpret_cast<AsmType*>(call_type));
2408       auto* fun_info =
2409           new (zone_) VariableInfo(reinterpret_cast<AsmType*>(table_type));
2410       fun_info->set_mutability(VariableInfo::kImmutableGlobal);
2411       AddForwardReference(name_var, fun_info);
2412       if (!ValidAsmIdentifier(name_var->name())) {
2413         FAIL(name_var,
2414              "Invalid asm.js identifier in (forward) function table name.");
2415       }
2416       if (!AddGlobal(name_var->var(), fun_info)) {
2417         DCHECK(false);
2418         FAIL(call, "Redeclared global identifier.");
2419       }
2420       SetTypeOf(call_property, reinterpret_cast<AsmType*>(call_type));
2421       SetTypeOf(call, return_type);
2422       return return_type;
2423     }
2424 
2425     auto* previous_type = name_info->type()->AsFunctionTableType();
2426     if (previous_type == nullptr) {
2427       FAIL(call, "Identifier does not name a function table.");
2428     }
2429 
2430     if (table_length != previous_type->length()) {
2431       FAIL(call, "Function table size does not match expected size.");
2432     }
2433 
2434     auto* previous_type_signature =
2435         previous_type->signature()->AsFunctionType();
2436     DCHECK(previous_type_signature != nullptr);
2437     if (!previous_type_signature->CanBeInvokedWith(return_type, args)) {
2438       // TODO(jpp): better error messages.
2439       FAIL(call,
2440            "Function pointer table signature does not match previous "
2441            "signature.");
2442     }
2443 
2444     SetTypeOf(call_property, previous_type->signature());
2445     SetTypeOf(call, return_type);
2446     return return_type;
2447   }
2448 
2449   FAIL(call, "Invalid call.");
2450 }
2451 
2452 // 6.10 ValidateHeapAccess
2453 namespace {
ExtractHeapAccessShift(Expression * expr,uint32_t * value)2454 bool ExtractHeapAccessShift(Expression* expr, uint32_t* value) {
2455   auto* as_literal = expr->AsLiteral();
2456   if (as_literal == nullptr) {
2457     return false;
2458   }
2459 
2460   if (as_literal->raw_value()->ContainsDot()) {
2461     return false;
2462   }
2463 
2464   return as_literal->value()->ToUint32(value);
2465 }
2466 
2467 // Returns whether index is too large to access a heap with the given type.
LiteralIndexOutOfBounds(AsmType * obj_type,uint32_t index)2468 bool LiteralIndexOutOfBounds(AsmType* obj_type, uint32_t index) {
2469   switch (obj_type->ElementSizeInBytes()) {
2470     case 1:
2471       return false;
2472     case 2:
2473       return (index & 0x80000000u) != 0;
2474     case 4:
2475       return (index & 0xC0000000u) != 0;
2476     case 8:
2477       return (index & 0xE0000000u) != 0;
2478   }
2479   UNREACHABLE();
2480   return true;
2481 }
2482 
2483 }  // namespace
2484 
ValidateHeapAccess(Property * heap,HeapAccessType access_type)2485 AsmType* AsmTyper::ValidateHeapAccess(Property* heap,
2486                                       HeapAccessType access_type) {
2487   auto* obj = heap->obj()->AsVariableProxy();
2488   if (obj == nullptr) {
2489     FAIL(heap, "Invalid heap access.");
2490   }
2491 
2492   auto* obj_info = Lookup(obj->var());
2493   if (obj_info == nullptr) {
2494     FAIL(heap, "Undeclared identifier in heap access.");
2495   }
2496 
2497   auto* obj_type = obj_info->type();
2498   if (!obj_type->IsA(AsmType::Heap())) {
2499     FAIL(heap, "Identifier does not represent a heap view.");
2500   }
2501   SetTypeOf(obj, obj_type);
2502 
2503   if (auto* key_as_literal = heap->key()->AsLiteral()) {
2504     if (key_as_literal->raw_value()->ContainsDot()) {
2505       FAIL(key_as_literal, "Heap access index must be int.");
2506     }
2507 
2508     uint32_t index;
2509     if (!key_as_literal->value()->ToUint32(&index)) {
2510       FAIL(key_as_literal,
2511            "Heap access index must be a 32-bit unsigned integer.");
2512     }
2513 
2514     if (LiteralIndexOutOfBounds(obj_type, index)) {
2515       FAIL(key_as_literal, "Heap access index is out of bounds");
2516     }
2517 
2518     if (access_type == LoadFromHeap) {
2519       return obj_type->LoadType();
2520     }
2521     return obj_type->StoreType();
2522   }
2523 
2524   if (auto* key_as_binop = heap->key()->AsBinaryOperation()) {
2525     uint32_t shift;
2526     if (key_as_binop->op() == Token::SAR &&
2527         ExtractHeapAccessShift(key_as_binop->right(), &shift) &&
2528         (1 << shift) == obj_type->ElementSizeInBytes()) {
2529       AsmType* type;
2530       RECURSE(type = ValidateExpression(key_as_binop->left()));
2531       if (type->IsA(AsmType::Intish())) {
2532         if (access_type == LoadFromHeap) {
2533           return obj_type->LoadType();
2534         }
2535         return obj_type->StoreType();
2536       }
2537       FAIL(key_as_binop, "Invalid heap access index.");
2538     }
2539   }
2540 
2541   if (obj_type->ElementSizeInBytes() == 1) {
2542     // Leniency: if this is a byte array, we don't require the shift operation
2543     // to be present.
2544     AsmType* index_type;
2545     RECURSE(index_type = ValidateExpression(heap->key()));
2546     if (!index_type->IsA(AsmType::Int())) {
2547       FAIL(heap, "Invalid heap access index for byte array.");
2548     }
2549     if (access_type == LoadFromHeap) {
2550       return obj_type->LoadType();
2551     }
2552     return obj_type->StoreType();
2553   }
2554 
2555   FAIL(heap, "Invalid heap access index.");
2556 }
2557 
2558 // 6.11 ValidateFloatCoercion
IsCallToFround(Call * call)2559 bool AsmTyper::IsCallToFround(Call* call) {
2560   if (call->arguments()->length() != 1) {
2561     return false;
2562   }
2563 
2564   auto* call_var_proxy = call->expression()->AsVariableProxy();
2565   if (call_var_proxy == nullptr) {
2566     return false;
2567   }
2568 
2569   auto* call_var_info = Lookup(call_var_proxy->var());
2570   if (call_var_info == nullptr) {
2571     return false;
2572   }
2573 
2574   return call_var_info->standard_member() == kMathFround;
2575 }
2576 
ValidateFloatCoercion(Call * call)2577 AsmType* AsmTyper::ValidateFloatCoercion(Call* call) {
2578   if (!IsCallToFround(call)) {
2579     return nullptr;
2580   }
2581 
2582   auto* arg = call->arguments()->at(0);
2583   // call is a fround() node. From now, there can be two possible outcomes:
2584   // 1. fround is used as a return type annotation.
2585   if (auto* arg_as_call = arg->AsCall()) {
2586     RECURSE(ValidateCall(AsmType::Float(), arg_as_call));
2587     return AsmType::Float();
2588   }
2589 
2590   // 2. fround is used for converting to float.
2591   AsmType* arg_type;
2592   RECURSE(arg_type = ValidateExpression(arg));
2593   if (arg_type->IsA(AsmType::Floatish()) || arg_type->IsA(AsmType::DoubleQ()) ||
2594       arg_type->IsA(AsmType::Signed()) || arg_type->IsA(AsmType::Unsigned())) {
2595     SetTypeOf(call->expression(), fround_type_);
2596     return AsmType::Float();
2597   }
2598 
2599   FAIL(call, "Invalid argument type to fround.");
2600 }
2601 
2602 // 5.1 ParameterTypeAnnotations
ParameterTypeAnnotations(Variable * parameter,Expression * annotation)2603 AsmType* AsmTyper::ParameterTypeAnnotations(Variable* parameter,
2604                                             Expression* annotation) {
2605   if (auto* binop = annotation->AsBinaryOperation()) {
2606     // Must be:
2607     //   * x|0
2608     //   * x*1 (*VIOLATION* i.e.,, +x)
2609     auto* left = binop->left()->AsVariableProxy();
2610     if (left == nullptr) {
2611       FAIL(
2612           binop->left(),
2613           "Invalid parameter type annotation - should annotate an identifier.");
2614     }
2615     if (left->var() != parameter) {
2616       FAIL(binop->left(),
2617            "Invalid parameter type annotation - should annotate a parameter.");
2618     }
2619     if (IsDoubleAnnotation(binop)) {
2620       SetTypeOf(left, AsmType::Double());
2621       return AsmType::Double();
2622     }
2623     if (IsIntAnnotation(binop)) {
2624       SetTypeOf(left, AsmType::Int());
2625       return AsmType::Int();
2626     }
2627     FAIL(binop, "Invalid parameter type annotation.");
2628   }
2629 
2630   auto* call = annotation->AsCall();
2631   if (call == nullptr) {
2632     FAIL(
2633         annotation,
2634         "Invalid float parameter type annotation - must be fround(parameter).");
2635   }
2636 
2637   if (!IsCallToFround(call)) {
2638     FAIL(annotation,
2639          "Invalid float parameter type annotation - must be call to fround.");
2640   }
2641 
2642   auto* src_expr = call->arguments()->at(0)->AsVariableProxy();
2643   if (src_expr == nullptr) {
2644     FAIL(annotation,
2645          "Invalid float parameter type annotation - argument to fround is not "
2646          "an identifier.");
2647   }
2648 
2649   if (src_expr->var() != parameter) {
2650     FAIL(annotation,
2651          "Invalid float parameter type annotation - argument to fround is not "
2652          "a parameter.");
2653   }
2654 
2655   SetTypeOf(src_expr, AsmType::Float());
2656   return AsmType::Float();
2657 }
2658 
2659 // 5.2 ReturnTypeAnnotations
ReturnTypeAnnotations(ReturnStatement * statement)2660 AsmType* AsmTyper::ReturnTypeAnnotations(ReturnStatement* statement) {
2661   if (statement == nullptr) {
2662     return AsmType::Void();
2663   }
2664 
2665   auto* ret_expr = statement->expression();
2666   if (ret_expr == nullptr) {
2667     return AsmType::Void();
2668   }
2669 
2670   if (auto* binop = ret_expr->AsBinaryOperation()) {
2671     if (IsDoubleAnnotation(binop)) {
2672       return AsmType::Double();
2673     } else if (IsIntAnnotation(binop)) {
2674       return AsmType::Signed();
2675     }
2676     FAIL(statement, "Invalid return type annotation.");
2677   }
2678 
2679   if (auto* call = ret_expr->AsCall()) {
2680     if (IsCallToFround(call)) {
2681       return AsmType::Float();
2682     }
2683     FAIL(statement, "Invalid function call in return statement.");
2684   }
2685 
2686   if (auto* literal = ret_expr->AsLiteral()) {
2687     int32_t _;
2688     if (literal->raw_value()->ContainsDot()) {
2689       return AsmType::Double();
2690     } else if (literal->value()->ToInt32(&_)) {
2691       return AsmType::Signed();
2692     } else if (literal->IsUndefinedLiteral()) {
2693       // *VIOLATION* The parser changes
2694       //
2695       // return;
2696       //
2697       // into
2698       //
2699       // return undefined
2700       return AsmType::Void();
2701     }
2702     FAIL(statement, "Invalid literal in return statement.");
2703   }
2704 
2705   if (auto* proxy = ret_expr->AsVariableProxy()) {
2706     auto* var_info = Lookup(proxy->var());
2707 
2708     if (var_info == nullptr) {
2709       FAIL(statement, "Undeclared identifier in return statement.");
2710     }
2711 
2712     if (var_info->mutability() != VariableInfo::kConstGlobal) {
2713       FAIL(statement, "Identifier in return statement is not const.");
2714     }
2715 
2716     if (!var_info->type()->IsReturnType()) {
2717       FAIL(statement, "Constant in return must be signed, float, or double.");
2718     }
2719 
2720     return var_info->type();
2721   }
2722 
2723   FAIL(statement, "Invalid return type expression.");
2724 }
2725 
2726 // 5.4 VariableTypeAnnotations
2727 // Also used for 5.5 GlobalVariableTypeAnnotations
VariableTypeAnnotations(Expression * initializer,VariableInfo::Mutability mutability_type)2728 AsmType* AsmTyper::VariableTypeAnnotations(
2729     Expression* initializer, VariableInfo::Mutability mutability_type) {
2730   if (auto* literal = initializer->AsLiteral()) {
2731     if (literal->raw_value()->ContainsDot()) {
2732       SetTypeOf(initializer, AsmType::Double());
2733       return AsmType::Double();
2734     }
2735     int32_t i32;
2736     uint32_t u32;
2737 
2738     AsmType* initializer_type = nullptr;
2739     if (literal->value()->ToUint32(&u32)) {
2740       if (u32 > LargestFixNum) {
2741         initializer_type = AsmType::Unsigned();
2742         SetTypeOf(initializer, initializer_type);
2743       } else {
2744         initializer_type = AsmType::FixNum();
2745         SetTypeOf(initializer, initializer_type);
2746         initializer_type = AsmType::Signed();
2747       }
2748     } else if (literal->value()->ToInt32(&i32)) {
2749       initializer_type = AsmType::Signed();
2750       SetTypeOf(initializer, initializer_type);
2751     } else {
2752       FAIL(initializer, "Invalid type annotation - forbidden literal.");
2753     }
2754     if (mutability_type != VariableInfo::kConstGlobal) {
2755       return AsmType::Int();
2756     }
2757     return initializer_type;
2758   }
2759 
2760   if (auto* proxy = initializer->AsVariableProxy()) {
2761     auto* var_info = Lookup(proxy->var());
2762 
2763     if (var_info == nullptr) {
2764       FAIL(initializer,
2765            "Undeclared identifier in variable declaration initializer.");
2766     }
2767 
2768     if (var_info->mutability() != VariableInfo::kConstGlobal) {
2769       FAIL(initializer,
2770            "Identifier in variable declaration initializer must be const.");
2771     }
2772 
2773     SetTypeOf(initializer, var_info->type());
2774     return var_info->type();
2775   }
2776 
2777   auto* call = initializer->AsCall();
2778   if (call == nullptr) {
2779     FAIL(initializer,
2780          "Invalid variable initialization - it should be a literal, const, or "
2781          "fround(literal).");
2782   }
2783 
2784   if (!IsCallToFround(call)) {
2785     FAIL(initializer,
2786          "Invalid float coercion - expected call fround(literal).");
2787   }
2788 
2789   auto* src_expr = call->arguments()->at(0)->AsLiteral();
2790   if (src_expr == nullptr) {
2791     FAIL(initializer,
2792          "Invalid float type annotation - expected literal argument for call "
2793          "to fround.");
2794   }
2795 
2796   // Float constants must contain dots in local, but not in globals.
2797   if (mutability_type == VariableInfo::kLocal) {
2798     if (!src_expr->raw_value()->ContainsDot()) {
2799       FAIL(initializer,
2800            "Invalid float type annotation - expected literal argument to be a "
2801            "floating point literal.");
2802     }
2803   }
2804 
2805   return AsmType::Float();
2806 }
2807 
2808 // 5.5 GlobalVariableTypeAnnotations
NewHeapView(CallNew * new_heap_view)2809 AsmType* AsmTyper::NewHeapView(CallNew* new_heap_view) {
2810   auto* heap_type = new_heap_view->expression()->AsProperty();
2811   if (heap_type == nullptr) {
2812     FAIL(new_heap_view, "Invalid type after new.");
2813   }
2814   auto* heap_view_info = ImportLookup(heap_type);
2815 
2816   if (heap_view_info == nullptr) {
2817     FAIL(new_heap_view, "Unknown stdlib member in heap view declaration.");
2818   }
2819 
2820   if (!heap_view_info->type()->IsA(AsmType::Heap())) {
2821     FAIL(new_heap_view, "Type is not a heap view type.");
2822   }
2823 
2824   if (new_heap_view->arguments()->length() != 1) {
2825     FAIL(new_heap_view, "Invalid number of arguments when creating heap view.");
2826   }
2827 
2828   auto* heap = new_heap_view->arguments()->at(0);
2829   auto* heap_var_proxy = heap->AsVariableProxy();
2830 
2831   if (heap_var_proxy == nullptr) {
2832     FAIL(heap,
2833          "Heap view creation parameter should be the module's heap parameter.");
2834   }
2835 
2836   auto* heap_var_info = Lookup(heap_var_proxy->var());
2837 
2838   if (heap_var_info == nullptr) {
2839     FAIL(heap, "Undeclared identifier instead of heap parameter.");
2840   }
2841 
2842   if (!heap_var_info->IsHeap()) {
2843     FAIL(heap,
2844          "Heap view creation parameter should be the module's heap parameter.");
2845   }
2846 
2847   DCHECK(heap_view_info->type()->IsA(AsmType::Heap()));
2848   return heap_view_info->type();
2849 }
2850 
IsValidAsm(Isolate * isolate,Zone * zone,Script * script,FunctionLiteral * root,std::string * error_message)2851 bool IsValidAsm(Isolate* isolate, Zone* zone, Script* script,
2852                 FunctionLiteral* root, std::string* error_message) {
2853   error_message->clear();
2854 
2855   AsmTyper typer(isolate, zone, script, root);
2856   if (typer.Validate()) {
2857     return true;
2858   }
2859 
2860   *error_message = typer.error_message();
2861   return false;
2862 }
2863 
2864 }  // namespace wasm
2865 }  // namespace internal
2866 }  // namespace v8
2867