Home | History | Annotate | Download | only in asmjs
      1 // Copyright 2016 the V8 project authors. All rights reserved.
      2 // Use of this source code is governed by a BSD-style license that can be
      3 // found in the LICENSE file.
      4 
      5 #include "src/asmjs/asm-typer.h"
      6 
      7 #include <algorithm>
      8 #include <limits>
      9 #include <memory>
     10 #include <string>
     11 
     12 #include "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<JSArray>::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 AsmTyper::FlattenedStatements::FlattenedStatements(Zone* zone,
     80                                                    ZoneList<Statement*>* s)
     81     : context_stack_(zone) {
     82   context_stack_.emplace_back(Context(s));
     83 }
     84 
     85 Statement* AsmTyper::FlattenedStatements::Next() {
     86   for (;;) {
     87     if (context_stack_.empty()) {
     88       return nullptr;
     89     }
     90 
     91     Context* current = &context_stack_.back();
     92 
     93     if (current->statements_->length() <= current->next_index_) {
     94       context_stack_.pop_back();
     95       continue;
     96     }
     97 
     98     Statement* current_statement =
     99         current->statements_->at(current->next_index_++);
    100     if (current_statement->IsBlock()) {
    101       context_stack_.emplace_back(
    102           Context(current_statement->AsBlock()->statements()));
    103       continue;
    104     }
    105 
    106     return current_statement;
    107   }
    108 }
    109 
    110 // ----------------------------------------------------------------------------
    111 // Implementation of AsmTyper::SourceLayoutTracker
    112 
    113 bool AsmTyper::SourceLayoutTracker::IsValid() const {
    114   const Section* kAllSections[] = {&use_asm_, &globals_, &functions_, &tables_,
    115                                    &exports_};
    116   for (size_t ii = 0; ii < arraysize(kAllSections); ++ii) {
    117     const auto& curr_section = *kAllSections[ii];
    118     for (size_t jj = ii + 1; jj < arraysize(kAllSections); ++jj) {
    119       if (curr_section.IsPrecededBy(*kAllSections[jj])) {
    120         return false;
    121       }
    122     }
    123   }
    124   return true;
    125 }
    126 
    127 void AsmTyper::SourceLayoutTracker::Section::AddNewElement(
    128     const AstNode& node) {
    129   const int node_pos = node.position();
    130   if (start_ == kNoSourcePosition) {
    131     start_ = node_pos;
    132   } else {
    133     start_ = std::min(start_, node_pos);
    134   }
    135   if (end_ == kNoSourcePosition) {
    136     end_ = node_pos;
    137   } else {
    138     end_ = std::max(end_, node_pos);
    139   }
    140 }
    141 
    142 bool AsmTyper::SourceLayoutTracker::Section::IsPrecededBy(
    143     const Section& other) const {
    144   if (start_ == kNoSourcePosition) {
    145     DCHECK_EQ(end_, kNoSourcePosition);
    146     return false;
    147   }
    148   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   return other.start_ <= end_;
    155 }
    156 
    157 // ----------------------------------------------------------------------------
    158 // Implementation of AsmTyper::VariableInfo
    159 
    160 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   new_var_info->standard_member_ = standard_member;
    166   new_var_info->mutability_ = kImmutableGlobal;
    167   return new_var_info;
    168 }
    169 
    170 AsmTyper::VariableInfo* AsmTyper::VariableInfo::Clone(Zone* zone) const {
    171   CHECK(standard_member_ != kNone);
    172   CHECK(!type_->IsA(AsmType::None()));
    173   auto* new_var_info = new (zone) VariableInfo(type_);
    174   new_var_info->standard_member_ = standard_member_;
    175   new_var_info->mutability_ = mutability_;
    176   return new_var_info;
    177 }
    178 
    179 void AsmTyper::VariableInfo::SetFirstForwardUse(
    180     const MessageLocation& source_location) {
    181   missing_definition_ = true;
    182   source_location_ = source_location;
    183 }
    184 
    185 // ----------------------------------------------------------------------------
    186 // Implementation of AsmTyper
    187 
    188 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       module_info_(VariableInfo::ForSpecialSymbol(zone_, kModule)),
    199       global_scope_(ZoneHashMap::kDefaultHashMapCapacity,
    200                     ZoneAllocationPolicy(zone)),
    201       local_scope_(ZoneHashMap::kDefaultHashMapCapacity,
    202                    ZoneAllocationPolicy(zone)),
    203       stack_limit_(isolate->stack_guard()->real_climit()),
    204       fround_type_(AsmType::FroundType(zone_)),
    205       ffi_type_(AsmType::FFIType(zone_)),
    206       function_pointer_tables_(zone_) {
    207   InitializeStdlib();
    208 }
    209 
    210 namespace {
    211 bool ValidAsmIdentifier(Handle<String> name) {
    212   static const char* kInvalidAsmNames[] = {"eval", "arguments"};
    213 
    214   for (size_t ii = 0; ii < arraysize(kInvalidAsmNames); ++ii) {
    215     if (strcmp(name->ToCString().get(), kInvalidAsmNames[ii]) == 0) {
    216       return false;
    217     }
    218   }
    219   return true;
    220 }
    221 }  // namespace
    222 
    223 void AsmTyper::InitializeStdlib() {
    224   auto* d = AsmType::Double();
    225   auto* dq = AsmType::DoubleQ();
    226   auto* dq2d = AsmType::Function(zone_, d);
    227   dq2d->AsFunctionType()->AddArgument(dq);
    228 
    229   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   auto* fq2f = AsmType::Function(zone_, f);
    236   fq2f->AsFunctionType()->AddArgument(fq);
    237 
    238   auto* s = AsmType::Signed();
    239   auto* s2s = AsmType::Function(zone_, s);
    240   s2s->AsFunctionType()->AddArgument(s);
    241 
    242   auto* i = AsmType::Int();
    243   auto* i2s = AsmType::Function(zone_, s);
    244   i2s->AsFunctionType()->AddArgument(i);
    245 
    246   auto* ii2s = AsmType::Function(zone_, s);
    247   ii2s->AsFunctionType()->AddArgument(i);
    248   ii2s->AsFunctionType()->AddArgument(i);
    249 
    250   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   auto* minmax_f = AsmType::MinMaxType(zone_, f, f);
    254   auto* minmax_i = AsmType::MinMaxType(zone_, s, i);
    255   auto* minmax = AsmType::OverloadedFunction(zone_);
    256   minmax->AsOverloadedFunctionType()->AddOverload(minmax_i);
    257   minmax->AsOverloadedFunctionType()->AddOverload(minmax_f);
    258   minmax->AsOverloadedFunctionType()->AddOverload(minmax_d);
    259 
    260   auto* fround = fround_type_;
    261 
    262   auto* abs = AsmType::OverloadedFunction(zone_);
    263   abs->AsOverloadedFunctionType()->AddOverload(s2s);
    264   abs->AsOverloadedFunctionType()->AddOverload(dq2d);
    265   abs->AsOverloadedFunctionType()->AddOverload(fq2f);
    266 
    267   auto* ceil = AsmType::OverloadedFunction(zone_);
    268   ceil->AsOverloadedFunctionType()->AddOverload(dq2d);
    269   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   };
    297   for (size_t ii = 0; ii < arraysize(stdlib); ++ii) {
    298     stdlib_types_[stdlib[ii].name] = new (zone_) VariableInfo(stdlib[ii].type);
    299     stdlib_types_[stdlib[ii].name]->set_standard_member(
    300         stdlib[ii].standard_member);
    301     stdlib_types_[stdlib[ii].name]->set_mutability(
    302         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   };
    337   for (size_t ii = 0; ii < arraysize(math); ++ii) {
    338     stdlib_math_types_[math[ii].name] = new (zone_) VariableInfo(math[ii].type);
    339     stdlib_math_types_[math[ii].name]->set_standard_member(
    340         math[ii].standard_member);
    341     stdlib_math_types_[math[ii].name]->set_mutability(
    342         VariableInfo::kImmutableGlobal);
    343   }
    344 }
    345 
    346 // Used for 5.5 GlobalVariableTypeAnnotations
    347 AsmTyper::VariableInfo* AsmTyper::ImportLookup(Property* import) {
    348   auto* obj = import->obj();
    349   auto* key = import->key()->AsLiteral();
    350   if (key == nullptr) {
    351     return nullptr;
    352   }
    353 
    354   ObjectTypeMap* stdlib = &stdlib_types_;
    355   if (auto* obj_as_property = obj->AsProperty()) {
    356     // This can only be stdlib.Math
    357     auto* math_name = obj_as_property->key()->AsLiteral();
    358     if (math_name == nullptr || !math_name->IsPropertyName()) {
    359       return nullptr;
    360     }
    361 
    362     if (!math_name->AsPropertyName()->IsUtf8EqualTo(CStrVector("Math"))) {
    363       return nullptr;
    364     }
    365 
    366     auto* stdlib_var_proxy = obj_as_property->obj()->AsVariableProxy();
    367     if (stdlib_var_proxy == nullptr) {
    368       return nullptr;
    369     }
    370     obj = stdlib_var_proxy;
    371     stdlib = &stdlib_math_types_;
    372   }
    373 
    374   auto* obj_as_var_proxy = obj->AsVariableProxy();
    375   if (obj_as_var_proxy == nullptr) {
    376     return nullptr;
    377   }
    378 
    379   auto* obj_info = Lookup(obj_as_var_proxy->var());
    380   if (obj_info == nullptr) {
    381     return nullptr;
    382   }
    383 
    384   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   if (!key->IsPropertyName()) {
    390     return nullptr;
    391   }
    392 
    393   std::unique_ptr<char[]> aname = key->AsPropertyName()->ToCString();
    394   ObjectTypeMap::iterator i = stdlib->find(std::string(aname.get()));
    395   if (i == stdlib->end()) {
    396     return nullptr;
    397   }
    398   stdlib_uses_.insert(i->second->standard_member());
    399   return i->second;
    400 }
    401 
    402 AsmTyper::VariableInfo* AsmTyper::Lookup(Variable* variable) const {
    403   const ZoneHashMap* scope = in_function_ ? &local_scope_ : &global_scope_;
    404   ZoneHashMap::Entry* entry =
    405       scope->Lookup(variable, ComputePointerHash(variable));
    406   if (entry == nullptr && in_function_) {
    407     entry = global_scope_.Lookup(variable, ComputePointerHash(variable));
    408   }
    409 
    410   if (entry == nullptr && !module_name_.is_null() &&
    411       module_name_->Equals(*variable->name())) {
    412     return module_info_;
    413   }
    414 
    415   return entry ? reinterpret_cast<VariableInfo*>(entry->value) : nullptr;
    416 }
    417 
    418 void AsmTyper::AddForwardReference(VariableProxy* proxy, VariableInfo* info) {
    419   MessageLocation location(script_, proxy->position(), proxy->position());
    420   info->SetFirstForwardUse(location);
    421   forward_definitions_.push_back(info);
    422 }
    423 
    424 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   if (!module_name_.is_null() && module_name_->Equals(*variable->name())) {
    432     return false;
    433   }
    434 
    435   ZoneHashMap::Entry* entry = global_scope_.LookupOrInsert(
    436       variable, ComputePointerHash(variable), ZoneAllocationPolicy(zone_));
    437 
    438   if (entry->value != nullptr) {
    439     return false;
    440   }
    441 
    442   entry->value = info;
    443   return true;
    444 }
    445 
    446 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       variable, ComputePointerHash(variable), ZoneAllocationPolicy(zone_));
    454 
    455   if (entry->value != nullptr) {
    456     return false;
    457   }
    458 
    459   entry->value = info;
    460   return true;
    461 }
    462 
    463 void AsmTyper::SetTypeOf(AstNode* node, AsmType* type) {
    464   DCHECK_NE(type, AsmType::None());
    465   if (in_function_) {
    466     DCHECK(function_node_types_.find(node) == function_node_types_.end());
    467     function_node_types_.insert(std::make_pair(node, type));
    468   } else {
    469     DCHECK(module_node_types_.find(node) == module_node_types_.end());
    470     module_node_types_.insert(std::make_pair(node, type));
    471   }
    472 }
    473 
    474 namespace {
    475 bool IsLiteralDouble(Literal* literal) {
    476   return literal->raw_value()->IsNumber() &&
    477          literal->raw_value()->ContainsDot();
    478 }
    479 
    480 bool IsLiteralInt(Literal* literal) {
    481   return literal->raw_value()->IsNumber() &&
    482          !literal->raw_value()->ContainsDot();
    483 }
    484 
    485 bool IsLiteralMinus1(Literal* literal) {
    486   return IsLiteralInt(literal) && literal->raw_value()->AsNumber() == -1.0;
    487 }
    488 
    489 bool IsLiteral1Dot0(Literal* literal) {
    490   return IsLiteralDouble(literal) && literal->raw_value()->AsNumber() == 1.0;
    491 }
    492 
    493 bool IsLiteral0(Literal* literal) {
    494   return IsLiteralInt(literal) && literal->raw_value()->AsNumber() == 0.0;
    495 }
    496 }  // namespace
    497 
    498 AsmType* AsmTyper::TypeOf(AstNode* node) const {
    499   auto node_type_iter = function_node_types_.find(node);
    500   if (node_type_iter != function_node_types_.end()) {
    501     return node_type_iter->second;
    502   }
    503   node_type_iter = module_node_types_.find(node);
    504   if (node_type_iter != module_node_types_.end()) {
    505     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   if (auto* literal = node->AsLiteral()) {
    511     if (IsLiteralDouble(literal)) {
    512       return AsmType::Double();
    513     }
    514     if (!IsLiteralInt(literal)) {
    515       return AsmType::None();
    516     }
    517     uint32_t u;
    518     if (literal->value()->ToUint32(&u)) {
    519       if (u > LargestFixNum) {
    520         return AsmType::Unsigned();
    521       }
    522       return AsmType::FixNum();
    523     }
    524     int32_t i;
    525     if (literal->value()->ToInt32(&i)) {
    526       return AsmType::Signed();
    527     }
    528   }
    529 
    530   return AsmType::None();
    531 }
    532 
    533 AsmType* AsmTyper::TypeOf(Variable* v) const { return Lookup(v)->type(); }
    534 
    535 AsmTyper::StandardMember AsmTyper::VariableAsStandardMember(Variable* var) {
    536   auto* var_info = Lookup(var);
    537   if (var_info == nullptr) {
    538     return kNone;
    539   }
    540   StandardMember member = var_info->standard_member();
    541   return member;
    542 }
    543 
    544 AsmType* AsmTyper::FailWithMessage(const char* text) {
    545   FAIL_RAW(root_, OneByteVector(text));
    546 }
    547 
    548 bool AsmTyper::Validate() {
    549   return ValidateBeforeFunctionsPhase() &&
    550          !AsmType::None()->IsExactly(ValidateModuleFunctions(root_)) &&
    551          ValidateAfterFunctionsPhase();
    552 }
    553 
    554 bool AsmTyper::ValidateBeforeFunctionsPhase() {
    555   if (!AsmType::None()->IsExactly(ValidateModuleBeforeFunctionsPhase(root_))) {
    556     return true;
    557   }
    558   return false;
    559 }
    560 
    561 bool AsmTyper::ValidateInnerFunction(FunctionDeclaration* fun_decl) {
    562   if (!AsmType::None()->IsExactly(ValidateModuleFunction(fun_decl))) {
    563     return true;
    564   }
    565   return false;
    566 }
    567 
    568 bool AsmTyper::ValidateAfterFunctionsPhase() {
    569   if (!AsmType::None()->IsExactly(ValidateModuleAfterFunctionsPhase(root_))) {
    570     return true;
    571   }
    572   return false;
    573 }
    574 
    575 void AsmTyper::ClearFunctionNodeTypes() { function_node_types_.clear(); }
    576 
    577 AsmType* AsmTyper::TriggerParsingError() { FAIL(root_, "Parsing error"); }
    578 
    579 namespace {
    580 bool IsUseAsmDirective(Statement* first_statement) {
    581   ExpressionStatement* use_asm = first_statement->AsExpressionStatement();
    582   if (use_asm == nullptr) {
    583     return false;
    584   }
    585 
    586   Literal* use_asm_literal = use_asm->expression()->AsLiteral();
    587 
    588   if (use_asm_literal == nullptr) {
    589     return false;
    590   }
    591 
    592   return use_asm_literal->raw_value()->AsString()->IsOneByteEqualTo("use asm");
    593 }
    594 
    595 Assignment* ExtractInitializerExpression(Statement* statement) {
    596   auto* expr_stmt = statement->AsExpressionStatement();
    597   if (expr_stmt == nullptr) {
    598     // Done with initializers.
    599     return nullptr;
    600   }
    601   auto* assign = expr_stmt->expression()->AsAssignment();
    602   if (assign == nullptr) {
    603     // Done with initializers.
    604     return nullptr;
    605   }
    606   if (assign->op() != Token::INIT) {
    607     // Done with initializers.
    608     return nullptr;
    609   }
    610   return assign;
    611 }
    612 
    613 }  // namespace
    614 
    615 // 6.1 ValidateModule
    616 AsmType* AsmTyper::ValidateModuleBeforeFunctionsPhase(FunctionLiteral* fun) {
    617   DeclarationScope* scope = fun->scope();
    618   if (!scope->is_function_scope()) FAIL(fun, "Not at function scope.");
    619   if (scope->inner_scope_calls_eval()) {
    620     FAIL(fun, "Invalid asm.js module using eval.");
    621   }
    622   if (!ValidAsmIdentifier(fun->name()))
    623     FAIL(fun, "Invalid asm.js identifier in module name.");
    624   module_name_ = fun->name();
    625 
    626   // Allowed parameters: Stdlib, FFI, Mem
    627   static const int MaxModuleParameters = 3;
    628   if (scope->num_parameters() > MaxModuleParameters) {
    629     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   };
    637 
    638   for (int ii = 0; ii < scope->num_parameters(); ++ii) {
    639     Variable* param = scope->parameter(ii);
    640     DCHECK(param);
    641 
    642     if (!ValidAsmIdentifier(param->name())) {
    643       FAIL(fun, "Invalid asm.js identifier in module parameter.");
    644     }
    645 
    646     auto* param_info = VariableInfo::ForSpecialSymbol(
    647         zone_, kModuleParamInfo[ii].standard_member);
    648 
    649     if (!AddGlobal(param, param_info)) {
    650       FAIL(fun, "Redeclared identifier in module parameter.");
    651     }
    652   }
    653 
    654   FlattenedStatements iter(zone_, fun->body());
    655   auto* use_asm_directive = iter.Next();
    656   if (use_asm_directive == nullptr) {
    657     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   ExpressionStatement* estatement = use_asm_directive->AsExpressionStatement();
    662   if (estatement != nullptr) {
    663     Assignment* assignment = estatement->expression()->AsAssignment();
    664     if (assignment != nullptr && assignment->target()->IsVariableProxy() &&
    665         assignment->target()
    666             ->AsVariableProxy()
    667             ->var()
    668             ->is_sloppy_function_name()) {
    669       use_asm_directive = iter.Next();
    670     }
    671   }
    672   if (!IsUseAsmDirective(use_asm_directive)) {
    673     FAIL(fun, "Missing \"use asm\".");
    674   }
    675   source_layout_.AddUseAsm(*use_asm_directive);
    676   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   while (Statement* current = iter.Next()) {
    683     if (auto* assign = ExtractInitializerExpression(current)) {
    684       if (assign->value()->IsArrayLiteral()) {
    685         // Save function tables for later validation.
    686         function_pointer_tables_.push_back(assign);
    687       } else {
    688         RECURSE(ValidateGlobalDeclaration(assign));
    689         source_layout_.AddGlobal(*assign);
    690       }
    691       continue;
    692     }
    693 
    694     if (auto* current_as_return = current->AsReturnStatement()) {
    695       if (module_return_ != nullptr) {
    696         FAIL(fun, "Multiple export statements.");
    697       }
    698       module_return_ = current_as_return;
    699       source_layout_.AddExport(*module_return_);
    700       continue;
    701     }
    702 
    703     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 AsmType* AsmTyper::ValidateModuleFunction(FunctionDeclaration* fun_decl) {
    710   RECURSE(ValidateFunction(fun_decl));
    711   source_layout_.AddFunction(*fun_decl);
    712 
    713   return AsmType::Int();  // Any type that is not AsmType::None();
    714 }
    715 
    716 AsmType* AsmTyper::ValidateModuleFunctions(FunctionLiteral* fun) {
    717   DeclarationScope* scope = fun->scope();
    718   Declaration::List* decls = scope->declarations();
    719   for (Declaration* decl : *decls) {
    720     if (FunctionDeclaration* fun_decl = decl->AsFunctionDeclaration()) {
    721       RECURSE(ValidateModuleFunction(fun_decl));
    722       continue;
    723     }
    724   }
    725 
    726   return AsmType::Int();  // Any type that is not AsmType::None();
    727 }
    728 
    729 AsmType* AsmTyper::ValidateModuleAfterFunctionsPhase(FunctionLiteral* fun) {
    730   for (auto* function_table : function_pointer_tables_) {
    731     RECURSE(ValidateFunctionTable(function_table));
    732     source_layout_.AddTable(*function_table);
    733   }
    734 
    735   DeclarationScope* scope = fun->scope();
    736   Declaration::List* decls = scope->declarations();
    737   for (Declaration* decl : *decls) {
    738     if (decl->IsFunctionDeclaration()) {
    739       continue;
    740     }
    741 
    742     VariableDeclaration* var_decl = decl->AsVariableDeclaration();
    743     if (var_decl == nullptr) {
    744       FAIL(decl, "Invalid asm.js declaration.");
    745     }
    746 
    747     auto* var_proxy = var_decl->proxy();
    748     if (var_proxy == nullptr) {
    749       FAIL(decl, "Invalid asm.js declaration.");
    750     }
    751 
    752     if (Lookup(var_proxy->var()) == nullptr) {
    753       FAIL(decl, "Global variable missing initializer in asm.js module.");
    754     }
    755   }
    756 
    757   // 6.2 ValidateExport
    758   if (module_return_ == nullptr) {
    759     FAIL(fun, "Missing asm.js module export.");
    760   }
    761 
    762   for (auto* forward_def : forward_definitions_) {
    763     if (forward_def->missing_definition()) {
    764       FAIL_LOCATION(forward_def->source_location(),
    765                     "Missing definition for forward declared identifier.");
    766     }
    767   }
    768 
    769   RECURSE(ValidateExport(module_return_));
    770 
    771   if (!source_layout_.IsValid()) {
    772     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 bool IsDoubleAnnotation(BinaryOperation* binop) {
    780   // *VIOLATION* The parser replaces uses of +x with x*1.0.
    781   if (binop->op() != Token::MUL) {
    782     return false;
    783   }
    784 
    785   auto* right_as_literal = binop->right()->AsLiteral();
    786   if (right_as_literal == nullptr) {
    787     return false;
    788   }
    789 
    790   return IsLiteral1Dot0(right_as_literal);
    791 }
    792 
    793 bool IsIntAnnotation(BinaryOperation* binop) {
    794   if (binop->op() != Token::BIT_OR) {
    795     return false;
    796   }
    797 
    798   auto* right_as_literal = binop->right()->AsLiteral();
    799   if (right_as_literal == nullptr) {
    800     return false;
    801   }
    802 
    803   return IsLiteral0(right_as_literal);
    804 }
    805 }  // namespace
    806 
    807 AsmType* AsmTyper::ValidateGlobalDeclaration(Assignment* assign) {
    808   DCHECK(!assign->is_compound());
    809   if (assign->is_compound()) {
    810     FAIL(assign,
    811          "Compound assignment not supported when declaring global variables.");
    812   }
    813 
    814   auto* target = assign->target();
    815   if (!target->IsVariableProxy()) {
    816     FAIL(target, "Module assignments may only assign to globals.");
    817   }
    818   auto* target_variable = target->AsVariableProxy()->var();
    819   auto* target_info = Lookup(target_variable);
    820 
    821   if (target_info != nullptr) {
    822     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   if (value->IsLiteral() || value->IsCall()) {
    830     AsmType* type = nullptr;
    831     VariableInfo::Mutability mutability;
    832     if (target_variable->mode() == CONST) {
    833       mutability = VariableInfo::kConstGlobal;
    834     } else {
    835       mutability = VariableInfo::kMutableGlobal;
    836     }
    837     RECURSE(type = VariableTypeAnnotations(value, mutability));
    838     target_info = new (zone_) VariableInfo(type);
    839     target_info->set_mutability(mutability);
    840     global_variable = true;
    841   } else if (value->IsProperty()) {
    842     target_info = ImportLookup(value->AsProperty());
    843     if (target_info == nullptr) {
    844       FAIL(assign, "Invalid import.");
    845     }
    846     CHECK(target_info->mutability() == VariableInfo::kImmutableGlobal);
    847     if (target_info->IsFFI()) {
    848       // create a new target info that represents a foreign variable.
    849       target_info = new (zone_) VariableInfo(ffi_type_);
    850       target_info->set_mutability(VariableInfo::kImmutableGlobal);
    851     } else if (target_info->type()->IsA(AsmType::Heap())) {
    852       FAIL(assign, "Heap view types can not be aliased.");
    853     } else {
    854       target_info = target_info->Clone(zone_);
    855     }
    856   } else if (value->IsBinaryOperation()) {
    857     // This should either be:
    858     //
    859     // var <> = ffi.<>|0
    860     //
    861     // or
    862     //
    863     // var <> = +ffi.<>
    864     auto* value_binop = value->AsBinaryOperation();
    865     auto* left = value_binop->left();
    866     AsmType* import_type = nullptr;
    867 
    868     if (IsDoubleAnnotation(value_binop)) {
    869       import_type = AsmType::Double();
    870     } else if (IsIntAnnotation(value_binop)) {
    871       import_type = AsmType::Int();
    872     } else {
    873       FAIL(value,
    874            "Invalid initializer for foreign import - unrecognized annotation.");
    875     }
    876 
    877     if (!left->IsProperty()) {
    878       FAIL(value,
    879            "Invalid initializer for foreign import - must import member.");
    880     }
    881     target_info = ImportLookup(left->AsProperty());
    882     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       FAIL(value,
    887            "Invalid initializer for foreign import - object lookup failed.");
    888     }
    889     CHECK(target_info->mutability() == VariableInfo::kImmutableGlobal);
    890     if (!target_info->IsFFI()) {
    891       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     target_info = new (zone_) VariableInfo(import_type);
    897     target_info->set_mutability(VariableInfo::kMutableGlobal);
    898   } else if (value->IsCallNew()) {
    899     AsmType* type = nullptr;
    900     RECURSE(type = NewHeapView(value->AsCallNew()));
    901     target_info = new (zone_) VariableInfo(type);
    902     target_info->set_mutability(VariableInfo::kImmutableGlobal);
    903   } else if (auto* proxy = value->AsVariableProxy()) {
    904     auto* var_info = Lookup(proxy->var());
    905 
    906     if (var_info == nullptr) {
    907       FAIL(value, "Undeclared identifier in global initializer");
    908     }
    909 
    910     if (var_info->mutability() != VariableInfo::kConstGlobal) {
    911       FAIL(value, "Identifier used to initialize a global must be a const");
    912     }
    913 
    914     target_info = new (zone_) VariableInfo(var_info->type());
    915     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   if (target_info == nullptr) {
    923     FAIL(assign, "Invalid global variable initializer.");
    924   }
    925 
    926   if (!ValidAsmIdentifier(target_variable->name())) {
    927     FAIL(target, "Invalid asm.js identifier in global variable.");
    928   }
    929 
    930   if (!AddGlobal(target_variable, target_info)) {
    931     FAIL(assign, "Redeclared global identifier.");
    932   }
    933 
    934   DCHECK(target_info->type() != AsmType::None());
    935   if (!global_variable) {
    936     // Global variables have their types set in VariableTypeAnnotations.
    937     SetTypeOf(value, target_info->type());
    938   }
    939   SetTypeOf(assign, target_info->type());
    940   SetTypeOf(target, target_info->type());
    941   return target_info->type();
    942 }
    943 
    944 // 6.2 ValidateExport
    945 AsmType* AsmTyper::ExportType(VariableProxy* fun_export) {
    946   auto* fun_info = Lookup(fun_export->var());
    947   if (fun_info == nullptr) {
    948     FAIL(fun_export, "Undefined identifier in asm.js module export.");
    949   }
    950 
    951   if (fun_info->standard_member() != kNone) {
    952     FAIL(fun_export, "Module cannot export standard library functions.");
    953   }
    954 
    955   auto* type = fun_info->type();
    956   if (type->AsFFIType() != nullptr) {
    957     FAIL(fun_export, "Module cannot export foreign functions.");
    958   }
    959 
    960   if (type->AsFunctionTableType() != nullptr) {
    961     FAIL(fun_export, "Module cannot export function tables.");
    962   }
    963 
    964   if (fun_info->type()->AsFunctionType() == nullptr) {
    965     FAIL(fun_export, "Module export is not an asm.js function.");
    966   }
    967 
    968   if (!fun_export->var()->is_function()) {
    969     FAIL(fun_export, "Module exports must be function declarations.");
    970   }
    971 
    972   return type;
    973 }
    974 
    975 AsmType* AsmTyper::ValidateExport(ReturnStatement* exports) {
    976   // asm.js modules can export single functions, or multiple functions in an
    977   // object literal.
    978   if (auto* fun_export = exports->expression()->AsVariableProxy()) {
    979     // Exporting single function.
    980     AsmType* export_type;
    981     RECURSE(export_type = ExportType(fun_export));
    982     return export_type;
    983   }
    984 
    985   if (auto* obj_export = exports->expression()->AsObjectLiteral()) {
    986     // Exporting object literal.
    987     for (auto* prop : *obj_export->properties()) {
    988       if (!prop->key()->IsLiteral()) {
    989         FAIL(prop->key(),
    990              "Only normal object properties may be used in the export object "
    991              "literal.");
    992       }
    993       if (!prop->key()->AsLiteral()->IsPropertyName()) {
    994         FAIL(prop->key(),
    995              "Exported functions must have valid identifier names.");
    996       }
    997 
    998       auto* export_obj = prop->value()->AsVariableProxy();
    999       if (export_obj == nullptr) {
   1000         FAIL(prop->value(), "Exported value must be an asm.js function name.");
   1001       }
   1002 
   1003       RECURSE(ExportType(export_obj));
   1004     }
   1005 
   1006     return AsmType::Int();
   1007   }
   1008 
   1009   FAIL(exports, "Unrecognized expression in asm.js module export expression.");
   1010 }
   1011 
   1012 // 6.3 ValidateFunctionTable
   1013 AsmType* AsmTyper::ValidateFunctionTable(Assignment* assign) {
   1014   if (assign->is_compound()) {
   1015     FAIL(assign,
   1016          "Compound assignment not supported when declaring global variables.");
   1017   }
   1018 
   1019   auto* target = assign->target();
   1020   if (!target->IsVariableProxy()) {
   1021     FAIL(target, "Module assignments may only assign to globals.");
   1022   }
   1023   auto* target_variable = target->AsVariableProxy()->var();
   1024 
   1025   auto* value = assign->value()->AsArrayLiteral();
   1026   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   if (!base::bits::IsPowerOfTwo32(pointers->length())) {
   1032     FAIL(assign, "Invalid length for function pointer table.");
   1033   }
   1034 
   1035   AsmType* table_element_type = nullptr;
   1036   for (auto* initializer : *pointers) {
   1037     auto* var_proxy = initializer->AsVariableProxy();
   1038     if (var_proxy == nullptr) {
   1039       FAIL(initializer,
   1040            "Function pointer table initializer must be a function name.");
   1041     }
   1042 
   1043     auto* var_info = Lookup(var_proxy->var());
   1044     if (var_info == nullptr) {
   1045       FAIL(var_proxy,
   1046            "Undefined identifier in function pointer table initializer.");
   1047     }
   1048 
   1049     if (var_info->standard_member() != kNone) {
   1050       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     if (initializer_type->AsFunctionType() == nullptr) {
   1057       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     if (table_element_type == nullptr) {
   1065       table_element_type = initializer_type;
   1066     } else if (!initializer_type->IsA(table_element_type)) {
   1067       FAIL(initializer, "Type mismatch in function pointer table initializer.");
   1068     }
   1069   }
   1070 
   1071   auto* target_info = Lookup(target_variable);
   1072   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         zone_, pointers->length(), table_element_type));
   1078     target_info->set_mutability(VariableInfo::kImmutableGlobal);
   1079     if (!ValidAsmIdentifier(target_variable->name())) {
   1080       FAIL(target, "Invalid asm.js identifier in function table name.");
   1081     }
   1082     if (!AddGlobal(target_variable, target_info)) {
   1083       DCHECK(false);
   1084       FAIL(assign, "Redeclared global identifier in function table name.");
   1085     }
   1086     SetTypeOf(value, target_info->type());
   1087     return target_info->type();
   1088   }
   1089 
   1090   auto* target_info_table = target_info->type()->AsFunctionTableType();
   1091   if (target_info_table == nullptr) {
   1092     FAIL(assign, "Identifier redefined as function pointer table.");
   1093   }
   1094 
   1095   if (!target_info->missing_definition()) {
   1096     FAIL(assign, "Identifier redefined (function table name).");
   1097   }
   1098 
   1099   if (static_cast<int>(target_info_table->length()) != pointers->length()) {
   1100     FAIL(assign, "Function table size mismatch.");
   1101   }
   1102 
   1103   DCHECK(target_info_table->signature()->AsFunctionType());
   1104   if (!table_element_type->IsA(target_info_table->signature())) {
   1105     FAIL(assign, "Function table initializer does not match previous type.");
   1106   }
   1107 
   1108   target_info->MarkDefined();
   1109   DCHECK(target_info->type() != AsmType::None());
   1110   SetTypeOf(value, target_info->type());
   1111 
   1112   return target_info->type();
   1113 }
   1114 
   1115 // 6.4 ValidateFunction
   1116 AsmType* AsmTyper::ValidateFunction(FunctionDeclaration* fun_decl) {
   1117   FunctionScope _(this);
   1118 
   1119   // Extract parameter types.
   1120   auto* fun = fun_decl->fun();
   1121 
   1122   auto* fun_decl_proxy = fun_decl->proxy();
   1123   if (fun_decl_proxy == nullptr) {
   1124     FAIL(fun_decl, "Anonymous functions are not support in asm.js.");
   1125   }
   1126 
   1127   Statement* current;
   1128   FlattenedStatements iter(zone_, fun->body());
   1129 
   1130   size_t annotated_parameters = 0;
   1131 
   1132   // 5.3 Function type annotations
   1133   //     * parameters
   1134   ZoneVector<AsmType*> parameter_types(zone_);
   1135   for (; (current = iter.Next()) != nullptr; ++annotated_parameters) {
   1136     auto* stmt = current->AsExpressionStatement();
   1137     if (stmt == nullptr) {
   1138       // Done with parameters.
   1139       break;
   1140     }
   1141     auto* expr = stmt->expression()->AsAssignment();
   1142     if (expr == nullptr || expr->is_compound()) {
   1143       // Done with parameters.
   1144       break;
   1145     }
   1146     auto* proxy = expr->target()->AsVariableProxy();
   1147     if (proxy == nullptr) {
   1148       // Done with parameters.
   1149       break;
   1150     }
   1151     auto* param = proxy->var();
   1152     if (param->location() != VariableLocation::PARAMETER ||
   1153         param->index() != static_cast<int>(annotated_parameters)) {
   1154       // Done with parameters.
   1155       break;
   1156     }
   1157 
   1158     AsmType* type;
   1159     RECURSE(type = ParameterTypeAnnotations(param, expr->value()));
   1160     DCHECK(type->IsParameterType());
   1161     auto* param_info = new (zone_) VariableInfo(type);
   1162     param_info->set_mutability(VariableInfo::kLocal);
   1163     if (!ValidAsmIdentifier(proxy->name())) {
   1164       FAIL(proxy, "Invalid asm.js identifier in parameter name.");
   1165     }
   1166 
   1167     if (!AddLocal(param, param_info)) {
   1168       FAIL(proxy, "Redeclared parameter.");
   1169     }
   1170     parameter_types.push_back(type);
   1171     SetTypeOf(proxy, type);
   1172     SetTypeOf(expr, type);
   1173     SetTypeOf(expr->value(), type);
   1174   }
   1175 
   1176   if (static_cast<int>(annotated_parameters) != fun->parameter_count()) {
   1177     FAIL(fun_decl, "Incorrect parameter type annotations.");
   1178   }
   1179 
   1180   // 5.3 Function type annotations
   1181   //     * locals
   1182   for (; current; current = iter.Next()) {
   1183     auto* initializer = ExtractInitializerExpression(current);
   1184     if (initializer == nullptr) {
   1185       // Done with locals.
   1186       break;
   1187     }
   1188 
   1189     auto* local = initializer->target()->AsVariableProxy();
   1190     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     RECURSE(type = VariableTypeAnnotations(initializer->value()));
   1201     auto* local_info = new (zone_) VariableInfo(type);
   1202     local_info->set_mutability(VariableInfo::kLocal);
   1203     if (!ValidAsmIdentifier(local->name())) {
   1204       FAIL(local, "Invalid asm.js identifier in local variable.");
   1205     }
   1206 
   1207     if (!AddLocal(local->var(), local_info)) {
   1208       FAIL(initializer, "Redeclared local.");
   1209     }
   1210 
   1211     SetTypeOf(local, type);
   1212     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   do {
   1221     if (statements->length() == 0) {
   1222       return_type_ = AsmType::Void();
   1223     } else {
   1224       auto* last_statement = statements->last();
   1225       auto* as_block = last_statement->AsBlock();
   1226       if (as_block != nullptr) {
   1227         statements = as_block->statements();
   1228       } else {
   1229         if (auto* ret_statement = last_statement->AsReturnStatement()) {
   1230           RECURSE(return_type_ =
   1231                       ReturnTypeAnnotations(ret_statement->expression()));
   1232         } else {
   1233           return_type_ = AsmType::Void();
   1234         }
   1235       }
   1236     }
   1237   } while (return_type_ == AsmType::None());
   1238 
   1239   DCHECK(return_type_->IsReturnType());
   1240 
   1241   for (Declaration* decl : *fun->scope()->declarations()) {
   1242     auto* var_decl = decl->AsVariableDeclaration();
   1243     if (var_decl == nullptr) {
   1244       FAIL(decl, "Functions may only define inner variables.");
   1245     }
   1246 
   1247     auto* var_proxy = var_decl->proxy();
   1248     if (var_proxy == nullptr) {
   1249       FAIL(decl, "Invalid local declaration declaration.");
   1250     }
   1251 
   1252     auto* var_info = Lookup(var_proxy->var());
   1253     if (var_info == nullptr || var_info->IsGlobal()) {
   1254       FAIL(decl, "Local variable missing initializer in asm.js module.");
   1255     }
   1256   }
   1257 
   1258   for (; current; current = iter.Next()) {
   1259     AsmType* current_type;
   1260     RECURSE(current_type = ValidateStatement(current));
   1261   }
   1262 
   1263   auto* fun_type = AsmType::Function(zone_, return_type_);
   1264   auto* fun_type_as_function = fun_type->AsFunctionType();
   1265   for (auto* param_type : parameter_types) {
   1266     fun_type_as_function->AddArgument(param_type);
   1267   }
   1268 
   1269   auto* fun_var = fun_decl_proxy->var();
   1270   auto* fun_info = new (zone_) VariableInfo(fun_type);
   1271   fun_info->set_mutability(VariableInfo::kImmutableGlobal);
   1272   auto* old_fun_info = Lookup(fun_var);
   1273   if (old_fun_info == nullptr) {
   1274     if (!ValidAsmIdentifier(fun_var->name())) {
   1275       FAIL(fun_decl_proxy, "Invalid asm.js identifier in function name.");
   1276     }
   1277     if (!AddGlobal(fun_var, fun_info)) {
   1278       DCHECK(false);
   1279       FAIL(fun_decl, "Redeclared global identifier.");
   1280     }
   1281 
   1282     SetTypeOf(fun, fun_type);
   1283     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   if (old_fun_type->AsFunctionType() == nullptr) {
   1291     FAIL(fun_decl, "Identifier redefined as function.");
   1292   }
   1293 
   1294   if (!old_fun_info->missing_definition()) {
   1295     FAIL(fun_decl, "Identifier redefined (function name).");
   1296   }
   1297 
   1298   if (!fun_type->IsA(old_fun_type)) {
   1299     FAIL(fun_decl, "Signature mismatch when defining function.");
   1300   }
   1301 
   1302   old_fun_info->MarkDefined();
   1303   SetTypeOf(fun, fun_type);
   1304 
   1305   return fun_type;
   1306 }
   1307 
   1308 // 6.5 ValidateStatement
   1309 AsmType* AsmTyper::ValidateStatement(Statement* statement) {
   1310   switch (statement->node_type()) {
   1311     default:
   1312       FAIL(statement, "Statement type invalid for asm.js.");
   1313     case AstNode::kBlock:
   1314       return ValidateBlockStatement(statement->AsBlock());
   1315     case AstNode::kExpressionStatement:
   1316       return ValidateExpressionStatement(statement->AsExpressionStatement());
   1317     case AstNode::kEmptyStatement:
   1318       return ValidateEmptyStatement(statement->AsEmptyStatement());
   1319     case AstNode::kIfStatement:
   1320       return ValidateIfStatement(statement->AsIfStatement());
   1321     case AstNode::kReturnStatement:
   1322       return ValidateReturnStatement(statement->AsReturnStatement());
   1323     case AstNode::kWhileStatement:
   1324       return ValidateWhileStatement(statement->AsWhileStatement());
   1325     case AstNode::kDoWhileStatement:
   1326       return ValidateDoWhileStatement(statement->AsDoWhileStatement());
   1327     case AstNode::kForStatement:
   1328       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       return ValidateSwitchStatement(statement->AsSwitchStatement());
   1335   }
   1336 
   1337   return AsmType::Void();
   1338 }
   1339 
   1340 // 6.5.1 BlockStatement
   1341 AsmType* AsmTyper::ValidateBlockStatement(Block* block) {
   1342   FlattenedStatements iter(zone_, block->statements());
   1343 
   1344   while (auto* current = iter.Next()) {
   1345     RECURSE(ValidateStatement(current));
   1346   }
   1347 
   1348   return AsmType::Void();
   1349 }
   1350 
   1351 // 6.5.2 ExpressionStatement
   1352 AsmType* AsmTyper::ValidateExpressionStatement(ExpressionStatement* expr) {
   1353   auto* expression = expr->expression();
   1354   if (auto* call = expression->AsCall()) {
   1355     RECURSE(ValidateCall(AsmType::Void(), call));
   1356   } else {
   1357     RECURSE(ValidateExpression(expression));
   1358   }
   1359 
   1360   return AsmType::Void();
   1361 }
   1362 
   1363 // 6.5.3 EmptyStatement
   1364 AsmType* AsmTyper::ValidateEmptyStatement(EmptyStatement* empty) {
   1365   return AsmType::Void();
   1366 }
   1367 
   1368 // 6.5.4 IfStatement
   1369 AsmType* AsmTyper::ValidateIfStatement(IfStatement* if_stmt) {
   1370   AsmType* cond_type;
   1371   RECURSE(cond_type = ValidateExpression(if_stmt->condition()));
   1372   if (!cond_type->IsA(AsmType::Int())) {
   1373     FAIL(if_stmt->condition(), "If condition must be type int.");
   1374   }
   1375   RECURSE(ValidateStatement(if_stmt->then_statement()));
   1376   RECURSE(ValidateStatement(if_stmt->else_statement()));
   1377   return AsmType::Void();
   1378 }
   1379 
   1380 // 6.5.5 ReturnStatement
   1381 AsmType* AsmTyper::ValidateReturnStatement(ReturnStatement* ret_stmt) {
   1382   AsmType* ret_expr_type = AsmType::Void();
   1383   if (auto* ret_expr = ret_stmt->expression()) {
   1384     RECURSE(ret_expr_type = ValidateExpression(ret_expr));
   1385     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       if (!ret_expr->IsUndefinedLiteral()) {
   1389         FAIL(ret_stmt, "Return statement expression can't be void.");
   1390       }
   1391     }
   1392   }
   1393 
   1394   if (!ret_expr_type->IsA(return_type_)) {
   1395     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 AsmType* AsmTyper::ValidateWhileStatement(WhileStatement* while_stmt) {
   1404   AsmType* cond_type;
   1405   RECURSE(cond_type = ValidateExpression(while_stmt->cond()));
   1406   if (!cond_type->IsA(AsmType::Int())) {
   1407     FAIL(while_stmt->cond(), "While condition must be type int.");
   1408   }
   1409 
   1410   if (auto* body = while_stmt->body()) {
   1411     RECURSE(ValidateStatement(body));
   1412   }
   1413   return AsmType::Void();
   1414 }
   1415 
   1416 // 6.5.6.b DoWhileStatement
   1417 AsmType* AsmTyper::ValidateDoWhileStatement(DoWhileStatement* do_while) {
   1418   AsmType* cond_type;
   1419   RECURSE(cond_type = ValidateExpression(do_while->cond()));
   1420   if (!cond_type->IsA(AsmType::Int())) {
   1421     FAIL(do_while->cond(), "Do {} While condition must be type int.");
   1422   }
   1423 
   1424   if (auto* body = do_while->body()) {
   1425     RECURSE(ValidateStatement(body));
   1426   }
   1427   return AsmType::Void();
   1428 }
   1429 
   1430 // 6.5.6.c ForStatement
   1431 AsmType* AsmTyper::ValidateForStatement(ForStatement* for_stmt) {
   1432   if (auto* init = for_stmt->init()) {
   1433     RECURSE(ValidateStatement(init));
   1434   }
   1435 
   1436   if (auto* cond = for_stmt->cond()) {
   1437     AsmType* cond_type;
   1438     RECURSE(cond_type = ValidateExpression(cond));
   1439     if (!cond_type->IsA(AsmType::Int())) {
   1440       FAIL(cond, "For condition must be type int.");
   1441     }
   1442   }
   1443 
   1444   if (auto* next = for_stmt->next()) {
   1445     RECURSE(ValidateStatement(next));
   1446   }
   1447 
   1448   if (auto* body = for_stmt->body()) {
   1449     RECURSE(ValidateStatement(body));
   1450   }
   1451 
   1452   return AsmType::Void();
   1453 }
   1454 
   1455 // 6.5.7 BreakStatement
   1456 AsmType* AsmTyper::ValidateBreakStatement(BreakStatement* brk_stmt) {
   1457   return AsmType::Void();
   1458 }
   1459 
   1460 // 6.5.8 ContinueStatement
   1461 AsmType* AsmTyper::ValidateContinueStatement(ContinueStatement* cont_stmt) {
   1462   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 AsmType* AsmTyper::ValidateSwitchStatement(SwitchStatement* stmt) {
   1470   AsmType* cond_type;
   1471   RECURSE(cond_type = ValidateExpression(stmt->tag()));
   1472   if (!cond_type->IsA(AsmType::Signed())) {
   1473     FAIL(stmt, "Switch tag must be signed.");
   1474   }
   1475 
   1476   int default_pos = kNoSourcePosition;
   1477   int last_case_pos = kNoSourcePosition;
   1478   ZoneSet<int32_t> cases_seen(zone_);
   1479   for (auto* a_case : *stmt->cases()) {
   1480     if (a_case->is_default()) {
   1481       CHECK(default_pos == kNoSourcePosition);
   1482       RECURSE(ValidateDefault(a_case));
   1483       default_pos = a_case->position();
   1484       continue;
   1485     }
   1486 
   1487     if (last_case_pos == kNoSourcePosition) {
   1488       last_case_pos = a_case->position();
   1489     } else {
   1490       last_case_pos = std::max(last_case_pos, a_case->position());
   1491     }
   1492 
   1493     int32_t case_lbl;
   1494     RECURSE(ValidateCase(a_case, &case_lbl));
   1495     auto case_lbl_pos = cases_seen.find(case_lbl);
   1496     if (case_lbl_pos != cases_seen.end() && *case_lbl_pos == case_lbl) {
   1497       FAIL(a_case, "Duplicated case label.");
   1498     }
   1499     cases_seen.insert(case_lbl);
   1500   }
   1501 
   1502   if (!cases_seen.empty()) {
   1503     const int64_t max_lbl = *cases_seen.rbegin();
   1504     const int64_t min_lbl = *cases_seen.begin();
   1505     if (max_lbl - min_lbl > std::numeric_limits<int32_t>::max()) {
   1506       FAIL(stmt, "Out-of-bounds case label range.");
   1507     }
   1508   }
   1509 
   1510   if (last_case_pos != kNoSourcePosition && default_pos != kNoSourcePosition &&
   1511       default_pos < last_case_pos) {
   1512     FAIL(stmt, "Switch default must appear last.");
   1513   }
   1514 
   1515   return AsmType::Void();
   1516 }
   1517 
   1518 // 6.6 ValidateCase
   1519 namespace {
   1520 bool ExtractInt32CaseLabel(CaseClause* clause, int32_t* lbl) {
   1521   auto* lbl_expr = clause->label()->AsLiteral();
   1522 
   1523   if (lbl_expr == nullptr) {
   1524     return false;
   1525   }
   1526 
   1527   if (!IsLiteralInt(lbl_expr)) {
   1528     return false;
   1529   }
   1530 
   1531   return lbl_expr->value()->ToInt32(lbl);
   1532 }
   1533 }  // namespace
   1534 
   1535 AsmType* AsmTyper::ValidateCase(CaseClause* label, int32_t* case_lbl) {
   1536   if (!ExtractInt32CaseLabel(label, case_lbl)) {
   1537     FAIL(label, "Case label must be a 32-bit signed integer.");
   1538   }
   1539 
   1540   FlattenedStatements iter(zone_, label->statements());
   1541   while (auto* current = iter.Next()) {
   1542     RECURSE(ValidateStatement(current));
   1543   }
   1544   return AsmType::Void();
   1545 }
   1546 
   1547 // 6.7 ValidateDefault
   1548 AsmType* AsmTyper::ValidateDefault(CaseClause* label) {
   1549   FlattenedStatements iter(zone_, label->statements());
   1550   while (auto* current = iter.Next()) {
   1551     RECURSE(ValidateStatement(current));
   1552   }
   1553   return AsmType::Void();
   1554 }
   1555 
   1556 // 6.8 ValidateExpression
   1557 AsmType* AsmTyper::ValidateExpression(Expression* expr) {
   1558   AsmType* expr_ty = AsmType::None();
   1559 
   1560   switch (expr->node_type()) {
   1561     default:
   1562       FAIL(expr, "Invalid asm.js expression.");
   1563     case AstNode::kLiteral:
   1564       RECURSE(expr_ty = ValidateNumericLiteral(expr->AsLiteral()));
   1565       break;
   1566     case AstNode::kVariableProxy:
   1567       RECURSE(expr_ty = ValidateIdentifier(expr->AsVariableProxy()));
   1568       break;
   1569     case AstNode::kCall:
   1570       RECURSE(expr_ty = ValidateCallExpression(expr->AsCall()));
   1571       break;
   1572     case AstNode::kProperty:
   1573       RECURSE(expr_ty = ValidateMemberExpression(expr->AsProperty()));
   1574       break;
   1575     case AstNode::kAssignment:
   1576       RECURSE(expr_ty = ValidateAssignmentExpression(expr->AsAssignment()));
   1577       break;
   1578     case AstNode::kUnaryOperation:
   1579       RECURSE(expr_ty = ValidateUnaryExpression(expr->AsUnaryOperation()));
   1580       break;
   1581     case AstNode::kConditional:
   1582       RECURSE(expr_ty = ValidateConditionalExpression(expr->AsConditional()));
   1583       break;
   1584     case AstNode::kCompareOperation:
   1585       RECURSE(expr_ty = ValidateCompareOperation(expr->AsCompareOperation()));
   1586       break;
   1587     case AstNode::kBinaryOperation:
   1588       RECURSE(expr_ty = ValidateBinaryOperation(expr->AsBinaryOperation()));
   1589       break;
   1590   }
   1591 
   1592   SetTypeOf(expr, expr_ty);
   1593   return expr_ty;
   1594 }
   1595 
   1596 AsmType* AsmTyper::ValidateCompareOperation(CompareOperation* cmp) {
   1597   switch (cmp->op()) {
   1598     default:
   1599       FAIL(cmp, "Invalid asm.js comparison operator.");
   1600     case Token::LT:
   1601     case Token::LTE:
   1602     case Token::GT:
   1603     case Token::GTE:
   1604       return ValidateRelationalExpression(cmp);
   1605     case Token::EQ:
   1606     case Token::NE:
   1607       return ValidateEqualityExpression(cmp);
   1608   }
   1609 
   1610   UNREACHABLE();
   1611 }
   1612 
   1613 namespace {
   1614 bool IsInvert(BinaryOperation* binop) {
   1615   if (binop->op() != Token::BIT_XOR) {
   1616     return false;
   1617   }
   1618 
   1619   auto* right_as_literal = binop->right()->AsLiteral();
   1620   if (right_as_literal == nullptr) {
   1621     return false;
   1622   }
   1623 
   1624   return IsLiteralMinus1(right_as_literal);
   1625 }
   1626 
   1627 bool IsUnaryMinus(BinaryOperation* binop) {
   1628   // *VIOLATION* The parser replaces uses of -x with x*-1.
   1629   if (binop->op() != Token::MUL) {
   1630     return false;
   1631   }
   1632 
   1633   auto* right_as_literal = binop->right()->AsLiteral();
   1634   if (right_as_literal == nullptr) {
   1635     return false;
   1636   }
   1637 
   1638   return IsLiteralMinus1(right_as_literal);
   1639 }
   1640 }  // namespace
   1641 
   1642 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   switch (expr->op()) {
   1651     default:
   1652       FAIL(expr, "Invalid asm.js binary expression.");
   1653     case Token::COMMA:
   1654       return ValidateCommaExpression(expr);
   1655     case Token::MUL:
   1656       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         if (auto* Call = expr->left()->AsCall()) {
   1660           return ValidateCall(AsmType::Double(), Call);
   1661         }
   1662         AsmType* left_type;
   1663         RECURSE(left_type = ValidateExpression(expr->left()));
   1664         SetTypeOf(expr->right(), AsmType::Double());
   1665         UNOP_OVERLOAD(Signed, Double);
   1666         UNOP_OVERLOAD(Unsigned, Double);
   1667         UNOP_OVERLOAD(DoubleQ, Double);
   1668         UNOP_OVERLOAD(FloatQ, Double);
   1669         FAIL(expr, "Invalid type for conversion to double.");
   1670       }
   1671 
   1672       if (IsUnaryMinus(expr)) {
   1673         // *VIOLATION* the parser converts -x to x * -1.
   1674         AsmType* left_type;
   1675         RECURSE(left_type = ValidateExpression(expr->left()));
   1676         SetTypeOf(expr->right(), left_type);
   1677         UNOP_OVERLOAD(Int, Intish);
   1678         UNOP_OVERLOAD(DoubleQ, Double);
   1679         UNOP_OVERLOAD(FloatQ, Floatish);
   1680         FAIL(expr, "Invalid type for unary -.");
   1681       }
   1682     // FALTHROUGH
   1683     case Token::DIV:
   1684     case Token::MOD:
   1685       return ValidateMultiplicativeExpression(expr);
   1686     case Token::ADD:
   1687     case Token::SUB: {
   1688       static const uint32_t kInitialIntishCount = 0;
   1689       return ValidateAdditiveExpression(expr, kInitialIntishCount);
   1690     }
   1691     case Token::SAR:
   1692     case Token::SHL:
   1693     case Token::SHR:
   1694       return ValidateShiftExpression(expr);
   1695     case Token::BIT_AND:
   1696       return ValidateBitwiseANDExpression(expr);
   1697     case Token::BIT_XOR:
   1698       if (IsInvert(expr)) {
   1699         auto* left = expr->left();
   1700         auto* left_as_binop = left->AsBinaryOperation();
   1701 
   1702         if (left_as_binop != nullptr && IsInvert(left_as_binop)) {
   1703           // This is the special ~~ operator.
   1704           AsmType* left_type;
   1705           RECURSE(left_type = ValidateExpression(left_as_binop->left()));
   1706           SetTypeOf(left_as_binop->right(), AsmType::FixNum());
   1707           SetTypeOf(left_as_binop, AsmType::Signed());
   1708           SetTypeOf(expr->right(), AsmType::FixNum());
   1709           UNOP_OVERLOAD(Double, Signed);
   1710           UNOP_OVERLOAD(FloatQ, Signed);
   1711           FAIL(left_as_binop, "Invalid type for conversion to signed.");
   1712         }
   1713 
   1714         AsmType* left_type;
   1715         RECURSE(left_type = ValidateExpression(left));
   1716         UNOP_OVERLOAD(Intish, Signed);
   1717         FAIL(left, "Invalid type for ~.");
   1718       }
   1719 
   1720       return ValidateBitwiseXORExpression(expr);
   1721     case Token::BIT_OR:
   1722       return ValidateBitwiseORExpression(expr);
   1723   }
   1724 #undef UNOP_OVERLOAD
   1725   UNREACHABLE();
   1726 }
   1727 
   1728 // 6.8.1 Expression
   1729 AsmType* AsmTyper::ValidateCommaExpression(BinaryOperation* comma) {
   1730   // The AST looks like:
   1731   // (expr COMMA (expr COMMA (expr COMMA (... ))))
   1732 
   1733   auto* left = comma->left();
   1734   if (auto* left_as_call = left->AsCall()) {
   1735     RECURSE(ValidateCall(AsmType::Void(), left_as_call));
   1736   } else {
   1737     RECURSE(ValidateExpression(left));
   1738   }
   1739 
   1740   auto* right = comma->right();
   1741   AsmType* right_type = nullptr;
   1742   if (auto* right_as_call = right->AsCall()) {
   1743     RECURSE(right_type = ValidateFloatCoercion(right_as_call));
   1744     if (right_type != AsmType::Float()) {
   1745       // right_type == nullptr <-> right_as_call is not a call to fround.
   1746       DCHECK(right_type == nullptr);
   1747       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     RECURSE(right_type = ValidateExpression(right));
   1754   }
   1755 
   1756   return right_type;
   1757 }
   1758 
   1759 // 6.8.2 NumericLiteral
   1760 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   if (literal->IsUndefinedLiteral()) {
   1764     return AsmType::Void();
   1765   }
   1766 
   1767   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   if (literal->raw_value()->IsTrue() || literal->raw_value()->IsFalse()) {
   1774     return AsmType::Int();
   1775   }
   1776 
   1777   uint32_t value;
   1778   if (!literal->value()->ToUint32(&value)) {
   1779     int32_t value;
   1780     if (!literal->value()->ToInt32(&value)) {
   1781       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   if (value <= LargestFixNum) {
   1790     return AsmType::FixNum();
   1791   }
   1792 
   1793   return AsmType::Unsigned();
   1794 }
   1795 
   1796 // 6.8.3 Identifier
   1797 AsmType* AsmTyper::ValidateIdentifier(VariableProxy* proxy) {
   1798   auto* proxy_info = Lookup(proxy->var());
   1799   if (proxy_info == nullptr) {
   1800     FAIL(proxy, "Undeclared identifier.");
   1801   }
   1802   auto* type = proxy_info->type();
   1803   if (type->IsA(AsmType::None()) || type->AsCallableType() != nullptr) {
   1804     FAIL(proxy, "Identifier may not be accessed by ordinary expressions.");
   1805   }
   1806   return type;
   1807 }
   1808 
   1809 // 6.8.4 CallExpression
   1810 AsmType* AsmTyper::ValidateCallExpression(Call* call) {
   1811   AsmType* return_type;
   1812   RECURSE(return_type = ValidateFloatCoercion(call));
   1813   if (return_type == nullptr) {
   1814     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 AsmType* AsmTyper::ValidateMemberExpression(Property* prop) {
   1821   AsmType* return_type;
   1822   RECURSE(return_type = ValidateHeapAccess(prop, LoadFromHeap));
   1823   return return_type;
   1824 }
   1825 
   1826 // 6.8.6 AssignmentExpression
   1827 AsmType* AsmTyper::ValidateAssignmentExpression(Assignment* assignment) {
   1828   AsmType* value_type;
   1829   RECURSE(value_type = ValidateExpression(assignment->value()));
   1830 
   1831   if (assignment->op() == Token::INIT) {
   1832     FAIL(assignment,
   1833          "Local variable declaration must be at the top of the function.");
   1834   }
   1835 
   1836   if (auto* target_as_proxy = assignment->target()->AsVariableProxy()) {
   1837     auto* var = target_as_proxy->var();
   1838     auto* target_info = Lookup(var);
   1839 
   1840     if (target_info == nullptr) {
   1841       if (var->mode() != TEMPORARY) {
   1842         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       auto* var_info = new (zone_) VariableInfo(value_type);
   1849       var_info->set_mutability(VariableInfo::kLocal);
   1850       if (!ValidAsmIdentifier(target_as_proxy->name())) {
   1851         FAIL(target_as_proxy,
   1852              "Invalid asm.js identifier in temporary variable.");
   1853       }
   1854 
   1855       if (!AddLocal(var, var_info)) {
   1856         FAIL(assignment, "Failed to add temporary variable to symbol table.");
   1857       }
   1858       return value_type;
   1859     }
   1860 
   1861     if (!target_info->IsMutable()) {
   1862       FAIL(assignment, "Can't assign to immutable symbol.");
   1863     }
   1864 
   1865     DCHECK_NE(AsmType::None(), target_info->type());
   1866     if (!value_type->IsA(target_info->type())) {
   1867       FAIL(assignment, "Type mismatch in assignment.");
   1868     }
   1869 
   1870     return value_type;
   1871   }
   1872 
   1873   if (auto* target_as_property = assignment->target()->AsProperty()) {
   1874     AsmType* allowed_store_types;
   1875     RECURSE(allowed_store_types =
   1876                 ValidateHeapAccess(target_as_property, StoreToHeap));
   1877 
   1878     if (!value_type->IsA(allowed_store_types)) {
   1879       FAIL(assignment, "Type mismatch in heap assignment.");
   1880     }
   1881 
   1882     return value_type;
   1883   }
   1884 
   1885   FAIL(assignment, "Invalid asm.js assignment.");
   1886 }
   1887 
   1888 // 6.8.7 UnaryExpression
   1889 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   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   switch (unop->op()) {
   1907     default:
   1908       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       UNOP_OVERLOAD(Signed, Double);
   1913       UNOP_OVERLOAD(Unsigned, Double);
   1914       UNOP_OVERLOAD(DoubleQ, Double);
   1915       UNOP_OVERLOAD(FloatQ, Double);
   1916       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       UNOP_OVERLOAD(Int, Intish);
   1921       UNOP_OVERLOAD(DoubleQ, Double);
   1922       UNOP_OVERLOAD(FloatQ, Floatish);
   1923       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       UNOP_OVERLOAD(Intish, Signed);
   1928       FAIL(unop, "Invalid type for ~.");
   1929     case Token::NOT:
   1930       UNOP_OVERLOAD(Int, Int);
   1931       FAIL(unop, "Invalid type for !.");
   1932   }
   1933 
   1934 #undef UNOP_OVERLOAD
   1935 
   1936   UNREACHABLE();
   1937 }
   1938 
   1939 // 6.8.8 MultiplicativeExpression
   1940 namespace {
   1941 bool IsIntishLiteralFactor(Expression* expr, int32_t* factor) {
   1942   auto* literal = expr->AsLiteral();
   1943   if (literal == nullptr) {
   1944     return false;
   1945   }
   1946 
   1947   if (!IsLiteralInt(literal)) {
   1948     return false;
   1949   }
   1950 
   1951   if (!literal->value()->ToInt32(factor)) {
   1952     return false;
   1953   }
   1954   static const int32_t kIntishBound = 1 << 20;
   1955   return -kIntishBound < *factor && *factor < kIntishBound;
   1956 }
   1957 }  // namespace
   1958 
   1959 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   if (binop->op() == Token::MUL) {
   1967     int32_t factor;
   1968     if (IsIntishLiteralFactor(left, &factor)) {
   1969       AsmType* right_type;
   1970       RECURSE(right_type = ValidateExpression(right));
   1971       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     if (IsIntishLiteralFactor(right, &factor)) {
   1982       AsmType* left_type;
   1983       RECURSE(left_type = ValidateExpression(left));
   1984       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       if (factor == -1) {
   1993         // *VIOLATION* The frontend transforms -x into x * -1 (not -1.0, because
   1994         // consistency is overrated.)
   1995         if (left_type->IsA(AsmType::DoubleQ())) {
   1996           return AsmType::Double();
   1997         } else if (left_type->IsA(AsmType::FloatQ())) {
   1998           return AsmType::Floatish();
   1999         }
   2000       }
   2001     }
   2002   }
   2003 
   2004   if (intish_mul_failed) {
   2005     FAIL(binop, "Invalid types for intish * (or unary -).");
   2006   }
   2007 
   2008   AsmType* left_type;
   2009   AsmType* right_type;
   2010   RECURSE(left_type = ValidateExpression(left));
   2011   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   switch (binop->op()) {
   2020     default:
   2021       FAIL(binop, "Invalid multiplicative expression.");
   2022     case Token::MUL:
   2023       BINOP_OVERLOAD(DoubleQ, DoubleQ, Double);
   2024       BINOP_OVERLOAD(FloatQ, FloatQ, Floatish);
   2025       FAIL(binop, "Invalid operands for *.");
   2026     case Token::DIV:
   2027       BINOP_OVERLOAD(Signed, Signed, Intish);
   2028       BINOP_OVERLOAD(Unsigned, Unsigned, Intish);
   2029       BINOP_OVERLOAD(DoubleQ, DoubleQ, Double);
   2030       BINOP_OVERLOAD(FloatQ, FloatQ, Floatish);
   2031       FAIL(binop, "Invalid operands for /.");
   2032     case Token::MOD:
   2033       BINOP_OVERLOAD(Signed, Signed, Intish);
   2034       BINOP_OVERLOAD(Unsigned, Unsigned, Intish);
   2035       BINOP_OVERLOAD(DoubleQ, DoubleQ, Double);
   2036       FAIL(binop, "Invalid operands for %.");
   2037   }
   2038 #undef BINOP_OVERLOAD
   2039 
   2040   UNREACHABLE();
   2041 }
   2042 
   2043 // 6.8.9 AdditiveExpression
   2044 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   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   if (left_as_binop != nullptr && (left_as_binop->op() == Token::ADD ||
   2055                                    left_as_binop->op() == Token::SUB)) {
   2056     RECURSE(left_type =
   2057                 ValidateAdditiveExpression(left_as_binop, intish_count + 1));
   2058     SetTypeOf(left_as_binop, left_type);
   2059   } else {
   2060     RECURSE(left_type = ValidateExpression(left));
   2061   }
   2062 
   2063   auto* right = binop->right();
   2064   auto* right_as_binop = right->AsBinaryOperation();
   2065   AsmType* right_type;
   2066 
   2067   if (right_as_binop != nullptr && (right_as_binop->op() == Token::ADD ||
   2068                                     right_as_binop->op() == Token::SUB)) {
   2069     RECURSE(right_type =
   2070                 ValidateAdditiveExpression(right_as_binop, intish_count + 1));
   2071     SetTypeOf(right_as_binop, right_type);
   2072   } else {
   2073     RECURSE(right_type = ValidateExpression(right));
   2074   }
   2075 
   2076   if (left_type->IsA(AsmType::FloatQ()) && right_type->IsA(AsmType::FloatQ())) {
   2077     return AsmType::Floatish();
   2078   }
   2079 
   2080   if (left_type->IsA(AsmType::Int()) && right_type->IsA(AsmType::Int())) {
   2081     if (intish_count == 0) {
   2082       return AsmType::Intish();
   2083     }
   2084     if (intish_count < kMaxIntish) {
   2085       return AsmType::Int();
   2086     }
   2087     FAIL(binop, "Too many uncoerced integer additive expressions.");
   2088   }
   2089 
   2090   if (left_type->IsA(AsmType::Double()) && right_type->IsA(AsmType::Double())) {
   2091     return AsmType::Double();
   2092   }
   2093 
   2094   if (binop->op() == Token::SUB) {
   2095     if (left_type->IsA(AsmType::DoubleQ()) &&
   2096         right_type->IsA(AsmType::DoubleQ())) {
   2097       return AsmType::Double();
   2098     }
   2099   }
   2100 
   2101   FAIL(binop, "Invalid operands for additive expression.");
   2102 }
   2103 
   2104 // 6.8.10 ShiftExpression
   2105 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   RECURSE(left_type = ValidateExpression(left));
   2112   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   switch (binop->op()) {
   2121     default:
   2122       FAIL(binop, "Invalid shift expression.");
   2123     case Token::SHL:
   2124       BINOP_OVERLOAD(Intish, Intish, Signed);
   2125       FAIL(binop, "Invalid operands for <<.");
   2126     case Token::SAR:
   2127       BINOP_OVERLOAD(Intish, Intish, Signed);
   2128       FAIL(binop, "Invalid operands for >>.");
   2129     case Token::SHR:
   2130       BINOP_OVERLOAD(Intish, Intish, Unsigned);
   2131       FAIL(binop, "Invalid operands for >>>.");
   2132   }
   2133 #undef BINOP_OVERLOAD
   2134 
   2135   UNREACHABLE();
   2136 }
   2137 
   2138 // 6.8.11 RelationalExpression
   2139 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   RECURSE(left_type = ValidateExpression(left));
   2146   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   switch (cmpop->op()) {
   2155     default:
   2156       FAIL(cmpop, "Invalid relational expression.");
   2157     case Token::LT:
   2158       CMPOP_OVERLOAD(Signed, Signed, Int);
   2159       CMPOP_OVERLOAD(Unsigned, Unsigned, Int);
   2160       CMPOP_OVERLOAD(Float, Float, Int);
   2161       CMPOP_OVERLOAD(Double, Double, Int);
   2162       FAIL(cmpop, "Invalid operands for <.");
   2163     case Token::GT:
   2164       CMPOP_OVERLOAD(Signed, Signed, Int);
   2165       CMPOP_OVERLOAD(Unsigned, Unsigned, Int);
   2166       CMPOP_OVERLOAD(Float, Float, Int);
   2167       CMPOP_OVERLOAD(Double, Double, Int);
   2168       FAIL(cmpop, "Invalid operands for >.");
   2169     case Token::LTE:
   2170       CMPOP_OVERLOAD(Signed, Signed, Int);
   2171       CMPOP_OVERLOAD(Unsigned, Unsigned, Int);
   2172       CMPOP_OVERLOAD(Float, Float, Int);
   2173       CMPOP_OVERLOAD(Double, Double, Int);
   2174       FAIL(cmpop, "Invalid operands for <=.");
   2175     case Token::GTE:
   2176       CMPOP_OVERLOAD(Signed, Signed, Int);
   2177       CMPOP_OVERLOAD(Unsigned, Unsigned, Int);
   2178       CMPOP_OVERLOAD(Float, Float, Int);
   2179       CMPOP_OVERLOAD(Double, Double, Int);
   2180       FAIL(cmpop, "Invalid operands for >=.");
   2181   }
   2182 #undef CMPOP_OVERLOAD
   2183 
   2184   UNREACHABLE();
   2185 }
   2186 
   2187 // 6.8.12 EqualityExpression
   2188 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   RECURSE(left_type = ValidateExpression(left));
   2195   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   switch (cmpop->op()) {
   2204     default:
   2205       FAIL(cmpop, "Invalid equality expression.");
   2206     case Token::EQ:
   2207       CMPOP_OVERLOAD(Signed, Signed, Int);
   2208       CMPOP_OVERLOAD(Unsigned, Unsigned, Int);
   2209       CMPOP_OVERLOAD(Float, Float, Int);
   2210       CMPOP_OVERLOAD(Double, Double, Int);
   2211       FAIL(cmpop, "Invalid operands for ==.");
   2212     case Token::NE:
   2213       CMPOP_OVERLOAD(Signed, Signed, Int);
   2214       CMPOP_OVERLOAD(Unsigned, Unsigned, Int);
   2215       CMPOP_OVERLOAD(Float, Float, Int);
   2216       CMPOP_OVERLOAD(Double, Double, Int);
   2217       FAIL(cmpop, "Invalid operands for !=.");
   2218   }
   2219 #undef CMPOP_OVERLOAD
   2220 
   2221   UNREACHABLE();
   2222 }
   2223 
   2224 // 6.8.13 BitwiseANDExpression
   2225 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   RECURSE(left_type = ValidateExpression(left));
   2232   RECURSE(right_type = ValidateExpression(right));
   2233 
   2234   if (binop->op() != Token::BIT_AND) {
   2235     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   BINOP_OVERLOAD(Intish, Intish, Signed);
   2245   FAIL(binop, "Invalid operands for &.");
   2246 #undef BINOP_OVERLOAD
   2247 
   2248   UNREACHABLE();
   2249 }
   2250 
   2251 // 6.8.14 BitwiseXORExpression
   2252 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   RECURSE(left_type = ValidateExpression(left));
   2259   RECURSE(right_type = ValidateExpression(right));
   2260 
   2261   if (binop->op() != Token::BIT_XOR) {
   2262     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   BINOP_OVERLOAD(Intish, Intish, Signed);
   2272   FAIL(binop, "Invalid operands for ^.");
   2273 #undef BINOP_OVERLOAD
   2274 
   2275   UNREACHABLE();
   2276 }
   2277 
   2278 // 6.8.15 BitwiseORExpression
   2279 AsmType* AsmTyper::ValidateBitwiseORExpression(BinaryOperation* binop) {
   2280   auto* left = binop->left();
   2281   if (IsIntAnnotation(binop)) {
   2282     if (auto* left_as_call = left->AsCall()) {
   2283       AsmType* type;
   2284       RECURSE(type = ValidateCall(AsmType::Signed(), left_as_call));
   2285       return type;
   2286     }
   2287     AsmType* left_type;
   2288     RECURSE(left_type = ValidateExpression(left));
   2289     if (!left_type->IsA(AsmType::Intish())) {
   2290       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   RECURSE(left_type = ValidateExpression(left));
   2299   RECURSE(right_type = ValidateExpression(right));
   2300 
   2301   if (binop->op() != Token::BIT_OR) {
   2302     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   BINOP_OVERLOAD(Intish, Intish, Signed);
   2312   FAIL(binop, "Invalid operands for |.");
   2313 #undef BINOP_OVERLOAD
   2314 
   2315   UNREACHABLE();
   2316 }
   2317 
   2318 // 6.8.16 ConditionalExpression
   2319 AsmType* AsmTyper::ValidateConditionalExpression(Conditional* cond) {
   2320   AsmType* cond_type;
   2321   RECURSE(cond_type = ValidateExpression(cond->condition()));
   2322   if (!cond_type->IsA(AsmType::Int())) {
   2323     FAIL(cond, "Ternary operation condition should be int.");
   2324   }
   2325 
   2326   AsmType* then_type;
   2327   RECURSE(then_type = ValidateExpression(cond->then_expression()));
   2328   AsmType* else_type;
   2329   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   SUCCEED_IF_BOTH_ARE(Int);
   2341   SUCCEED_IF_BOTH_ARE(Float);
   2342   SUCCEED_IF_BOTH_ARE(Double);
   2343 #undef SUCCEED_IF_BOTH_ARE
   2344 
   2345   FAIL(cond, "Ternary operator must return int, float, or double.");
   2346 }
   2347 
   2348 // 6.9 ValidateCall
   2349 namespace {
   2350 bool ExtractIndirectCallMask(Expression* expr, uint32_t* value) {
   2351   auto* as_literal = expr->AsLiteral();
   2352   if (as_literal == nullptr) {
   2353     return false;
   2354   }
   2355 
   2356   if (!IsLiteralInt(as_literal)) {
   2357     return false;
   2358   }
   2359 
   2360   if (!as_literal->value()->ToUint32(value)) {
   2361     return false;
   2362   }
   2363 
   2364   return base::bits::IsPowerOfTwo32(1 + *value);
   2365 }
   2366 }  // namespace
   2367 
   2368 AsmType* AsmTyper::ValidateCall(AsmType* return_type, Call* call) {
   2369   AsmType* float_coercion_type;
   2370   RECURSE(float_coercion_type = ValidateFloatCoercion(call));
   2371   if (float_coercion_type == AsmType::Float()) {
   2372     SetTypeOf(call, AsmType::Float());
   2373     return return_type;
   2374   }
   2375 
   2376   // TODO(jpp): we should be able to reuse the args vector's storage space.
   2377   ZoneVector<AsmType*> args(zone_);
   2378   args.reserve(call->arguments()->length());
   2379 
   2380   for (auto* arg : *call->arguments()) {
   2381     AsmType* arg_type;
   2382     RECURSE(arg_type = ValidateExpression(arg));
   2383     args.emplace_back(arg_type);
   2384   }
   2385 
   2386   auto* call_expr = call->expression();
   2387 
   2388   // identifier(Expression...)
   2389   if (auto* call_var_proxy = call_expr->AsVariableProxy()) {
   2390     auto* call_var_info = Lookup(call_var_proxy->var());
   2391 
   2392     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       auto* call_type = AsmType::Function(zone_, return_type)->AsFunctionType();
   2397       for (auto* arg : args) {
   2398         call_type->AddArgument(arg->ToParameterType());
   2399       }
   2400       auto* fun_info =
   2401           new (zone_) VariableInfo(reinterpret_cast<AsmType*>(call_type));
   2402       fun_info->set_mutability(VariableInfo::kImmutableGlobal);
   2403       AddForwardReference(call_var_proxy, fun_info);
   2404       if (!ValidAsmIdentifier(call_var_proxy->name())) {
   2405         FAIL(call_var_proxy,
   2406              "Invalid asm.js identifier in (forward) function name.");
   2407       }
   2408       if (!AddGlobal(call_var_proxy->var(), fun_info)) {
   2409         DCHECK(false);
   2410         FAIL(call, "Redeclared global identifier.");
   2411       }
   2412       if (call->GetCallType() != Call::OTHER_CALL) {
   2413         FAIL(call, "Invalid call of existing global function.");
   2414       }
   2415       SetTypeOf(call_var_proxy, reinterpret_cast<AsmType*>(call_type));
   2416       SetTypeOf(call, return_type);
   2417       return return_type;
   2418     }
   2419 
   2420     auto* callee_type = call_var_info->type()->AsCallableType();
   2421     if (callee_type == nullptr) {
   2422       FAIL(call, "Calling something that's not a function.");
   2423     }
   2424 
   2425     if (callee_type->AsFFIType() != nullptr) {
   2426       if (return_type == AsmType::Float()) {
   2427         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           FFIUseSignature(call_var_proxy->var(), zone_));
   2433       FFIUseSignature* sig = &ffi_use_signatures_.back();
   2434       sig->return_type_ = return_type;
   2435       sig->arg_types_.reserve(args.size());
   2436       for (size_t i = 0; i < args.size(); ++i) {
   2437         sig->arg_types_.emplace_back(args[i]);
   2438       }
   2439     }
   2440 
   2441     if (!callee_type->CanBeInvokedWith(return_type, args)) {
   2442       FAIL(call, "Function invocation does not match function type.");
   2443     }
   2444 
   2445     if (call->GetCallType() != Call::OTHER_CALL) {
   2446       FAIL(call, "Invalid forward call of global function.");
   2447     }
   2448 
   2449     SetTypeOf(call_var_proxy, call_var_info->type());
   2450     SetTypeOf(call, return_type);
   2451     return return_type;
   2452   }
   2453 
   2454   // identifier[expr & n](Expression...)
   2455   if (auto* call_property = call_expr->AsProperty()) {
   2456     auto* index = call_property->key()->AsBinaryOperation();
   2457     if (index == nullptr || index->op() != Token::BIT_AND) {
   2458       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     if (!ExtractIndirectCallMask(right, &mask)) {
   2466       if (!ExtractIndirectCallMask(left, &mask)) {
   2467         FAIL(right, "Invalid indirect call mask.");
   2468       } else {
   2469         left = right;
   2470       }
   2471     }
   2472     const uint32_t table_length = mask + 1;
   2473 
   2474     AsmType* left_type;
   2475     RECURSE(left_type = ValidateExpression(left));
   2476     if (!left_type->IsA(AsmType::Intish())) {
   2477       FAIL(left, "Indirect call index should be an intish.");
   2478     }
   2479 
   2480     auto* name_var = call_property->obj()->AsVariableProxy();
   2481 
   2482     if (name_var == nullptr) {
   2483       FAIL(call_property, "Invalid call.");
   2484     }
   2485 
   2486     auto* name_info = Lookup(name_var->var());
   2487     if (name_info == nullptr) {
   2488       // We can't fail here -- just like above.
   2489       auto* call_type = AsmType::Function(zone_, return_type)->AsFunctionType();
   2490       for (auto* arg : args) {
   2491         call_type->AddArgument(arg->ToParameterType());
   2492       }
   2493       auto* table_type = AsmType::FunctionTableType(
   2494           zone_, table_length, reinterpret_cast<AsmType*>(call_type));
   2495       auto* fun_info =
   2496           new (zone_) VariableInfo(reinterpret_cast<AsmType*>(table_type));
   2497       fun_info->set_mutability(VariableInfo::kImmutableGlobal);
   2498       AddForwardReference(name_var, fun_info);
   2499       if (!ValidAsmIdentifier(name_var->name())) {
   2500         FAIL(name_var,
   2501              "Invalid asm.js identifier in (forward) function table name.");
   2502       }
   2503       if (!AddGlobal(name_var->var(), fun_info)) {
   2504         DCHECK(false);
   2505         FAIL(call, "Redeclared global identifier.");
   2506       }
   2507       if (call->GetCallType() != Call::KEYED_PROPERTY_CALL) {
   2508         FAIL(call, "Invalid call of existing function table.");
   2509       }
   2510       SetTypeOf(call_property, reinterpret_cast<AsmType*>(call_type));
   2511       SetTypeOf(call, return_type);
   2512       return return_type;
   2513     }
   2514 
   2515     auto* previous_type = name_info->type()->AsFunctionTableType();
   2516     if (previous_type == nullptr) {
   2517       FAIL(call, "Identifier does not name a function table.");
   2518     }
   2519 
   2520     if (table_length != previous_type->length()) {
   2521       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     if (!previous_type_signature->CanBeInvokedWith(return_type, args)) {
   2528       // TODO(jpp): better error messages.
   2529       FAIL(call,
   2530            "Function pointer table signature does not match previous "
   2531            "signature.");
   2532     }
   2533 
   2534     if (call->GetCallType() != Call::KEYED_PROPERTY_CALL) {
   2535       FAIL(call, "Invalid forward call of function table.");
   2536     }
   2537     SetTypeOf(call_property, previous_type->signature());
   2538     SetTypeOf(call, return_type);
   2539     return return_type;
   2540   }
   2541 
   2542   FAIL(call, "Invalid call.");
   2543 }
   2544 
   2545 // 6.10 ValidateHeapAccess
   2546 namespace {
   2547 bool ExtractHeapAccessShift(Expression* expr, uint32_t* value) {
   2548   auto* as_literal = expr->AsLiteral();
   2549   if (as_literal == nullptr) {
   2550     return false;
   2551   }
   2552 
   2553   if (!IsLiteralInt(as_literal)) {
   2554     return false;
   2555   }
   2556 
   2557   return as_literal->value()->ToUint32(value);
   2558 }
   2559 
   2560 // Returns whether index is too large to access a heap with the given type.
   2561 bool LiteralIndexOutOfBounds(AsmType* obj_type, uint32_t index) {
   2562   switch (obj_type->ElementSizeInBytes()) {
   2563     case 1:
   2564       return false;
   2565     case 2:
   2566       return (index & 0x80000000u) != 0;
   2567     case 4:
   2568       return (index & 0xC0000000u) != 0;
   2569     case 8:
   2570       return (index & 0xE0000000u) != 0;
   2571   }
   2572   UNREACHABLE();
   2573   return true;
   2574 }
   2575 
   2576 }  // namespace
   2577 
   2578 AsmType* AsmTyper::ValidateHeapAccess(Property* heap,
   2579                                       HeapAccessType access_type) {
   2580   auto* obj = heap->obj()->AsVariableProxy();
   2581   if (obj == nullptr) {
   2582     FAIL(heap, "Invalid heap access.");
   2583   }
   2584 
   2585   auto* obj_info = Lookup(obj->var());
   2586   if (obj_info == nullptr) {
   2587     FAIL(heap, "Undeclared identifier in heap access.");
   2588   }
   2589 
   2590   auto* obj_type = obj_info->type();
   2591   if (!obj_type->IsA(AsmType::Heap())) {
   2592     FAIL(heap, "Identifier does not represent a heap view.");
   2593   }
   2594   SetTypeOf(obj, obj_type);
   2595 
   2596   if (auto* key_as_literal = heap->key()->AsLiteral()) {
   2597     if (!IsLiteralInt(key_as_literal)) {
   2598       FAIL(key_as_literal, "Heap access index must be int.");
   2599     }
   2600 
   2601     uint32_t index;
   2602     if (!key_as_literal->value()->ToUint32(&index)) {
   2603       FAIL(key_as_literal,
   2604            "Heap access index must be a 32-bit unsigned integer.");
   2605     }
   2606 
   2607     if (LiteralIndexOutOfBounds(obj_type, index)) {
   2608       FAIL(key_as_literal, "Heap access index is out of bounds");
   2609     }
   2610 
   2611     if (access_type == LoadFromHeap) {
   2612       return obj_type->LoadType();
   2613     }
   2614     return obj_type->StoreType();
   2615   }
   2616 
   2617   if (auto* key_as_binop = heap->key()->AsBinaryOperation()) {
   2618     uint32_t shift;
   2619     if (key_as_binop->op() == Token::SAR &&
   2620         ExtractHeapAccessShift(key_as_binop->right(), &shift) &&
   2621         (1 << shift) == obj_type->ElementSizeInBytes()) {
   2622       AsmType* type;
   2623       RECURSE(type = ValidateExpression(key_as_binop->left()));
   2624       if (type->IsA(AsmType::Intish())) {
   2625         if (access_type == LoadFromHeap) {
   2626           return obj_type->LoadType();
   2627         }
   2628         return obj_type->StoreType();
   2629       }
   2630       FAIL(key_as_binop, "Invalid heap access index.");
   2631     }
   2632   }
   2633 
   2634   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     RECURSE(index_type = ValidateExpression(heap->key()));
   2639     if (!index_type->IsA(AsmType::Int())) {
   2640       FAIL(heap, "Invalid heap access index for byte array.");
   2641     }
   2642     if (access_type == LoadFromHeap) {
   2643       return obj_type->LoadType();
   2644     }
   2645     return obj_type->StoreType();
   2646   }
   2647 
   2648   FAIL(heap, "Invalid heap access index.");
   2649 }
   2650 
   2651 // 6.11 ValidateFloatCoercion
   2652 bool AsmTyper::IsCallToFround(Call* call) {
   2653   if (call->arguments()->length() != 1) {
   2654     return false;
   2655   }
   2656 
   2657   auto* call_var_proxy = call->expression()->AsVariableProxy();
   2658   if (call_var_proxy == nullptr) {
   2659     return false;
   2660   }
   2661 
   2662   auto* call_var_info = Lookup(call_var_proxy->var());
   2663   if (call_var_info == nullptr) {
   2664     return false;
   2665   }
   2666 
   2667   return call_var_info->standard_member() == kMathFround;
   2668 }
   2669 
   2670 AsmType* AsmTyper::ValidateFloatCoercion(Call* call) {
   2671   if (!IsCallToFround(call)) {
   2672     return nullptr;
   2673   }
   2674 
   2675   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   if (auto* arg_as_call = arg->AsCall()) {
   2679     RECURSE(ValidateCall(AsmType::Float(), arg_as_call));
   2680     return AsmType::Float();
   2681   }
   2682 
   2683   // 2. fround is used for converting to float.
   2684   AsmType* arg_type;
   2685   RECURSE(arg_type = ValidateExpression(arg));
   2686   if (arg_type->IsA(AsmType::Floatish()) || arg_type->IsA(AsmType::DoubleQ()) ||
   2687       arg_type->IsA(AsmType::Signed()) || arg_type->IsA(AsmType::Unsigned())) {
   2688     SetTypeOf(call->expression(), fround_type_);
   2689     return AsmType::Float();
   2690   }
   2691 
   2692   FAIL(call, "Invalid argument type to fround.");
   2693 }
   2694 
   2695 // 5.1 ParameterTypeAnnotations
   2696 AsmType* AsmTyper::ParameterTypeAnnotations(Variable* parameter,
   2697                                             Expression* annotation) {
   2698   if (auto* binop = annotation->AsBinaryOperation()) {
   2699     // Must be:
   2700     //   * x|0
   2701     //   * x*1 (*VIOLATION* i.e.,, +x)
   2702     auto* left = binop->left()->AsVariableProxy();
   2703     if (left == nullptr) {
   2704       FAIL(
   2705           binop->left(),
   2706           "Invalid parameter type annotation - should annotate an identifier.");
   2707     }
   2708     if (left->var() != parameter) {
   2709       FAIL(binop->left(),
   2710            "Invalid parameter type annotation - should annotate a parameter.");
   2711     }
   2712     if (IsDoubleAnnotation(binop)) {
   2713       SetTypeOf(left, AsmType::Double());
   2714       return AsmType::Double();
   2715     }
   2716     if (IsIntAnnotation(binop)) {
   2717       SetTypeOf(left, AsmType::Int());
   2718       return AsmType::Int();
   2719     }
   2720     FAIL(binop, "Invalid parameter type annotation.");
   2721   }
   2722 
   2723   auto* call = annotation->AsCall();
   2724   if (call == nullptr) {
   2725     FAIL(
   2726         annotation,
   2727         "Invalid float parameter type annotation - must be fround(parameter).");
   2728   }
   2729 
   2730   if (!IsCallToFround(call)) {
   2731     FAIL(annotation,
   2732          "Invalid float parameter type annotation - must be call to fround.");
   2733   }
   2734 
   2735   auto* src_expr = call->arguments()->at(0)->AsVariableProxy();
   2736   if (src_expr == nullptr) {
   2737     FAIL(annotation,
   2738          "Invalid float parameter type annotation - argument to fround is not "
   2739          "an identifier.");
   2740   }
   2741 
   2742   if (src_expr->var() != parameter) {
   2743     FAIL(annotation,
   2744          "Invalid float parameter type annotation - argument to fround is not "
   2745          "a parameter.");
   2746   }
   2747 
   2748   SetTypeOf(src_expr, AsmType::Float());
   2749   return AsmType::Float();
   2750 }
   2751 
   2752 // 5.2 ReturnTypeAnnotations
   2753 AsmType* AsmTyper::ReturnTypeAnnotations(Expression* ret_expr) {
   2754   DCHECK_NOT_NULL(ret_expr);
   2755 
   2756   if (auto* binop = ret_expr->AsBinaryOperation()) {
   2757     if (IsDoubleAnnotation(binop)) {
   2758       return AsmType::Double();
   2759     } else if (IsIntAnnotation(binop)) {
   2760       return AsmType::Signed();
   2761     }
   2762     FAIL(ret_expr, "Invalid return type annotation.");
   2763   }
   2764 
   2765   if (auto* call = ret_expr->AsCall()) {
   2766     if (IsCallToFround(call)) {
   2767       return AsmType::Float();
   2768     }
   2769     FAIL(ret_expr, "Invalid function call in return statement.");
   2770   }
   2771 
   2772   if (auto* literal = ret_expr->AsLiteral()) {
   2773     int32_t _;
   2774     if (IsLiteralDouble(literal)) {
   2775       return AsmType::Double();
   2776     } else if (IsLiteralInt(literal) && literal->value()->ToInt32(&_)) {
   2777       return AsmType::Signed();
   2778     } 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     FAIL(ret_expr, "Invalid literal in return statement.");
   2789   }
   2790 
   2791   if (auto* proxy = ret_expr->AsVariableProxy()) {
   2792     auto* var_info = Lookup(proxy->var());
   2793 
   2794     if (var_info == nullptr) {
   2795       FAIL(ret_expr, "Undeclared identifier in return statement.");
   2796     }
   2797 
   2798     if (var_info->mutability() != VariableInfo::kConstGlobal) {
   2799       FAIL(ret_expr, "Identifier in return statement is not const.");
   2800     }
   2801 
   2802     if (!var_info->type()->IsReturnType()) {
   2803       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   if (auto* cond = ret_expr->AsConditional()) {
   2812     AsmType* a = AsmType::None();
   2813     AsmType* b = AsmType::None();
   2814     RECURSE(a = ReturnTypeAnnotations(cond->then_expression()));
   2815     if (a->IsA(AsmType::None())) {
   2816       return a;
   2817     }
   2818     RECURSE(b = ReturnTypeAnnotations(cond->else_expression()));
   2819     if (b->IsA(AsmType::None())) {
   2820       return b;
   2821     }
   2822     if (a->IsExactly(b)) {
   2823       return a;
   2824     }
   2825   }
   2826 
   2827   FAIL(ret_expr, "Invalid return type expression.");
   2828 }
   2829 
   2830 // 5.4 VariableTypeAnnotations
   2831 // Also used for 5.5 GlobalVariableTypeAnnotations
   2832 AsmType* AsmTyper::VariableTypeAnnotations(
   2833     Expression* initializer, VariableInfo::Mutability mutability_type) {
   2834   if (auto* literal = initializer->AsLiteral()) {
   2835     if (IsLiteralDouble(literal)) {
   2836       SetTypeOf(initializer, AsmType::Double());
   2837       return AsmType::Double();
   2838     }
   2839     if (!IsLiteralInt(literal)) {
   2840       FAIL(initializer, "Invalid type annotation - forbidden literal.");
   2841     }
   2842     int32_t i32;
   2843     uint32_t u32;
   2844     AsmType* initializer_type = nullptr;
   2845     if (literal->value()->ToUint32(&u32)) {
   2846       if (u32 > LargestFixNum) {
   2847         initializer_type = AsmType::Unsigned();
   2848         SetTypeOf(initializer, initializer_type);
   2849       } else {
   2850         initializer_type = AsmType::FixNum();
   2851         SetTypeOf(initializer, initializer_type);
   2852         initializer_type = AsmType::Signed();
   2853       }
   2854     } else if (literal->value()->ToInt32(&i32)) {
   2855       initializer_type = AsmType::Signed();
   2856       SetTypeOf(initializer, initializer_type);
   2857     } else {
   2858       FAIL(initializer, "Invalid type annotation - forbidden literal.");
   2859     }
   2860     if (mutability_type != VariableInfo::kConstGlobal) {
   2861       return AsmType::Int();
   2862     }
   2863     return initializer_type;
   2864   }
   2865 
   2866   if (auto* proxy = initializer->AsVariableProxy()) {
   2867     auto* var_info = Lookup(proxy->var());
   2868 
   2869     if (var_info == nullptr) {
   2870       FAIL(initializer,
   2871            "Undeclared identifier in variable declaration initializer.");
   2872     }
   2873 
   2874     if (var_info->mutability() != VariableInfo::kConstGlobal) {
   2875       FAIL(initializer,
   2876            "Identifier in variable declaration initializer must be const.");
   2877     }
   2878 
   2879     SetTypeOf(initializer, var_info->type());
   2880     return var_info->type();
   2881   }
   2882 
   2883   auto* call = initializer->AsCall();
   2884   if (call == nullptr) {
   2885     FAIL(initializer,
   2886          "Invalid variable initialization - it should be a literal, const, or "
   2887          "fround(literal).");
   2888   }
   2889 
   2890   if (!IsCallToFround(call)) {
   2891     FAIL(initializer,
   2892          "Invalid float coercion - expected call fround(literal).");
   2893   }
   2894 
   2895   auto* src_expr = call->arguments()->at(0)->AsLiteral();
   2896   if (src_expr == nullptr) {
   2897     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   if (!src_expr->raw_value()->IsNumber()) {
   2910     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 AsmType* AsmTyper::NewHeapView(CallNew* new_heap_view) {
   2920   auto* heap_type = new_heap_view->expression()->AsProperty();
   2921   if (heap_type == nullptr) {
   2922     FAIL(new_heap_view, "Invalid type after new.");
   2923   }
   2924   auto* heap_view_info = ImportLookup(heap_type);
   2925 
   2926   if (heap_view_info == nullptr) {
   2927     FAIL(new_heap_view, "Unknown stdlib member in heap view declaration.");
   2928   }
   2929 
   2930   if (!heap_view_info->type()->IsA(AsmType::Heap())) {
   2931     FAIL(new_heap_view, "Type is not a heap view type.");
   2932   }
   2933 
   2934   if (new_heap_view->arguments()->length() != 1) {
   2935     FAIL(new_heap_view, "Invalid number of arguments when creating heap view.");
   2936   }
   2937 
   2938   auto* heap = new_heap_view->arguments()->at(0);
   2939   auto* heap_var_proxy = heap->AsVariableProxy();
   2940 
   2941   if (heap_var_proxy == nullptr) {
   2942     FAIL(heap,
   2943          "Heap view creation parameter should be the module's heap parameter.");
   2944   }
   2945 
   2946   auto* heap_var_info = Lookup(heap_var_proxy->var());
   2947 
   2948   if (heap_var_info == nullptr) {
   2949     FAIL(heap, "Undeclared identifier instead of heap parameter.");
   2950   }
   2951 
   2952   if (!heap_var_info->IsHeap()) {
   2953     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   return heap_view_info->type();
   2959 }
   2960 
   2961 }  // namespace wasm
   2962 }  // namespace internal
   2963 }  // namespace v8
   2964