LCOV - code coverage report
Current view: top level - src/asmjs - asm-typer.cc (source / functions) Hit Total Coverage
Test: app.info Lines: 1098 1168 94.0 %
Date: 2017-04-26 Functions: 88 93 94.6 %

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

Generated by: LCOV version 1.10