Home | History | Annotate | Download | only in asmjs
      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 
     62 AsmTyper::FlattenedStatements::FlattenedStatements(Zone* zone,
     63                                                    ZoneList<Statement*>* s)
     64     : context_stack_(zone) {
     65   context_stack_.emplace_back(Context(s));
     66 }
     67 
     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 
     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 
    106 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 
    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 
    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 {
    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 
    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
    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 
    331 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 
    347 void AsmTyper::AddForwardReference(VariableProxy* proxy, VariableInfo* info) {
    348   info->FirstForwardUseIs(proxy);
    349   forward_definitions_.push_back(info);
    350 }
    351 
    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 
    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 
    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 
    397 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 
    425 AsmType* AsmTyper::TypeOf(Variable* v) const { return Lookup(v)->type(); }
    426 
    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 
    436 bool AsmTyper::Validate() {
    437   if (!AsmType::None()->IsExactly(ValidateModule(root_))) {
    438     return true;
    439   }
    440   return false;
    441 }
    442 
    443 namespace {
    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 
    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 
    488   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 
    502   void AddUseAsm(const AstNode& node) { use_asm_.AddNewElement(node); }
    503 
    504   void AddGlobal(const AstNode& node) { globals_.AddNewElement(node); }
    505 
    506   void AddFunction(const AstNode& node) { functions_.AddNewElement(node); }
    507 
    508   void AddTable(const AstNode& node) { tables_.AddNewElement(node); }
    509 
    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 
    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 
    533     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 
    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 {
    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 
    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 
    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
    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 
    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
    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
   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
   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
   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
   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
   1282 AsmType* AsmTyper::ValidateEmptyStatement(EmptyStatement* empty) {
   1283   return AsmType::Void();
   1284 }
   1285 
   1286 // 6.5.4 IfStatement
   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
   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
   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
   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
   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
   1374 AsmType* AsmTyper::ValidateBreakStatement(BreakStatement* brk_stmt) {
   1375   return AsmType::Void();
   1376 }
   1377 
   1378 // 6.5.8 ContinueStatement
   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
   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 {
   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 
   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
   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
   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 
   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 {
   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 
   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 
   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
   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
   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
   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
   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
   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
   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
   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 {
   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 
   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
   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
   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
   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
   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
   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
   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
   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
   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 {
   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 
   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 {
   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.
   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 
   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
   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 
   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
   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
   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
   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
   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 
   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