Home | History | Annotate | Download | only in asmjs
      1 // Copyright 2015 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/v8.h"
      6 
      7 // Required to get M_E etc. in MSVC.
      8 #if defined(_WIN32)
      9 #define _USE_MATH_DEFINES
     10 #endif
     11 #include <math.h>
     12 
     13 #include "src/asmjs/asm-types.h"
     14 #include "src/asmjs/asm-wasm-builder.h"
     15 #include "src/asmjs/switch-logic.h"
     16 
     17 #include "src/wasm/wasm-macro-gen.h"
     18 #include "src/wasm/wasm-opcodes.h"
     19 
     20 #include "src/ast/ast.h"
     21 #include "src/ast/scopes.h"
     22 #include "src/codegen.h"
     23 #include "src/compilation-info.h"
     24 #include "src/compiler.h"
     25 #include "src/counters.h"
     26 #include "src/isolate.h"
     27 #include "src/objects-inl.h"
     28 #include "src/parsing/parse-info.h"
     29 
     30 namespace v8 {
     31 namespace internal {
     32 namespace wasm {
     33 
     34 #define RECURSE(call)               \
     35   do {                              \
     36     DCHECK(!HasStackOverflow());    \
     37     call;                           \
     38     if (HasStackOverflow()) return; \
     39   } while (false)
     40 
     41 namespace {
     42 
     43 enum AsmScope { kModuleScope, kInitScope, kFuncScope, kExportScope };
     44 enum ValueFate { kDrop, kLeaveOnStack };
     45 
     46 struct ForeignVariable {
     47   Handle<Name> name;
     48   Variable* var;
     49   ValueType type;
     50 };
     51 
     52 enum TargetType : uint8_t { NoTarget, BreakTarget, ContinueTarget };
     53 
     54 }  // namespace
     55 
     56 class AsmWasmBuilderImpl final : public AstVisitor<AsmWasmBuilderImpl> {
     57  public:
     58   AsmWasmBuilderImpl(Isolate* isolate, Zone* zone, CompilationInfo* info,
     59                      AstValueFactory* ast_value_factory, Handle<Script> script,
     60                      FunctionLiteral* literal, AsmTyper* typer)
     61       : local_variables_(ZoneHashMap::kDefaultHashMapCapacity,
     62                          ZoneAllocationPolicy(zone)),
     63         functions_(ZoneHashMap::kDefaultHashMapCapacity,
     64                    ZoneAllocationPolicy(zone)),
     65         global_variables_(ZoneHashMap::kDefaultHashMapCapacity,
     66                           ZoneAllocationPolicy(zone)),
     67         scope_(kModuleScope),
     68         builder_(new (zone) WasmModuleBuilder(zone)),
     69         current_function_builder_(nullptr),
     70         literal_(literal),
     71         isolate_(isolate),
     72         zone_(zone),
     73         info_(info),
     74         ast_value_factory_(ast_value_factory),
     75         script_(script),
     76         typer_(typer),
     77         typer_failed_(false),
     78         typer_finished_(false),
     79         breakable_blocks_(zone),
     80         foreign_variables_(zone),
     81         init_function_(nullptr),
     82         foreign_init_function_(nullptr),
     83         function_tables_(ZoneHashMap::kDefaultHashMapCapacity,
     84                          ZoneAllocationPolicy(zone)),
     85         imported_function_table_(this),
     86         parent_binop_(nullptr) {
     87     InitializeAstVisitor(isolate);
     88   }
     89 
     90   void InitializeInitFunction() {
     91     FunctionSig::Builder b(zone(), 0, 0);
     92     init_function_ = builder_->AddFunction(b.Build());
     93     builder_->MarkStartFunction(init_function_);
     94   }
     95 
     96   void BuildForeignInitFunction() {
     97     foreign_init_function_ = builder_->AddFunction();
     98     FunctionSig::Builder b(zone(), 0, foreign_variables_.size());
     99     for (auto i = foreign_variables_.begin(); i != foreign_variables_.end();
    100          ++i) {
    101       b.AddParam(i->type);
    102     }
    103     foreign_init_function_->ExportAs(
    104         CStrVector(AsmWasmBuilder::foreign_init_name));
    105     foreign_init_function_->SetSignature(b.Build());
    106     for (size_t pos = 0; pos < foreign_variables_.size(); ++pos) {
    107       foreign_init_function_->EmitGetLocal(static_cast<uint32_t>(pos));
    108       ForeignVariable* fv = &foreign_variables_[pos];
    109       uint32_t index = LookupOrInsertGlobal(fv->var, fv->type);
    110       foreign_init_function_->EmitWithVarUint(kExprSetGlobal, index);
    111     }
    112     foreign_init_function_->Emit(kExprEnd);
    113   }
    114 
    115   Handle<FixedArray> GetForeignArgs() {
    116     Handle<FixedArray> ret = isolate_->factory()->NewFixedArray(
    117         static_cast<int>(foreign_variables_.size()));
    118     for (size_t i = 0; i < foreign_variables_.size(); ++i) {
    119       ForeignVariable* fv = &foreign_variables_[i];
    120       ret->set(static_cast<int>(i), *fv->name);
    121     }
    122     return ret;
    123   }
    124 
    125   bool Build() {
    126     InitializeInitFunction();
    127     if (!typer_->ValidateBeforeFunctionsPhase()) {
    128       return false;
    129     }
    130     DCHECK(!HasStackOverflow());
    131     VisitFunctionLiteral(literal_);
    132     if (HasStackOverflow()) {
    133       return false;
    134     }
    135     if (!typer_finished_ && !typer_failed_) {
    136       typer_->FailWithMessage("Module missing export section.");
    137       typer_failed_ = true;
    138     }
    139     if (typer_failed_) {
    140       return false;
    141     }
    142     BuildForeignInitFunction();
    143     init_function_->Emit(kExprEnd);  // finish init function.
    144     return true;
    145   }
    146 
    147   void VisitVariableDeclaration(VariableDeclaration* decl) {}
    148 
    149   void VisitFunctionDeclaration(FunctionDeclaration* decl) {
    150     DCHECK_EQ(kModuleScope, scope_);
    151     DCHECK_NULL(current_function_builder_);
    152     FunctionLiteral* old_func = decl->fun();
    153     DeclarationScope* new_func_scope = nullptr;
    154     std::unique_ptr<ParseInfo> info;
    155     if (decl->fun()->body() == nullptr) {
    156       // TODO(titzer/bradnelson): Reuse SharedFunctionInfos used here when
    157       // compiling the wasm module.
    158       Handle<SharedFunctionInfo> shared =
    159           Compiler::GetSharedFunctionInfo(decl->fun(), script_, info_);
    160       shared->set_is_toplevel(false);
    161       info.reset(new ParseInfo(script_));
    162       info->set_shared_info(shared);
    163       info->set_toplevel(false);
    164       info->set_language_mode(decl->fun()->scope()->language_mode());
    165       info->set_allow_lazy_parsing(false);
    166       info->set_function_literal_id(shared->function_literal_id());
    167       info->set_ast_value_factory(ast_value_factory_);
    168       info->set_ast_value_factory_owned(false);
    169       // Create fresh function scope to use to parse the function in.
    170       new_func_scope = new (info->zone()) DeclarationScope(
    171           info->zone(), decl->fun()->scope()->outer_scope(), FUNCTION_SCOPE);
    172       info->set_asm_function_scope(new_func_scope);
    173       if (!Compiler::ParseAndAnalyze(info.get())) {
    174         decl->fun()->scope()->outer_scope()->RemoveInnerScope(new_func_scope);
    175         if (isolate_->has_pending_exception()) {
    176           isolate_->clear_pending_exception();
    177         }
    178         typer_->TriggerParsingError();
    179         typer_failed_ = true;
    180         return;
    181       }
    182       FunctionLiteral* func = info->literal();
    183       DCHECK_NOT_NULL(func);
    184       decl->set_fun(func);
    185     }
    186     if (!typer_->ValidateInnerFunction(decl)) {
    187       typer_failed_ = true;
    188       decl->set_fun(old_func);
    189       if (new_func_scope != nullptr) {
    190         DCHECK_EQ(new_func_scope, decl->scope()->inner_scope());
    191         if (!decl->scope()->RemoveInnerScope(new_func_scope)) {
    192           UNREACHABLE();
    193         }
    194       }
    195       return;
    196     }
    197     current_function_builder_ = LookupOrInsertFunction(decl->proxy()->var());
    198     scope_ = kFuncScope;
    199 
    200     // Record start of the function, used as position for the stack check.
    201     current_function_builder_->SetAsmFunctionStartPosition(
    202         decl->fun()->start_position());
    203 
    204     RECURSE(Visit(decl->fun()));
    205     decl->set_fun(old_func);
    206     if (new_func_scope != nullptr) {
    207       DCHECK_EQ(new_func_scope, decl->scope()->inner_scope());
    208       if (!decl->scope()->RemoveInnerScope(new_func_scope)) {
    209         UNREACHABLE();
    210       }
    211     }
    212     scope_ = kModuleScope;
    213     current_function_builder_ = nullptr;
    214     local_variables_.Clear();
    215     typer_->ClearFunctionNodeTypes();
    216   }
    217 
    218   void VisitStatements(ZoneList<Statement*>* stmts) {
    219     for (int i = 0; i < stmts->length(); ++i) {
    220       Statement* stmt = stmts->at(i);
    221       ExpressionStatement* e = stmt->AsExpressionStatement();
    222       if (e != nullptr && e->expression()->IsUndefinedLiteral()) {
    223         continue;
    224       }
    225       RECURSE(Visit(stmt));
    226       if (typer_failed_) break;
    227     }
    228   }
    229 
    230   void VisitBlock(Block* stmt) {
    231     if (stmt->statements()->length() == 1) {
    232       ExpressionStatement* expr =
    233           stmt->statements()->at(0)->AsExpressionStatement();
    234       if (expr != nullptr) {
    235         if (expr->expression()->IsAssignment()) {
    236           RECURSE(VisitExpressionStatement(expr));
    237           return;
    238         }
    239       }
    240     }
    241     if (scope_ == kFuncScope) {
    242       BlockVisitor visitor(this, stmt->AsBreakableStatement(), kExprBlock,
    243                            BreakTarget);
    244       RECURSE(VisitStatements(stmt->statements()));
    245     } else {
    246       RECURSE(VisitStatements(stmt->statements()));
    247     }
    248   }
    249 
    250   class BlockVisitor {
    251    private:
    252     AsmWasmBuilderImpl* builder_;
    253 
    254    public:
    255     BlockVisitor(AsmWasmBuilderImpl* builder, BreakableStatement* stmt,
    256                  WasmOpcode opcode, TargetType target_type = NoTarget)
    257         : builder_(builder) {
    258       builder_->breakable_blocks_.emplace_back(stmt, target_type);
    259       // block and loops have a type immediate.
    260       builder_->current_function_builder_->EmitWithU8(opcode, kLocalVoid);
    261     }
    262     ~BlockVisitor() {
    263       builder_->current_function_builder_->Emit(kExprEnd);
    264       builder_->breakable_blocks_.pop_back();
    265     }
    266   };
    267 
    268   void VisitExpressionStatement(ExpressionStatement* stmt) {
    269     VisitForEffect(stmt->expression());
    270   }
    271 
    272   void VisitForEffect(Expression* expr) {
    273     if (expr->IsAssignment()) {
    274       // Don't emit drops for assignments. Instead use SetLocal/GetLocal.
    275       VisitAssignment(expr->AsAssignment(), kDrop);
    276       return;
    277     }
    278     if (expr->IsCall()) {
    279       // Only emit a drop if the call has a non-void return value.
    280       if (VisitCallExpression(expr->AsCall()) && scope_ == kFuncScope) {
    281         current_function_builder_->Emit(kExprDrop);
    282       }
    283       return;
    284     }
    285     if (expr->IsBinaryOperation()) {
    286       BinaryOperation* binop = expr->AsBinaryOperation();
    287       if (binop->op() == Token::COMMA) {
    288         VisitForEffect(binop->left());
    289         VisitForEffect(binop->right());
    290         return;
    291       }
    292     }
    293     RECURSE(Visit(expr));
    294     if (scope_ == kFuncScope) current_function_builder_->Emit(kExprDrop);
    295   }
    296 
    297   void VisitEmptyStatement(EmptyStatement* stmt) {}
    298 
    299   void VisitEmptyParentheses(EmptyParentheses* paren) { UNREACHABLE(); }
    300 
    301   void VisitGetIterator(GetIterator* expr) { UNREACHABLE(); }
    302 
    303   void VisitIfStatement(IfStatement* stmt) {
    304     DCHECK_EQ(kFuncScope, scope_);
    305     RECURSE(Visit(stmt->condition()));
    306     // Wasm ifs come with implicit blocks for both arms.
    307     BlockVisitor block(this, nullptr, kExprIf);
    308     if (stmt->HasThenStatement()) {
    309       RECURSE(Visit(stmt->then_statement()));
    310     }
    311     if (stmt->HasElseStatement()) {
    312       current_function_builder_->Emit(kExprElse);
    313       RECURSE(Visit(stmt->else_statement()));
    314     }
    315   }
    316 
    317   void DoBreakOrContinue(BreakableStatement* target, TargetType type) {
    318     DCHECK_EQ(kFuncScope, scope_);
    319     for (int i = static_cast<int>(breakable_blocks_.size()) - 1; i >= 0; --i) {
    320       auto elem = breakable_blocks_.at(i);
    321       if (elem.first == target && elem.second == type) {
    322         int block_distance = static_cast<int>(breakable_blocks_.size() - i - 1);
    323         current_function_builder_->EmitWithVarUint(kExprBr, block_distance);
    324         return;
    325       }
    326     }
    327     UNREACHABLE();  // statement not found
    328   }
    329 
    330   void VisitContinueStatement(ContinueStatement* stmt) {
    331     DoBreakOrContinue(stmt->target(), ContinueTarget);
    332   }
    333 
    334   void VisitBreakStatement(BreakStatement* stmt) {
    335     DoBreakOrContinue(stmt->target(), BreakTarget);
    336   }
    337 
    338   void VisitReturnStatement(ReturnStatement* stmt) {
    339     if (scope_ == kModuleScope) {
    340       if (typer_finished_) {
    341         typer_->FailWithMessage("Module has multiple returns.");
    342         typer_failed_ = true;
    343         return;
    344       }
    345       if (!typer_->ValidateAfterFunctionsPhase()) {
    346         typer_failed_ = true;
    347         return;
    348       }
    349       typer_finished_ = true;
    350       scope_ = kExportScope;
    351       RECURSE(Visit(stmt->expression()));
    352       scope_ = kModuleScope;
    353     } else if (scope_ == kFuncScope) {
    354       RECURSE(Visit(stmt->expression()));
    355       current_function_builder_->Emit(kExprReturn);
    356     } else {
    357       UNREACHABLE();
    358     }
    359   }
    360 
    361   void VisitWithStatement(WithStatement* stmt) { UNREACHABLE(); }
    362 
    363   void HandleCase(CaseNode* node,
    364                   ZoneMap<int, unsigned int>& case_to_block,
    365                   VariableProxy* tag, int default_block, int if_depth) {
    366     int prev_if_depth = if_depth;
    367     if (node->left != nullptr) {
    368       VisitVariableProxy(tag);
    369       current_function_builder_->EmitI32Const(node->begin);
    370       current_function_builder_->Emit(kExprI32LtS);
    371       current_function_builder_->EmitWithU8(kExprIf, kLocalVoid);
    372       if_depth++;
    373       breakable_blocks_.emplace_back(nullptr, NoTarget);
    374       HandleCase(node->left, case_to_block, tag, default_block, if_depth);
    375       current_function_builder_->Emit(kExprElse);
    376     }
    377     if (node->right != nullptr) {
    378       VisitVariableProxy(tag);
    379       current_function_builder_->EmitI32Const(node->end);
    380       current_function_builder_->Emit(kExprI32GtS);
    381       current_function_builder_->EmitWithU8(kExprIf, kLocalVoid);
    382       if_depth++;
    383       breakable_blocks_.emplace_back(nullptr, NoTarget);
    384       HandleCase(node->right, case_to_block, tag, default_block, if_depth);
    385       current_function_builder_->Emit(kExprElse);
    386     }
    387     if (node->begin == node->end) {
    388       VisitVariableProxy(tag);
    389       current_function_builder_->EmitI32Const(node->begin);
    390       current_function_builder_->Emit(kExprI32Eq);
    391       current_function_builder_->EmitWithU8(kExprIf, kLocalVoid);
    392       DCHECK(case_to_block.find(node->begin) != case_to_block.end());
    393       current_function_builder_->Emit(kExprBr);
    394       current_function_builder_->EmitVarUint(1 + if_depth +
    395                                              case_to_block[node->begin]);
    396       current_function_builder_->Emit(kExprEnd);
    397     } else {
    398       if (node->begin != 0) {
    399         VisitVariableProxy(tag);
    400         current_function_builder_->EmitI32Const(node->begin);
    401         current_function_builder_->Emit(kExprI32Sub);
    402       } else {
    403         VisitVariableProxy(tag);
    404       }
    405       current_function_builder_->Emit(kExprBrTable);
    406       current_function_builder_->EmitVarUint(node->end - node->begin + 1);
    407       for (int v = node->begin; v <= node->end; ++v) {
    408         if (case_to_block.find(v) != case_to_block.end()) {
    409           uint32_t target = if_depth + case_to_block[v];
    410           current_function_builder_->EmitVarUint(target);
    411         } else {
    412           uint32_t target = if_depth + default_block;
    413           current_function_builder_->EmitVarUint(target);
    414         }
    415         if (v == kMaxInt) {
    416           break;
    417         }
    418       }
    419       uint32_t target = if_depth + default_block;
    420       current_function_builder_->EmitVarUint(target);
    421     }
    422 
    423     while (if_depth-- != prev_if_depth) {
    424       breakable_blocks_.pop_back();
    425       current_function_builder_->Emit(kExprEnd);
    426     }
    427   }
    428 
    429   void VisitSwitchStatement(SwitchStatement* stmt) {
    430     VariableProxy* tag = stmt->tag()->AsVariableProxy();
    431     DCHECK_NOT_NULL(tag);
    432     ZoneList<CaseClause*>* clauses = stmt->cases();
    433     int case_count = clauses->length();
    434     if (case_count == 0) {
    435       return;
    436     }
    437     BlockVisitor visitor(this, stmt->AsBreakableStatement(), kExprBlock,
    438                          BreakTarget);
    439     ZoneVector<BlockVisitor*> blocks(zone_);
    440     ZoneVector<int32_t> cases(zone_);
    441     ZoneMap<int, unsigned int> case_to_block(zone_);
    442     bool has_default = false;
    443     for (int i = case_count - 1; i >= 0; --i) {
    444       CaseClause* clause = clauses->at(i);
    445       blocks.push_back(new BlockVisitor(this, nullptr, kExprBlock));
    446       if (!clause->is_default()) {
    447         Literal* label = clause->label()->AsLiteral();
    448         Handle<Object> value = label->value();
    449         int32_t label_value;
    450         bool label_is_i32 = value->ToInt32(&label_value);
    451         DCHECK(value->IsNumber() && label_is_i32);
    452         (void)label_is_i32;
    453         case_to_block[label_value] = i;
    454         cases.push_back(label_value);
    455       } else {
    456         DCHECK_EQ(i, case_count - 1);
    457         has_default = true;
    458       }
    459     }
    460     if (!has_default || case_count > 1) {
    461       int default_block = has_default ? case_count - 1 : case_count;
    462       BlockVisitor switch_logic_block(this, nullptr, kExprBlock);
    463       CaseNode* root = OrderCases(&cases, zone_);
    464       HandleCase(root, case_to_block, tag, default_block, 0);
    465       if (root->left != nullptr || root->right != nullptr ||
    466           root->begin == root->end) {
    467         current_function_builder_->Emit(kExprBr);
    468         current_function_builder_->EmitVarUint(default_block);
    469       }
    470     }
    471     for (int i = 0; i < case_count; ++i) {
    472       CaseClause* clause = clauses->at(i);
    473       RECURSE(VisitStatements(clause->statements()));
    474       BlockVisitor* v = blocks.at(case_count - i - 1);
    475       blocks.pop_back();
    476       delete v;
    477     }
    478   }
    479 
    480   void VisitCaseClause(CaseClause* clause) { UNREACHABLE(); }
    481 
    482   void VisitDoWhileStatement(DoWhileStatement* stmt) {
    483     DCHECK_EQ(kFuncScope, scope_);
    484     BlockVisitor block(this, stmt->AsBreakableStatement(), kExprBlock,
    485                        BreakTarget);
    486     BlockVisitor loop(this, stmt->AsBreakableStatement(), kExprLoop);
    487     {
    488       BlockVisitor inner_block(this, stmt->AsBreakableStatement(), kExprBlock,
    489                                ContinueTarget);
    490       RECURSE(Visit(stmt->body()));
    491     }
    492     RECURSE(Visit(stmt->cond()));
    493     current_function_builder_->EmitWithU8(kExprBrIf, 0);
    494   }
    495 
    496   void VisitWhileStatement(WhileStatement* stmt) {
    497     DCHECK_EQ(kFuncScope, scope_);
    498     BlockVisitor block(this, stmt->AsBreakableStatement(), kExprBlock,
    499                        BreakTarget);
    500     BlockVisitor loop(this, stmt->AsBreakableStatement(), kExprLoop,
    501                       ContinueTarget);
    502     RECURSE(Visit(stmt->cond()));
    503     BlockVisitor if_block(this, nullptr, kExprIf);
    504     RECURSE(Visit(stmt->body()));
    505     current_function_builder_->EmitWithU8(kExprBr, 1);
    506   }
    507 
    508   void VisitForStatement(ForStatement* stmt) {
    509     DCHECK_EQ(kFuncScope, scope_);
    510     if (stmt->init() != nullptr) {
    511       RECURSE(Visit(stmt->init()));
    512     }
    513     BlockVisitor block(this, stmt->AsBreakableStatement(), kExprBlock,
    514                        BreakTarget);
    515     BlockVisitor loop(this, stmt->AsBreakableStatement(), kExprLoop,
    516                       ContinueTarget);
    517     if (stmt->cond() != nullptr) {
    518       RECURSE(Visit(stmt->cond()));
    519       current_function_builder_->Emit(kExprI32Eqz);
    520       current_function_builder_->EmitWithU8(kExprIf, kLocalVoid);
    521       current_function_builder_->EmitWithU8(kExprBr, 2);
    522       current_function_builder_->Emit(kExprEnd);
    523     }
    524     if (stmt->body() != nullptr) {
    525       RECURSE(Visit(stmt->body()));
    526     }
    527     if (stmt->next() != nullptr) {
    528       RECURSE(Visit(stmt->next()));
    529     }
    530     current_function_builder_->EmitWithU8(kExprBr, 0);
    531   }
    532 
    533   void VisitForInStatement(ForInStatement* stmt) { UNREACHABLE(); }
    534 
    535   void VisitForOfStatement(ForOfStatement* stmt) { UNREACHABLE(); }
    536 
    537   void VisitTryCatchStatement(TryCatchStatement* stmt) { UNREACHABLE(); }
    538 
    539   void VisitTryFinallyStatement(TryFinallyStatement* stmt) { UNREACHABLE(); }
    540 
    541   void VisitDebuggerStatement(DebuggerStatement* stmt) { UNREACHABLE(); }
    542 
    543   void VisitFunctionLiteral(FunctionLiteral* expr) {
    544     DeclarationScope* scope = expr->scope();
    545     if (scope_ == kFuncScope) {
    546       if (auto* func_type = typer_->TypeOf(expr)->AsFunctionType()) {
    547         // Add the parameters for the function.
    548         const auto& arguments = func_type->Arguments();
    549         for (int i = 0; i < expr->parameter_count(); ++i) {
    550           ValueType type = TypeFrom(arguments[i]);
    551           DCHECK_NE(kWasmStmt, type);
    552           InsertParameter(scope->parameter(i), type, i);
    553         }
    554       } else {
    555         UNREACHABLE();
    556       }
    557     }
    558     RECURSE(VisitDeclarations(scope->declarations()));
    559     if (typer_failed_) return;
    560     RECURSE(VisitStatements(expr->body()));
    561     if (scope_ == kFuncScope) {
    562       // Finish the function-body scope block.
    563       current_function_builder_->Emit(kExprEnd);
    564     }
    565   }
    566 
    567   void VisitNativeFunctionLiteral(NativeFunctionLiteral* expr) {
    568     UNREACHABLE();
    569   }
    570 
    571   void VisitConditional(Conditional* expr) {
    572     DCHECK_EQ(kFuncScope, scope_);
    573     RECURSE(Visit(expr->condition()));
    574     // Wasm ifs come with implicit blocks for both arms.
    575     breakable_blocks_.emplace_back(nullptr, NoTarget);
    576     ValueTypeCode type;
    577     switch (TypeOf(expr)) {
    578       case kWasmI32:
    579         type = kLocalI32;
    580         break;
    581       case kWasmI64:
    582         type = kLocalI64;
    583         break;
    584       case kWasmF32:
    585         type = kLocalF32;
    586         break;
    587       case kWasmF64:
    588         type = kLocalF64;
    589         break;
    590       default:
    591         UNREACHABLE();
    592     }
    593     current_function_builder_->EmitWithU8(kExprIf, type);
    594     RECURSE(Visit(expr->then_expression()));
    595     current_function_builder_->Emit(kExprElse);
    596     RECURSE(Visit(expr->else_expression()));
    597     current_function_builder_->Emit(kExprEnd);
    598     breakable_blocks_.pop_back();
    599   }
    600 
    601   bool VisitStdlibConstant(Variable* var) {
    602     AsmTyper::StandardMember standard_object =
    603         typer_->VariableAsStandardMember(var);
    604     double value;
    605     switch (standard_object) {
    606       case AsmTyper::kInfinity: {
    607         value = std::numeric_limits<double>::infinity();
    608         break;
    609       }
    610       case AsmTyper::kNaN: {
    611         value = std::numeric_limits<double>::quiet_NaN();
    612         break;
    613       }
    614       case AsmTyper::kMathE: {
    615         value = M_E;
    616         break;
    617       }
    618       case AsmTyper::kMathLN10: {
    619         value = M_LN10;
    620         break;
    621       }
    622       case AsmTyper::kMathLN2: {
    623         value = M_LN2;
    624         break;
    625       }
    626       case AsmTyper::kMathLOG10E: {
    627         value = M_LOG10E;
    628         break;
    629       }
    630       case AsmTyper::kMathLOG2E: {
    631         value = M_LOG2E;
    632         break;
    633       }
    634       case AsmTyper::kMathPI: {
    635         value = M_PI;
    636         break;
    637       }
    638       case AsmTyper::kMathSQRT1_2: {
    639         value = M_SQRT1_2;
    640         break;
    641       }
    642       case AsmTyper::kMathSQRT2: {
    643         value = M_SQRT2;
    644         break;
    645       }
    646       default: { return false; }
    647     }
    648     byte code[] = {WASM_F64(value)};
    649     current_function_builder_->EmitCode(code, sizeof(code));
    650     return true;
    651   }
    652 
    653   void VisitVariableProxy(VariableProxy* expr) {
    654     if (scope_ == kFuncScope || scope_ == kInitScope) {
    655       Variable* var = expr->var();
    656       if (VisitStdlibConstant(var)) {
    657         return;
    658       }
    659       ValueType var_type = TypeOf(expr);
    660       DCHECK_NE(kWasmStmt, var_type);
    661       if (var->IsContextSlot()) {
    662         current_function_builder_->EmitWithVarUint(
    663             kExprGetGlobal, LookupOrInsertGlobal(var, var_type));
    664       } else {
    665         current_function_builder_->EmitGetLocal(
    666             LookupOrInsertLocal(var, var_type));
    667       }
    668     } else if (scope_ == kExportScope) {
    669       Variable* var = expr->var();
    670       DCHECK(var->is_function());
    671       WasmFunctionBuilder* function = LookupOrInsertFunction(var);
    672       function->ExportAs(CStrVector(AsmWasmBuilder::single_function_name));
    673     }
    674   }
    675 
    676   void VisitLiteral(Literal* expr) {
    677     Handle<Object> value = expr->value();
    678     if (!(value->IsNumber() || expr->raw_value()->IsTrue() ||
    679           expr->raw_value()->IsFalse()) ||
    680         (scope_ != kFuncScope && scope_ != kInitScope)) {
    681       return;
    682     }
    683     AsmType* type = typer_->TypeOf(expr);
    684     DCHECK_NE(type, AsmType::None());
    685 
    686     if (type->IsA(AsmType::Signed())) {
    687       int32_t i = 0;
    688       CHECK(value->ToInt32(&i));
    689       current_function_builder_->EmitI32Const(i);
    690     } else if (type->IsA(AsmType::Unsigned()) || type->IsA(AsmType::FixNum())) {
    691       uint32_t u = 0;
    692       CHECK(value->ToUint32(&u));
    693       current_function_builder_->EmitI32Const(bit_cast<int32_t>(u));
    694     } else if (type->IsA(AsmType::Int())) {
    695       // The parser can collapse !0, !1 etc to true / false.
    696       // Allow these as int literals.
    697       if (expr->raw_value()->IsTrue()) {
    698         byte code[] = {WASM_ONE};
    699         current_function_builder_->EmitCode(code, sizeof(code));
    700       } else if (expr->raw_value()->IsFalse()) {
    701         byte code[] = {WASM_ZERO};
    702         current_function_builder_->EmitCode(code, sizeof(code));
    703       } else if (expr->raw_value()->IsNumber()) {
    704         // This can happen when -x becomes x * -1 (due to the parser).
    705         int32_t i = 0;
    706         CHECK(value->ToInt32(&i) && i == -1);
    707         byte code[] = {WASM_I32V_1(-1)};
    708         current_function_builder_->EmitCode(code, sizeof(code));
    709       } else {
    710         UNREACHABLE();
    711       }
    712     } else if (type->IsA(AsmType::Double())) {
    713       // TODO(bradnelson): Pattern match the case where negation occurs and
    714       // emit f64.neg instead.
    715       double val = expr->raw_value()->AsNumber();
    716       byte code[] = {WASM_F64(val)};
    717       current_function_builder_->EmitCode(code, sizeof(code));
    718     } else if (type->IsA(AsmType::Float())) {
    719       // This can happen when -fround(x) becomes fround(x) * 1.0[float]
    720       // (due to the parser).
    721       // TODO(bradnelson): Pattern match this and emit f32.neg instead.
    722       double val = expr->raw_value()->AsNumber();
    723       DCHECK_EQ(-1.0, val);
    724       byte code[] = {WASM_F32(val)};
    725       current_function_builder_->EmitCode(code, sizeof(code));
    726     } else {
    727       UNREACHABLE();
    728     }
    729   }
    730 
    731   void VisitRegExpLiteral(RegExpLiteral* expr) { UNREACHABLE(); }
    732 
    733   void VisitObjectLiteral(ObjectLiteral* expr) {
    734     ZoneList<ObjectLiteralProperty*>* props = expr->properties();
    735     for (int i = 0; i < props->length(); ++i) {
    736       ObjectLiteralProperty* prop = props->at(i);
    737       DCHECK_EQ(kExportScope, scope_);
    738       VariableProxy* expr = prop->value()->AsVariableProxy();
    739       DCHECK_NOT_NULL(expr);
    740       Variable* var = expr->var();
    741       Literal* name = prop->key()->AsLiteral();
    742       DCHECK_NOT_NULL(name);
    743       DCHECK(name->IsPropertyName());
    744       Handle<String> function_name = name->AsPropertyName();
    745       int length;
    746       std::unique_ptr<char[]> utf8 = function_name->ToCString(
    747           DISALLOW_NULLS, FAST_STRING_TRAVERSAL, &length);
    748       if (var->is_function()) {
    749         WasmFunctionBuilder* function = LookupOrInsertFunction(var);
    750         function->ExportAs({utf8.get(), length});
    751       }
    752     }
    753   }
    754 
    755   void VisitArrayLiteral(ArrayLiteral* expr) { UNREACHABLE(); }
    756 
    757   void LoadInitFunction() {
    758     current_function_builder_ = init_function_;
    759     scope_ = kInitScope;
    760   }
    761 
    762   void UnLoadInitFunction() {
    763     scope_ = kModuleScope;
    764     current_function_builder_ = nullptr;
    765   }
    766 
    767   struct FunctionTableIndices : public ZoneObject {
    768     uint32_t start_index;
    769     uint32_t signature_index;
    770   };
    771 
    772   FunctionTableIndices* LookupOrAddFunctionTable(VariableProxy* table,
    773                                                  Property* p) {
    774     FunctionTableIndices* indices = LookupFunctionTable(table->var());
    775     if (indices != nullptr) {
    776       // Already setup.
    777       return indices;
    778     }
    779     indices = new (zone()) FunctionTableIndices();
    780     auto* func_type = typer_->TypeOf(p)->AsFunctionType();
    781     auto* func_table_type = typer_->TypeOf(p->obj()->AsVariableProxy()->var())
    782                                 ->AsFunctionTableType();
    783     const auto& arguments = func_type->Arguments();
    784     ValueType return_type = TypeFrom(func_type->ReturnType());
    785     FunctionSig::Builder sig(zone(), return_type == kWasmStmt ? 0 : 1,
    786                              arguments.size());
    787     if (return_type != kWasmStmt) {
    788       sig.AddReturn(return_type);
    789     }
    790     for (auto* arg : arguments) {
    791       sig.AddParam(TypeFrom(arg));
    792     }
    793     uint32_t signature_index = builder_->AddSignature(sig.Build());
    794     indices->start_index = builder_->AllocateIndirectFunctions(
    795         static_cast<uint32_t>(func_table_type->length()));
    796     indices->signature_index = signature_index;
    797     ZoneHashMap::Entry* entry = function_tables_.LookupOrInsert(
    798         table->var(), ComputePointerHash(table->var()),
    799         ZoneAllocationPolicy(zone()));
    800     entry->value = indices;
    801     return indices;
    802   }
    803 
    804   FunctionTableIndices* LookupFunctionTable(Variable* v) {
    805     ZoneHashMap::Entry* entry =
    806         function_tables_.Lookup(v, ComputePointerHash(v));
    807     if (entry == nullptr) {
    808       return nullptr;
    809     }
    810     return reinterpret_cast<FunctionTableIndices*>(entry->value);
    811   }
    812 
    813   void PopulateFunctionTable(VariableProxy* table, ArrayLiteral* funcs) {
    814     FunctionTableIndices* indices = LookupFunctionTable(table->var());
    815     // Ignore unused function tables.
    816     if (indices == nullptr) {
    817       return;
    818     }
    819     for (int i = 0; i < funcs->values()->length(); ++i) {
    820       VariableProxy* func = funcs->values()->at(i)->AsVariableProxy();
    821       DCHECK_NOT_NULL(func);
    822       builder_->SetIndirectFunction(
    823           indices->start_index + i,
    824           LookupOrInsertFunction(func->var())->func_index());
    825     }
    826   }
    827 
    828   class ImportedFunctionTable {
    829    private:
    830     class ImportedFunctionIndices : public ZoneObject {
    831      public:
    832       const char* name_;
    833       int name_length_;
    834       WasmModuleBuilder::SignatureMap signature_to_index_;
    835 
    836       ImportedFunctionIndices(const char* name, int name_length, Zone* zone)
    837           : name_(name), name_length_(name_length), signature_to_index_(zone) {}
    838     };
    839     ZoneHashMap table_;
    840     AsmWasmBuilderImpl* builder_;
    841 
    842    public:
    843     explicit ImportedFunctionTable(AsmWasmBuilderImpl* builder)
    844         : table_(ZoneHashMap::kDefaultHashMapCapacity,
    845                  ZoneAllocationPolicy(builder->zone())),
    846           builder_(builder) {}
    847 
    848     ImportedFunctionIndices* LookupOrInsertImport(Variable* v) {
    849       auto* entry = table_.LookupOrInsert(
    850           v, ComputePointerHash(v), ZoneAllocationPolicy(builder_->zone()));
    851       ImportedFunctionIndices* indices;
    852       if (entry->value == nullptr) {
    853         indices = new (builder_->zone())
    854             ImportedFunctionIndices(nullptr, 0, builder_->zone());
    855         entry->value = indices;
    856       } else {
    857         indices = reinterpret_cast<ImportedFunctionIndices*>(entry->value);
    858       }
    859       return indices;
    860     }
    861 
    862     void SetImportName(Variable* v, const char* name, int name_length) {
    863       auto* indices = LookupOrInsertImport(v);
    864       indices->name_ = name;
    865       indices->name_length_ = name_length;
    866       for (auto i : indices->signature_to_index_) {
    867         builder_->builder_->SetImportName(i.second, indices->name_,
    868                                           indices->name_length_);
    869       }
    870     }
    871 
    872     // Get a function's index (or allocate if new).
    873     uint32_t LookupOrInsertImportUse(Variable* v, FunctionSig* sig) {
    874       auto* indices = LookupOrInsertImport(v);
    875       WasmModuleBuilder::SignatureMap::iterator pos =
    876           indices->signature_to_index_.find(sig);
    877       if (pos != indices->signature_to_index_.end()) {
    878         return pos->second;
    879       } else {
    880         uint32_t index = builder_->builder_->AddImport(
    881             indices->name_, indices->name_length_, sig);
    882         indices->signature_to_index_[sig] = index;
    883         return index;
    884       }
    885     }
    886   };
    887 
    888   void EmitAssignmentLhs(Expression* target, AsmType** atype) {
    889     // Match the left hand side of the assignment.
    890     VariableProxy* target_var = target->AsVariableProxy();
    891     if (target_var != nullptr) {
    892       // Left hand side is a local or a global variable, no code on LHS.
    893       return;
    894     }
    895 
    896     Property* target_prop = target->AsProperty();
    897     if (target_prop != nullptr) {
    898       // Left hand side is a property access, i.e. the asm.js heap.
    899       VisitPropertyAndEmitIndex(target_prop, atype);
    900       return;
    901     }
    902 
    903     if (target_var == nullptr && target_prop == nullptr) {
    904       UNREACHABLE();  // invalid assignment.
    905     }
    906   }
    907 
    908   void EmitAssignmentRhs(Expression* target, Expression* value, bool* is_nop) {
    909     BinaryOperation* binop = value->AsBinaryOperation();
    910     if (binop != nullptr) {
    911       if (scope_ == kInitScope) {
    912         // Handle foreign variables in the initialization scope.
    913         Property* prop = binop->left()->AsProperty();
    914         if (binop->op() == Token::MUL) {
    915           DCHECK(binop->right()->IsLiteral());
    916           DCHECK_EQ(1.0, binop->right()->AsLiteral()->raw_value()->AsNumber());
    917           DCHECK(binop->right()->AsLiteral()->raw_value()->ContainsDot());
    918           DCHECK(target->IsVariableProxy());
    919           VisitForeignVariable(true, target->AsVariableProxy()->var(), prop);
    920           *is_nop = true;
    921           return;
    922         } else if (binop->op() == Token::BIT_OR) {
    923           DCHECK(binop->right()->IsLiteral());
    924           DCHECK_EQ(0.0, binop->right()->AsLiteral()->raw_value()->AsNumber());
    925           DCHECK(!binop->right()->AsLiteral()->raw_value()->ContainsDot());
    926           DCHECK(target->IsVariableProxy());
    927           VisitForeignVariable(false, target->AsVariableProxy()->var(), prop);
    928           *is_nop = true;
    929           return;
    930         } else {
    931           UNREACHABLE();
    932         }
    933       }
    934       if (MatchBinaryOperation(binop) == kAsIs) {
    935         VariableProxy* target_var = target->AsVariableProxy();
    936         VariableProxy* effective_value_var = GetLeft(binop)->AsVariableProxy();
    937         if (target_var != nullptr && effective_value_var != nullptr &&
    938             target_var->var() == effective_value_var->var()) {
    939           *is_nop = true;
    940           return;
    941         }
    942       }
    943     }
    944     RECURSE(Visit(value));
    945   }
    946 
    947   void EmitAssignment(Assignment* expr, AsmType* type, ValueFate fate) {
    948     // Match the left hand side of the assignment.
    949     VariableProxy* target_var = expr->target()->AsVariableProxy();
    950     if (target_var != nullptr) {
    951       // Left hand side is a local or a global variable.
    952       Variable* var = target_var->var();
    953       ValueType var_type = TypeOf(expr);
    954       DCHECK_NE(kWasmStmt, var_type);
    955       if (var->IsContextSlot()) {
    956         uint32_t index = LookupOrInsertGlobal(var, var_type);
    957         current_function_builder_->EmitWithVarUint(kExprSetGlobal, index);
    958         if (fate == kLeaveOnStack) {
    959           current_function_builder_->EmitWithVarUint(kExprGetGlobal, index);
    960         }
    961       } else {
    962         if (fate == kDrop) {
    963           current_function_builder_->EmitSetLocal(
    964               LookupOrInsertLocal(var, var_type));
    965         } else {
    966           current_function_builder_->EmitTeeLocal(
    967               LookupOrInsertLocal(var, var_type));
    968         }
    969       }
    970     }
    971 
    972     Property* target_prop = expr->target()->AsProperty();
    973     if (target_prop != nullptr) {
    974       // Left hand side is a property access, i.e. the asm.js heap.
    975       if (TypeOf(expr->value()) == kWasmF64 && expr->target()->IsProperty() &&
    976           typer_->TypeOf(expr->target()->AsProperty()->obj())
    977               ->IsA(AsmType::Float32Array())) {
    978         current_function_builder_->Emit(kExprF32ConvertF64);
    979       }
    980       // Note that unlike StoreMem, AsmjsStoreMem ignores out-of-bounds writes.
    981       WasmOpcode opcode;
    982       if (type == AsmType::Int8Array()) {
    983         opcode = kExprI32AsmjsStoreMem8;
    984       } else if (type == AsmType::Uint8Array()) {
    985         opcode = kExprI32AsmjsStoreMem8;
    986       } else if (type == AsmType::Int16Array()) {
    987         opcode = kExprI32AsmjsStoreMem16;
    988       } else if (type == AsmType::Uint16Array()) {
    989         opcode = kExprI32AsmjsStoreMem16;
    990       } else if (type == AsmType::Int32Array()) {
    991         opcode = kExprI32AsmjsStoreMem;
    992       } else if (type == AsmType::Uint32Array()) {
    993         opcode = kExprI32AsmjsStoreMem;
    994       } else if (type == AsmType::Float32Array()) {
    995         opcode = kExprF32AsmjsStoreMem;
    996       } else if (type == AsmType::Float64Array()) {
    997         opcode = kExprF64AsmjsStoreMem;
    998       } else {
    999         UNREACHABLE();
   1000       }
   1001       current_function_builder_->Emit(opcode);
   1002       if (fate == kDrop) {
   1003         // Asm.js stores to memory leave their result on the stack.
   1004         current_function_builder_->Emit(kExprDrop);
   1005       }
   1006     }
   1007 
   1008     if (target_var == nullptr && target_prop == nullptr) {
   1009       UNREACHABLE();  // invalid assignment.
   1010     }
   1011   }
   1012 
   1013   void VisitAssignment(Assignment* expr) {
   1014     VisitAssignment(expr, kLeaveOnStack);
   1015   }
   1016 
   1017   void VisitAssignment(Assignment* expr, ValueFate fate) {
   1018     bool as_init = false;
   1019     if (scope_ == kModuleScope) {
   1020       // Skip extra assignment inserted by the parser when in this form:
   1021       // (function Module(a, b, c) {... })
   1022       if (expr->target()->IsVariableProxy() &&
   1023           expr->target()->AsVariableProxy()->var()->is_sloppy_function_name()) {
   1024         return;
   1025       }
   1026       Property* prop = expr->value()->AsProperty();
   1027       if (prop != nullptr) {
   1028         VariableProxy* vp = prop->obj()->AsVariableProxy();
   1029         if (vp != nullptr && vp->var()->IsParameter() &&
   1030             vp->var()->index() == 1) {
   1031           VariableProxy* target = expr->target()->AsVariableProxy();
   1032           if (typer_->TypeOf(target)->AsFFIType() != nullptr) {
   1033             const AstRawString* name =
   1034                 prop->key()->AsLiteral()->AsRawPropertyName();
   1035             imported_function_table_.SetImportName(
   1036                 target->var(), reinterpret_cast<const char*>(name->raw_data()),
   1037                 name->length());
   1038           }
   1039         }
   1040         // Property values in module scope don't emit code, so return.
   1041         return;
   1042       }
   1043       ArrayLiteral* funcs = expr->value()->AsArrayLiteral();
   1044       if (funcs != nullptr) {
   1045         VariableProxy* target = expr->target()->AsVariableProxy();
   1046         DCHECK_NOT_NULL(target);
   1047         PopulateFunctionTable(target, funcs);
   1048         // Only add to the function table. No init needed.
   1049         return;
   1050       }
   1051       if (expr->value()->IsCallNew()) {
   1052         // No init code to emit for CallNew nodes.
   1053         return;
   1054       }
   1055       as_init = true;
   1056     }
   1057 
   1058     if (as_init) LoadInitFunction();
   1059     AsmType* atype = AsmType::None();
   1060     bool is_nop = false;
   1061     EmitAssignmentLhs(expr->target(), &atype);
   1062     EmitAssignmentRhs(expr->target(), expr->value(), &is_nop);
   1063     if (!is_nop) {
   1064       EmitAssignment(expr, atype, fate);
   1065     }
   1066     if (as_init) UnLoadInitFunction();
   1067   }
   1068 
   1069   void VisitYield(Yield* expr) { UNREACHABLE(); }
   1070 
   1071   void VisitThrow(Throw* expr) { UNREACHABLE(); }
   1072 
   1073   void VisitForeignVariable(bool is_float, Variable* var, Property* expr) {
   1074     DCHECK(expr->obj()->AsVariableProxy());
   1075     DCHECK(VariableLocation::PARAMETER ==
   1076            expr->obj()->AsVariableProxy()->var()->location());
   1077     DCHECK_EQ(1, expr->obj()->AsVariableProxy()->var()->index());
   1078     Literal* key_literal = expr->key()->AsLiteral();
   1079     DCHECK_NOT_NULL(key_literal);
   1080     if (!key_literal->value().is_null()) {
   1081       Handle<Name> name =
   1082           Object::ToName(isolate_, key_literal->value()).ToHandleChecked();
   1083       ValueType type = is_float ? kWasmF64 : kWasmI32;
   1084       foreign_variables_.push_back({name, var, type});
   1085     }
   1086   }
   1087 
   1088   void VisitPropertyAndEmitIndex(Property* expr, AsmType** atype) {
   1089     Expression* obj = expr->obj();
   1090     *atype = typer_->TypeOf(obj);
   1091     int32_t size = (*atype)->ElementSizeInBytes();
   1092     if (size == 1) {
   1093       // Allow more general expression in byte arrays than the spec
   1094       // strictly permits.
   1095       // Early versions of Emscripten emit HEAP8[HEAP32[..]|0] in
   1096       // places that strictly should be HEAP8[HEAP32[..]>>0].
   1097       RECURSE(Visit(expr->key()));
   1098       return;
   1099     }
   1100 
   1101     Literal* value = expr->key()->AsLiteral();
   1102     if (value) {
   1103       DCHECK(value->raw_value()->IsNumber());
   1104       DCHECK_EQ(kWasmI32, TypeOf(value));
   1105       int32_t val = static_cast<int32_t>(value->raw_value()->AsNumber());
   1106       // TODO(titzer): handle overflow here.
   1107       current_function_builder_->EmitI32Const(val * size);
   1108       return;
   1109     }
   1110     BinaryOperation* binop = expr->key()->AsBinaryOperation();
   1111     if (binop) {
   1112       DCHECK_EQ(Token::SAR, binop->op());
   1113       DCHECK(binop->right()->AsLiteral()->raw_value()->IsNumber());
   1114       DCHECK(kWasmI32 == TypeOf(binop->right()->AsLiteral()));
   1115       DCHECK_EQ(size,
   1116                 1 << static_cast<int>(
   1117                     binop->right()->AsLiteral()->raw_value()->AsNumber()));
   1118       // Mask bottom bits to match asm.js behavior.
   1119       RECURSE(Visit(binop->left()));
   1120       current_function_builder_->EmitI32Const(~(size - 1));
   1121       current_function_builder_->Emit(kExprI32And);
   1122       return;
   1123     }
   1124     UNREACHABLE();
   1125   }
   1126 
   1127   void VisitProperty(Property* expr) {
   1128     AsmType* type = AsmType::None();
   1129     VisitPropertyAndEmitIndex(expr, &type);
   1130     WasmOpcode opcode;
   1131     if (type == AsmType::Int8Array()) {
   1132       opcode = kExprI32AsmjsLoadMem8S;
   1133     } else if (type == AsmType::Uint8Array()) {
   1134       opcode = kExprI32AsmjsLoadMem8U;
   1135     } else if (type == AsmType::Int16Array()) {
   1136       opcode = kExprI32AsmjsLoadMem16S;
   1137     } else if (type == AsmType::Uint16Array()) {
   1138       opcode = kExprI32AsmjsLoadMem16U;
   1139     } else if (type == AsmType::Int32Array()) {
   1140       opcode = kExprI32AsmjsLoadMem;
   1141     } else if (type == AsmType::Uint32Array()) {
   1142       opcode = kExprI32AsmjsLoadMem;
   1143     } else if (type == AsmType::Float32Array()) {
   1144       opcode = kExprF32AsmjsLoadMem;
   1145     } else if (type == AsmType::Float64Array()) {
   1146       opcode = kExprF64AsmjsLoadMem;
   1147     } else {
   1148       UNREACHABLE();
   1149     }
   1150 
   1151     current_function_builder_->Emit(opcode);
   1152   }
   1153 
   1154   bool VisitStdlibFunction(Call* call, VariableProxy* expr) {
   1155     Variable* var = expr->var();
   1156     AsmTyper::StandardMember standard_object =
   1157         typer_->VariableAsStandardMember(var);
   1158     ZoneList<Expression*>* args = call->arguments();
   1159     ValueType call_type = TypeOf(call);
   1160 
   1161     switch (standard_object) {
   1162       case AsmTyper::kNone: {
   1163         return false;
   1164       }
   1165       case AsmTyper::kMathAcos: {
   1166         VisitCallArgs(call);
   1167         DCHECK_EQ(kWasmF64, call_type);
   1168         current_function_builder_->Emit(kExprF64Acos);
   1169         break;
   1170       }
   1171       case AsmTyper::kMathAsin: {
   1172         VisitCallArgs(call);
   1173         DCHECK_EQ(kWasmF64, call_type);
   1174         current_function_builder_->Emit(kExprF64Asin);
   1175         break;
   1176       }
   1177       case AsmTyper::kMathAtan: {
   1178         VisitCallArgs(call);
   1179         DCHECK_EQ(kWasmF64, call_type);
   1180         current_function_builder_->Emit(kExprF64Atan);
   1181         break;
   1182       }
   1183       case AsmTyper::kMathCos: {
   1184         VisitCallArgs(call);
   1185         DCHECK_EQ(kWasmF64, call_type);
   1186         current_function_builder_->Emit(kExprF64Cos);
   1187         break;
   1188       }
   1189       case AsmTyper::kMathSin: {
   1190         VisitCallArgs(call);
   1191         DCHECK_EQ(kWasmF64, call_type);
   1192         current_function_builder_->Emit(kExprF64Sin);
   1193         break;
   1194       }
   1195       case AsmTyper::kMathTan: {
   1196         VisitCallArgs(call);
   1197         DCHECK_EQ(kWasmF64, call_type);
   1198         current_function_builder_->Emit(kExprF64Tan);
   1199         break;
   1200       }
   1201       case AsmTyper::kMathExp: {
   1202         VisitCallArgs(call);
   1203         DCHECK_EQ(kWasmF64, call_type);
   1204         current_function_builder_->Emit(kExprF64Exp);
   1205         break;
   1206       }
   1207       case AsmTyper::kMathLog: {
   1208         VisitCallArgs(call);
   1209         DCHECK_EQ(kWasmF64, call_type);
   1210         current_function_builder_->Emit(kExprF64Log);
   1211         break;
   1212       }
   1213       case AsmTyper::kMathCeil: {
   1214         VisitCallArgs(call);
   1215         if (call_type == kWasmF32) {
   1216           current_function_builder_->Emit(kExprF32Ceil);
   1217         } else if (call_type == kWasmF64) {
   1218           current_function_builder_->Emit(kExprF64Ceil);
   1219         } else {
   1220           UNREACHABLE();
   1221         }
   1222         break;
   1223       }
   1224       case AsmTyper::kMathFloor: {
   1225         VisitCallArgs(call);
   1226         if (call_type == kWasmF32) {
   1227           current_function_builder_->Emit(kExprF32Floor);
   1228         } else if (call_type == kWasmF64) {
   1229           current_function_builder_->Emit(kExprF64Floor);
   1230         } else {
   1231           UNREACHABLE();
   1232         }
   1233         break;
   1234       }
   1235       case AsmTyper::kMathSqrt: {
   1236         VisitCallArgs(call);
   1237         if (call_type == kWasmF32) {
   1238           current_function_builder_->Emit(kExprF32Sqrt);
   1239         } else if (call_type == kWasmF64) {
   1240           current_function_builder_->Emit(kExprF64Sqrt);
   1241         } else {
   1242           UNREACHABLE();
   1243         }
   1244         break;
   1245       }
   1246       case AsmTyper::kMathClz32: {
   1247         VisitCallArgs(call);
   1248         DCHECK(call_type == kWasmI32);
   1249         current_function_builder_->Emit(kExprI32Clz);
   1250         break;
   1251       }
   1252       case AsmTyper::kMathAbs: {
   1253         if (call_type == kWasmI32) {
   1254           WasmTemporary tmp(current_function_builder_, kWasmI32);
   1255 
   1256           // if set_local(tmp, x) < 0
   1257           Visit(call->arguments()->at(0));
   1258           current_function_builder_->EmitTeeLocal(tmp.index());
   1259           byte code[] = {WASM_ZERO};
   1260           current_function_builder_->EmitCode(code, sizeof(code));
   1261           current_function_builder_->Emit(kExprI32LtS);
   1262           current_function_builder_->EmitWithU8(kExprIf, kLocalI32);
   1263 
   1264           // then (0 - tmp)
   1265           current_function_builder_->EmitCode(code, sizeof(code));
   1266           current_function_builder_->EmitGetLocal(tmp.index());
   1267           current_function_builder_->Emit(kExprI32Sub);
   1268 
   1269           // else tmp
   1270           current_function_builder_->Emit(kExprElse);
   1271           current_function_builder_->EmitGetLocal(tmp.index());
   1272           // end
   1273           current_function_builder_->Emit(kExprEnd);
   1274 
   1275         } else if (call_type == kWasmF32) {
   1276           VisitCallArgs(call);
   1277           current_function_builder_->Emit(kExprF32Abs);
   1278         } else if (call_type == kWasmF64) {
   1279           VisitCallArgs(call);
   1280           current_function_builder_->Emit(kExprF64Abs);
   1281         } else {
   1282           UNREACHABLE();
   1283         }
   1284         break;
   1285       }
   1286       case AsmTyper::kMathMin: {
   1287         // TODO(bradnelson): Change wasm to match Math.min in asm.js mode.
   1288         if (call_type == kWasmI32) {
   1289           WasmTemporary tmp_x(current_function_builder_, kWasmI32);
   1290           WasmTemporary tmp_y(current_function_builder_, kWasmI32);
   1291 
   1292           // if set_local(tmp_x, x) < set_local(tmp_y, y)
   1293           Visit(call->arguments()->at(0));
   1294           current_function_builder_->EmitTeeLocal(tmp_x.index());
   1295 
   1296           Visit(call->arguments()->at(1));
   1297           current_function_builder_->EmitTeeLocal(tmp_y.index());
   1298 
   1299           current_function_builder_->Emit(kExprI32LeS);
   1300           current_function_builder_->EmitWithU8(kExprIf, kLocalI32);
   1301 
   1302           // then tmp_x
   1303           current_function_builder_->EmitGetLocal(tmp_x.index());
   1304 
   1305           // else tmp_y
   1306           current_function_builder_->Emit(kExprElse);
   1307           current_function_builder_->EmitGetLocal(tmp_y.index());
   1308           current_function_builder_->Emit(kExprEnd);
   1309 
   1310         } else if (call_type == kWasmF32) {
   1311           VisitCallArgs(call);
   1312           current_function_builder_->Emit(kExprF32Min);
   1313         } else if (call_type == kWasmF64) {
   1314           VisitCallArgs(call);
   1315           current_function_builder_->Emit(kExprF64Min);
   1316         } else {
   1317           UNREACHABLE();
   1318         }
   1319         break;
   1320       }
   1321       case AsmTyper::kMathMax: {
   1322         // TODO(bradnelson): Change wasm to match Math.max in asm.js mode.
   1323         if (call_type == kWasmI32) {
   1324           WasmTemporary tmp_x(current_function_builder_, kWasmI32);
   1325           WasmTemporary tmp_y(current_function_builder_, kWasmI32);
   1326 
   1327           // if set_local(tmp_x, x) < set_local(tmp_y, y)
   1328           Visit(call->arguments()->at(0));
   1329 
   1330           current_function_builder_->EmitTeeLocal(tmp_x.index());
   1331 
   1332           Visit(call->arguments()->at(1));
   1333           current_function_builder_->EmitTeeLocal(tmp_y.index());
   1334 
   1335           current_function_builder_->Emit(kExprI32LeS);
   1336           current_function_builder_->EmitWithU8(kExprIf, kLocalI32);
   1337 
   1338           // then tmp_y
   1339           current_function_builder_->EmitGetLocal(tmp_y.index());
   1340 
   1341           // else tmp_x
   1342           current_function_builder_->Emit(kExprElse);
   1343           current_function_builder_->EmitGetLocal(tmp_x.index());
   1344           current_function_builder_->Emit(kExprEnd);
   1345 
   1346         } else if (call_type == kWasmF32) {
   1347           VisitCallArgs(call);
   1348           current_function_builder_->Emit(kExprF32Max);
   1349         } else if (call_type == kWasmF64) {
   1350           VisitCallArgs(call);
   1351           current_function_builder_->Emit(kExprF64Max);
   1352         } else {
   1353           UNREACHABLE();
   1354         }
   1355         break;
   1356       }
   1357       case AsmTyper::kMathAtan2: {
   1358         VisitCallArgs(call);
   1359         DCHECK_EQ(kWasmF64, call_type);
   1360         current_function_builder_->Emit(kExprF64Atan2);
   1361         break;
   1362       }
   1363       case AsmTyper::kMathPow: {
   1364         VisitCallArgs(call);
   1365         DCHECK_EQ(kWasmF64, call_type);
   1366         current_function_builder_->Emit(kExprF64Pow);
   1367         break;
   1368       }
   1369       case AsmTyper::kMathImul: {
   1370         VisitCallArgs(call);
   1371         current_function_builder_->Emit(kExprI32Mul);
   1372         break;
   1373       }
   1374       case AsmTyper::kMathFround: {
   1375         DCHECK(args->length() == 1);
   1376         Literal* literal = args->at(0)->AsLiteral();
   1377         if (literal != nullptr) {
   1378           // constant fold Math.fround(#const);
   1379           if (literal->raw_value()->IsNumber()) {
   1380             float val = static_cast<float>(literal->raw_value()->AsNumber());
   1381             byte code[] = {WASM_F32(val)};
   1382             current_function_builder_->EmitCode(code, sizeof(code));
   1383             return true;
   1384           }
   1385         }
   1386         VisitCallArgs(call);
   1387         static const bool kDontIgnoreSign = false;
   1388         switch (TypeIndexOf(args->at(0), kDontIgnoreSign)) {
   1389           case kInt32:
   1390           case kFixnum:
   1391             current_function_builder_->Emit(kExprF32SConvertI32);
   1392             break;
   1393           case kUint32:
   1394             current_function_builder_->Emit(kExprF32UConvertI32);
   1395             break;
   1396           case kFloat32:
   1397             break;
   1398           case kFloat64:
   1399             current_function_builder_->Emit(kExprF32ConvertF64);
   1400             break;
   1401           default:
   1402             UNREACHABLE();
   1403         }
   1404         break;
   1405       }
   1406       default: {
   1407         UNREACHABLE();
   1408         break;
   1409       }
   1410     }
   1411     return true;
   1412   }
   1413 
   1414   void VisitCallArgs(Call* expr) {
   1415     ZoneList<Expression*>* args = expr->arguments();
   1416     for (int i = 0; i < args->length(); ++i) {
   1417       Expression* arg = args->at(i);
   1418       RECURSE(Visit(arg));
   1419     }
   1420   }
   1421 
   1422   void VisitCall(Call* expr) { VisitCallExpression(expr); }
   1423 
   1424   bool VisitCallExpression(Call* expr) {
   1425     Call::CallType call_type = expr->GetCallType();
   1426     bool returns_value = true;
   1427 
   1428     // Save the parent now, it might be overwritten in VisitCallArgs.
   1429     BinaryOperation* parent_binop = parent_binop_;
   1430 
   1431     switch (call_type) {
   1432       case Call::OTHER_CALL: {
   1433         VariableProxy* proxy = expr->expression()->AsVariableProxy();
   1434         if (proxy != nullptr) {
   1435           DCHECK(kFuncScope == scope_ ||
   1436                  typer_->VariableAsStandardMember(proxy->var()) ==
   1437                      AsmTyper::kMathFround);
   1438           if (VisitStdlibFunction(expr, proxy)) {
   1439             return true;
   1440           }
   1441         }
   1442         DCHECK(kFuncScope == scope_);
   1443         VariableProxy* vp = expr->expression()->AsVariableProxy();
   1444         DCHECK_NOT_NULL(vp);
   1445         if (typer_->TypeOf(vp)->AsFFIType() != nullptr) {
   1446           ValueType return_type = TypeOf(expr);
   1447           ZoneList<Expression*>* args = expr->arguments();
   1448           FunctionSig::Builder sig(zone(), return_type == kWasmStmt ? 0 : 1,
   1449                                    args->length());
   1450           if (return_type != kWasmStmt) {
   1451             sig.AddReturn(return_type);
   1452           } else {
   1453             returns_value = false;
   1454           }
   1455           for (int i = 0; i < args->length(); ++i) {
   1456             sig.AddParam(TypeOf(args->at(i)));
   1457           }
   1458           uint32_t index = imported_function_table_.LookupOrInsertImportUse(
   1459               vp->var(), sig.Build());
   1460           VisitCallArgs(expr);
   1461           // For non-void functions, we must know the parent node.
   1462           DCHECK_IMPLIES(returns_value, parent_binop != nullptr);
   1463           DCHECK_IMPLIES(returns_value, parent_binop->left() == expr ||
   1464                                             parent_binop->right() == expr);
   1465           int pos = expr->position();
   1466           int parent_pos = returns_value ? parent_binop->position() : pos;
   1467           current_function_builder_->AddAsmWasmOffset(pos, parent_pos);
   1468           current_function_builder_->Emit(kExprCallFunction);
   1469           current_function_builder_->EmitVarUint(index);
   1470         } else {
   1471           WasmFunctionBuilder* function = LookupOrInsertFunction(vp->var());
   1472           VisitCallArgs(expr);
   1473           current_function_builder_->AddAsmWasmOffset(expr->position(),
   1474                                                       expr->position());
   1475           current_function_builder_->Emit(kExprCallFunction);
   1476           current_function_builder_->EmitDirectCallIndex(
   1477               function->func_index());
   1478           returns_value = function->signature()->return_count() > 0;
   1479         }
   1480         break;
   1481       }
   1482       case Call::KEYED_PROPERTY_CALL: {
   1483         DCHECK_EQ(kFuncScope, scope_);
   1484         Property* p = expr->expression()->AsProperty();
   1485         DCHECK_NOT_NULL(p);
   1486         VariableProxy* var = p->obj()->AsVariableProxy();
   1487         DCHECK_NOT_NULL(var);
   1488         FunctionTableIndices* indices = LookupOrAddFunctionTable(var, p);
   1489         Visit(p->key());  // TODO(titzer): should use RECURSE()
   1490 
   1491         // We have to use a temporary for the correct order of evaluation.
   1492         current_function_builder_->EmitI32Const(indices->start_index);
   1493         current_function_builder_->Emit(kExprI32Add);
   1494         WasmTemporary tmp(current_function_builder_, kWasmI32);
   1495         current_function_builder_->EmitSetLocal(tmp.index());
   1496 
   1497         VisitCallArgs(expr);
   1498 
   1499         current_function_builder_->EmitGetLocal(tmp.index());
   1500         current_function_builder_->AddAsmWasmOffset(expr->position(),
   1501                                                     expr->position());
   1502         current_function_builder_->Emit(kExprCallIndirect);
   1503         current_function_builder_->EmitVarUint(indices->signature_index);
   1504         current_function_builder_->EmitVarUint(0);  // table index
   1505         returns_value =
   1506             builder_->GetSignature(indices->signature_index)->return_count() >
   1507             0;
   1508         break;
   1509       }
   1510       default:
   1511         UNREACHABLE();
   1512     }
   1513     return returns_value;
   1514   }
   1515 
   1516   void VisitCallNew(CallNew* expr) { UNREACHABLE(); }
   1517 
   1518   void VisitCallRuntime(CallRuntime* expr) { UNREACHABLE(); }
   1519 
   1520   void VisitUnaryOperation(UnaryOperation* expr) {
   1521     RECURSE(Visit(expr->expression()));
   1522     switch (expr->op()) {
   1523       case Token::NOT: {
   1524         DCHECK_EQ(kWasmI32, TypeOf(expr->expression()));
   1525         current_function_builder_->Emit(kExprI32Eqz);
   1526         break;
   1527       }
   1528       default:
   1529         UNREACHABLE();
   1530     }
   1531   }
   1532 
   1533   void VisitCountOperation(CountOperation* expr) { UNREACHABLE(); }
   1534 
   1535   bool MatchIntBinaryOperation(BinaryOperation* expr, Token::Value op,
   1536                                int32_t val) {
   1537     DCHECK_NOT_NULL(expr->right());
   1538     if (expr->op() == op && expr->right()->IsLiteral() &&
   1539         TypeOf(expr) == kWasmI32) {
   1540       Literal* right = expr->right()->AsLiteral();
   1541       if (right->raw_value()->IsNumber() &&
   1542           static_cast<int32_t>(right->raw_value()->AsNumber()) == val) {
   1543         return true;
   1544       }
   1545     }
   1546     return false;
   1547   }
   1548 
   1549   bool MatchDoubleBinaryOperation(BinaryOperation* expr, Token::Value op,
   1550                                   double val) {
   1551     DCHECK_NOT_NULL(expr->right());
   1552     if (expr->op() == op && expr->right()->IsLiteral() &&
   1553         TypeOf(expr) == kWasmF64) {
   1554       Literal* right = expr->right()->AsLiteral();
   1555       DCHECK(right->raw_value()->IsNumber());
   1556       if (right->raw_value()->AsNumber() == val) {
   1557         return true;
   1558       }
   1559     }
   1560     return false;
   1561   }
   1562 
   1563   enum ConvertOperation { kNone, kAsIs, kToInt, kToDouble };
   1564 
   1565   ConvertOperation MatchOr(BinaryOperation* expr) {
   1566     if (MatchIntBinaryOperation(expr, Token::BIT_OR, 0) &&
   1567         (TypeOf(expr->left()) == kWasmI32)) {
   1568       return kAsIs;
   1569     } else {
   1570       return kNone;
   1571     }
   1572   }
   1573 
   1574   ConvertOperation MatchShr(BinaryOperation* expr) {
   1575     if (MatchIntBinaryOperation(expr, Token::SHR, 0)) {
   1576       // TODO(titzer): this probably needs to be kToUint
   1577       return (TypeOf(expr->left()) == kWasmI32) ? kAsIs : kToInt;
   1578     } else {
   1579       return kNone;
   1580     }
   1581   }
   1582 
   1583   ConvertOperation MatchXor(BinaryOperation* expr) {
   1584     if (MatchIntBinaryOperation(expr, Token::BIT_XOR, 0xffffffff)) {
   1585       DCHECK_EQ(kWasmI32, TypeOf(expr->left()));
   1586       DCHECK_EQ(kWasmI32, TypeOf(expr->right()));
   1587       BinaryOperation* op = expr->left()->AsBinaryOperation();
   1588       if (op != nullptr) {
   1589         if (MatchIntBinaryOperation(op, Token::BIT_XOR, 0xffffffff)) {
   1590           DCHECK_EQ(kWasmI32, TypeOf(op->right()));
   1591           if (TypeOf(op->left()) != kWasmI32) {
   1592             return kToInt;
   1593           } else {
   1594             return kAsIs;
   1595           }
   1596         }
   1597       }
   1598     }
   1599     return kNone;
   1600   }
   1601 
   1602   ConvertOperation MatchMul(BinaryOperation* expr) {
   1603     if (MatchDoubleBinaryOperation(expr, Token::MUL, 1.0)) {
   1604       DCHECK_EQ(kWasmF64, TypeOf(expr->right()));
   1605       if (TypeOf(expr->left()) != kWasmF64) {
   1606         return kToDouble;
   1607       } else {
   1608         return kAsIs;
   1609       }
   1610     } else {
   1611       return kNone;
   1612     }
   1613   }
   1614 
   1615   ConvertOperation MatchBinaryOperation(BinaryOperation* expr) {
   1616     switch (expr->op()) {
   1617       case Token::BIT_OR:
   1618         return MatchOr(expr);
   1619       case Token::SHR:
   1620         return MatchShr(expr);
   1621       case Token::BIT_XOR:
   1622         return MatchXor(expr);
   1623       case Token::MUL:
   1624         return MatchMul(expr);
   1625       default:
   1626         return kNone;
   1627     }
   1628   }
   1629 
   1630 // Work around Mul + Div being defined in PPC assembler.
   1631 #ifdef Mul
   1632 #undef Mul
   1633 #endif
   1634 
   1635 #define NON_SIGNED_BINOP(op)      \
   1636   static WasmOpcode opcodes[] = { \
   1637     kExprI32##op,                 \
   1638     kExprI32##op,                 \
   1639     kExprF32##op,                 \
   1640     kExprF64##op                  \
   1641   }
   1642 
   1643 #define SIGNED_BINOP(op)          \
   1644   static WasmOpcode opcodes[] = { \
   1645     kExprI32##op##S,              \
   1646     kExprI32##op##U,              \
   1647     kExprF32##op,                 \
   1648     kExprF64##op                  \
   1649   }
   1650 
   1651 #define NON_SIGNED_INT_BINOP(op) \
   1652   static WasmOpcode opcodes[] = { kExprI32##op, kExprI32##op }
   1653 
   1654 #define BINOP_CASE(token, op, V, ignore_sign)                         \
   1655   case token: {                                                       \
   1656     V(op);                                                            \
   1657     int type = TypeIndexOf(expr->left(), expr->right(), ignore_sign); \
   1658     current_function_builder_->Emit(opcodes[type]);                   \
   1659     break;                                                            \
   1660   }
   1661 
   1662   Expression* GetLeft(BinaryOperation* expr) {
   1663     if (expr->op() == Token::BIT_XOR) {
   1664       return expr->left()->AsBinaryOperation()->left();
   1665     } else {
   1666       return expr->left();
   1667     }
   1668   }
   1669 
   1670   void VisitBinaryOperation(BinaryOperation* expr) {
   1671     ConvertOperation convertOperation = MatchBinaryOperation(expr);
   1672     static const bool kDontIgnoreSign = false;
   1673     parent_binop_ = expr;
   1674     if (convertOperation == kToDouble) {
   1675       RECURSE(Visit(expr->left()));
   1676       TypeIndex type = TypeIndexOf(expr->left(), kDontIgnoreSign);
   1677       if (type == kInt32 || type == kFixnum) {
   1678         current_function_builder_->Emit(kExprF64SConvertI32);
   1679       } else if (type == kUint32) {
   1680         current_function_builder_->Emit(kExprF64UConvertI32);
   1681       } else if (type == kFloat32) {
   1682         current_function_builder_->Emit(kExprF64ConvertF32);
   1683       } else {
   1684         UNREACHABLE();
   1685       }
   1686     } else if (convertOperation == kToInt) {
   1687       RECURSE(Visit(GetLeft(expr)));
   1688       TypeIndex type = TypeIndexOf(GetLeft(expr), kDontIgnoreSign);
   1689       if (type == kFloat32) {
   1690         current_function_builder_->Emit(kExprI32AsmjsSConvertF32);
   1691       } else if (type == kFloat64) {
   1692         current_function_builder_->Emit(kExprI32AsmjsSConvertF64);
   1693       } else {
   1694         UNREACHABLE();
   1695       }
   1696     } else if (convertOperation == kAsIs) {
   1697       RECURSE(Visit(GetLeft(expr)));
   1698     } else {
   1699       if (expr->op() == Token::COMMA) {
   1700         RECURSE(VisitForEffect(expr->left()));
   1701         RECURSE(Visit(expr->right()));
   1702         return;
   1703       }
   1704       RECURSE(Visit(expr->left()));
   1705       RECURSE(Visit(expr->right()));
   1706 
   1707       switch (expr->op()) {
   1708         BINOP_CASE(Token::ADD, Add, NON_SIGNED_BINOP, true);
   1709         BINOP_CASE(Token::SUB, Sub, NON_SIGNED_BINOP, true);
   1710         BINOP_CASE(Token::MUL, Mul, NON_SIGNED_BINOP, true);
   1711         BINOP_CASE(Token::BIT_OR, Ior, NON_SIGNED_INT_BINOP, true);
   1712         BINOP_CASE(Token::BIT_AND, And, NON_SIGNED_INT_BINOP, true);
   1713         BINOP_CASE(Token::BIT_XOR, Xor, NON_SIGNED_INT_BINOP, true);
   1714         BINOP_CASE(Token::SHL, Shl, NON_SIGNED_INT_BINOP, true);
   1715         BINOP_CASE(Token::SAR, ShrS, NON_SIGNED_INT_BINOP, true);
   1716         BINOP_CASE(Token::SHR, ShrU, NON_SIGNED_INT_BINOP, true);
   1717         case Token::DIV: {
   1718           static WasmOpcode opcodes[] = {kExprI32AsmjsDivS, kExprI32AsmjsDivU,
   1719                                          kExprF32Div, kExprF64Div};
   1720           int type = TypeIndexOf(expr->left(), expr->right(), false);
   1721           current_function_builder_->Emit(opcodes[type]);
   1722           break;
   1723         }
   1724         case Token::MOD: {
   1725           TypeIndex type = TypeIndexOf(expr->left(), expr->right(), false);
   1726           if (type == kInt32) {
   1727             current_function_builder_->Emit(kExprI32AsmjsRemS);
   1728           } else if (type == kUint32) {
   1729             current_function_builder_->Emit(kExprI32AsmjsRemU);
   1730           } else if (type == kFloat64) {
   1731             current_function_builder_->Emit(kExprF64Mod);
   1732             return;
   1733           } else {
   1734             UNREACHABLE();
   1735           }
   1736           break;
   1737         }
   1738         case Token::COMMA: {
   1739           break;
   1740         }
   1741         default:
   1742           UNREACHABLE();
   1743       }
   1744     }
   1745   }
   1746 
   1747   void VisitCompareOperation(CompareOperation* expr) {
   1748     RECURSE(Visit(expr->left()));
   1749     RECURSE(Visit(expr->right()));
   1750     switch (expr->op()) {
   1751       BINOP_CASE(Token::EQ, Eq, NON_SIGNED_BINOP, false);
   1752       BINOP_CASE(Token::LT, Lt, SIGNED_BINOP, false);
   1753       BINOP_CASE(Token::LTE, Le, SIGNED_BINOP, false);
   1754       BINOP_CASE(Token::GT, Gt, SIGNED_BINOP, false);
   1755       BINOP_CASE(Token::GTE, Ge, SIGNED_BINOP, false);
   1756       default:
   1757         UNREACHABLE();
   1758     }
   1759   }
   1760 
   1761 #undef BINOP_CASE
   1762 #undef NON_SIGNED_INT_BINOP
   1763 #undef SIGNED_BINOP
   1764 #undef NON_SIGNED_BINOP
   1765 
   1766   enum TypeIndex {
   1767     kInt32 = 0,
   1768     kUint32 = 1,
   1769     kFloat32 = 2,
   1770     kFloat64 = 3,
   1771     kFixnum = 4
   1772   };
   1773 
   1774   TypeIndex TypeIndexOf(Expression* left, Expression* right, bool ignore_sign) {
   1775     TypeIndex left_index = TypeIndexOf(left, ignore_sign);
   1776     TypeIndex right_index = TypeIndexOf(right, ignore_sign);
   1777     if (left_index == kFixnum) {
   1778       left_index = right_index;
   1779     }
   1780     if (right_index == kFixnum) {
   1781       right_index = left_index;
   1782     }
   1783     if (left_index == kFixnum && right_index == kFixnum) {
   1784       left_index = kInt32;
   1785       right_index = kInt32;
   1786     }
   1787     if (left_index != right_index) {
   1788       DCHECK(ignore_sign && (left_index <= 1) && (right_index <= 1));
   1789     }
   1790     return left_index;
   1791   }
   1792 
   1793   TypeIndex TypeIndexOf(Expression* expr, bool ignore_sign) {
   1794     AsmType* type = typer_->TypeOf(expr);
   1795     if (type->IsA(AsmType::FixNum())) {
   1796       return kFixnum;
   1797     }
   1798 
   1799     if (type->IsA(AsmType::Signed())) {
   1800       return kInt32;
   1801     }
   1802 
   1803     if (type->IsA(AsmType::Unsigned())) {
   1804       return kUint32;
   1805     }
   1806 
   1807     if (type->IsA(AsmType::Intish())) {
   1808       if (!ignore_sign) {
   1809         // TODO(jpp): log a warning and move on.
   1810       }
   1811       return kInt32;
   1812     }
   1813 
   1814     if (type->IsA(AsmType::Floatish())) {
   1815       return kFloat32;
   1816     }
   1817 
   1818     if (type->IsA(AsmType::DoubleQ())) {
   1819       return kFloat64;
   1820     }
   1821 
   1822     UNREACHABLE();
   1823     return kInt32;
   1824   }
   1825 
   1826 #undef CASE
   1827 #undef NON_SIGNED_INT
   1828 #undef SIGNED
   1829 #undef NON_SIGNED
   1830 
   1831   void VisitThisFunction(ThisFunction* expr) { UNREACHABLE(); }
   1832 
   1833   void VisitDeclarations(Declaration::List* decls) {
   1834     for (Declaration* decl : *decls) {
   1835       RECURSE(Visit(decl));
   1836       if (typer_failed_) {
   1837         return;
   1838       }
   1839     }
   1840   }
   1841 
   1842   void VisitClassLiteral(ClassLiteral* expr) { UNREACHABLE(); }
   1843 
   1844   void VisitSpread(Spread* expr) { UNREACHABLE(); }
   1845 
   1846   void VisitSuperPropertyReference(SuperPropertyReference* expr) {
   1847     UNREACHABLE();
   1848   }
   1849 
   1850   void VisitSuperCallReference(SuperCallReference* expr) { UNREACHABLE(); }
   1851 
   1852   void VisitSloppyBlockFunctionStatement(SloppyBlockFunctionStatement* expr) {
   1853     UNREACHABLE();
   1854   }
   1855 
   1856   void VisitDoExpression(DoExpression* expr) { UNREACHABLE(); }
   1857 
   1858   void VisitRewritableExpression(RewritableExpression* expr) { UNREACHABLE(); }
   1859 
   1860   struct IndexContainer : public ZoneObject {
   1861     uint32_t index;
   1862   };
   1863 
   1864   uint32_t LookupOrInsertLocal(Variable* v, ValueType type) {
   1865     DCHECK_NOT_NULL(current_function_builder_);
   1866     ZoneHashMap::Entry* entry =
   1867         local_variables_.Lookup(v, ComputePointerHash(v));
   1868     if (entry == nullptr) {
   1869       uint32_t index;
   1870       DCHECK(!v->IsParameter());
   1871       index = current_function_builder_->AddLocal(type);
   1872       IndexContainer* container = new (zone()) IndexContainer();
   1873       container->index = index;
   1874       entry = local_variables_.LookupOrInsert(v, ComputePointerHash(v),
   1875                                               ZoneAllocationPolicy(zone()));
   1876       entry->value = container;
   1877     }
   1878     return (reinterpret_cast<IndexContainer*>(entry->value))->index;
   1879   }
   1880 
   1881   void InsertParameter(Variable* v, ValueType type, uint32_t index) {
   1882     DCHECK(v->IsParameter());
   1883     DCHECK_NOT_NULL(current_function_builder_);
   1884     ZoneHashMap::Entry* entry =
   1885         local_variables_.Lookup(v, ComputePointerHash(v));
   1886     DCHECK_NULL(entry);
   1887     IndexContainer* container = new (zone()) IndexContainer();
   1888     container->index = index;
   1889     entry = local_variables_.LookupOrInsert(v, ComputePointerHash(v),
   1890                                             ZoneAllocationPolicy(zone()));
   1891     entry->value = container;
   1892   }
   1893 
   1894   uint32_t LookupOrInsertGlobal(Variable* v, ValueType type) {
   1895     ZoneHashMap::Entry* entry =
   1896         global_variables_.Lookup(v, ComputePointerHash(v));
   1897     if (entry == nullptr) {
   1898       uint32_t index = builder_->AddGlobal(type, 0);
   1899       IndexContainer* container = new (zone()) IndexContainer();
   1900       container->index = index;
   1901       entry = global_variables_.LookupOrInsert(v, ComputePointerHash(v),
   1902                                                ZoneAllocationPolicy(zone()));
   1903       entry->value = container;
   1904     }
   1905     return (reinterpret_cast<IndexContainer*>(entry->value))->index;
   1906   }
   1907 
   1908   WasmFunctionBuilder* LookupOrInsertFunction(Variable* v) {
   1909     DCHECK_NOT_NULL(builder_);
   1910     ZoneHashMap::Entry* entry = functions_.Lookup(v, ComputePointerHash(v));
   1911     if (entry == nullptr) {
   1912       auto* func_type = typer_->TypeOf(v)->AsFunctionType();
   1913       DCHECK_NOT_NULL(func_type);
   1914       // Build the signature for the function.
   1915       ValueType return_type = TypeFrom(func_type->ReturnType());
   1916       const auto& arguments = func_type->Arguments();
   1917       FunctionSig::Builder b(zone(), return_type == kWasmStmt ? 0 : 1,
   1918                              arguments.size());
   1919       if (return_type != kWasmStmt) b.AddReturn(return_type);
   1920       for (int i = 0; i < static_cast<int>(arguments.size()); ++i) {
   1921         ValueType type = TypeFrom(arguments[i]);
   1922         DCHECK_NE(kWasmStmt, type);
   1923         b.AddParam(type);
   1924       }
   1925 
   1926       WasmFunctionBuilder* function = builder_->AddFunction(b.Build());
   1927       entry = functions_.LookupOrInsert(v, ComputePointerHash(v),
   1928                                         ZoneAllocationPolicy(zone()));
   1929       function->SetName(
   1930           {reinterpret_cast<const char*>(v->raw_name()->raw_data()),
   1931            v->raw_name()->length()});
   1932       entry->value = function;
   1933     }
   1934     return (reinterpret_cast<WasmFunctionBuilder*>(entry->value));
   1935   }
   1936 
   1937   ValueType TypeOf(Expression* expr) { return TypeFrom(typer_->TypeOf(expr)); }
   1938 
   1939   ValueType TypeFrom(AsmType* type) {
   1940     if (type->IsA(AsmType::Intish())) {
   1941       return kWasmI32;
   1942     }
   1943 
   1944     if (type->IsA(AsmType::Floatish())) {
   1945       return kWasmF32;
   1946     }
   1947 
   1948     if (type->IsA(AsmType::DoubleQ())) {
   1949       return kWasmF64;
   1950     }
   1951 
   1952     return kWasmStmt;
   1953   }
   1954 
   1955   Zone* zone() { return zone_; }
   1956 
   1957   ZoneHashMap local_variables_;
   1958   ZoneHashMap functions_;
   1959   ZoneHashMap global_variables_;
   1960   AsmScope scope_;
   1961   WasmModuleBuilder* builder_;
   1962   WasmFunctionBuilder* current_function_builder_;
   1963   FunctionLiteral* literal_;
   1964   Isolate* isolate_;
   1965   Zone* zone_;
   1966   CompilationInfo* info_;
   1967   AstValueFactory* ast_value_factory_;
   1968   Handle<Script> script_;
   1969   AsmTyper* typer_;
   1970   bool typer_failed_;
   1971   bool typer_finished_;
   1972   ZoneVector<std::pair<BreakableStatement*, TargetType>> breakable_blocks_;
   1973   ZoneVector<ForeignVariable> foreign_variables_;
   1974   WasmFunctionBuilder* init_function_;
   1975   WasmFunctionBuilder* foreign_init_function_;
   1976   uint32_t next_table_index_;
   1977   ZoneHashMap function_tables_;
   1978   ImportedFunctionTable imported_function_table_;
   1979   // Remember the parent node for reporting the correct location for ToNumber
   1980   // conversions after calls.
   1981   BinaryOperation* parent_binop_;
   1982 
   1983   DEFINE_AST_VISITOR_SUBCLASS_MEMBERS();
   1984 
   1985  private:
   1986   DISALLOW_COPY_AND_ASSIGN(AsmWasmBuilderImpl);
   1987 };
   1988 
   1989 AsmWasmBuilder::AsmWasmBuilder(CompilationInfo* info)
   1990     : info_(info),
   1991       typer_(info->isolate(), info->zone(), info->script(), info->literal()) {}
   1992 
   1993 // TODO(aseemgarg): probably should take zone (to write wasm to) as input so
   1994 // that zone in constructor may be thrown away once wasm module is written.
   1995 AsmWasmBuilder::Result AsmWasmBuilder::Run(Handle<FixedArray>* foreign_args) {
   1996   HistogramTimerScope asm_wasm_time_scope(
   1997       info_->isolate()->counters()->asm_wasm_translation_time());
   1998 
   1999   Zone* zone = info_->zone();
   2000   AsmWasmBuilderImpl impl(info_->isolate(), zone, info_,
   2001                           info_->parse_info()->ast_value_factory(),
   2002                           info_->script(), info_->literal(), &typer_);
   2003   bool success = impl.Build();
   2004   *foreign_args = impl.GetForeignArgs();
   2005   ZoneBuffer* module_buffer = new (zone) ZoneBuffer(zone);
   2006   impl.builder_->WriteTo(*module_buffer);
   2007   ZoneBuffer* asm_offsets_buffer = new (zone) ZoneBuffer(zone);
   2008   impl.builder_->WriteAsmJsOffsetTable(*asm_offsets_buffer);
   2009   return {module_buffer, asm_offsets_buffer, success};
   2010 }
   2011 
   2012 const char* AsmWasmBuilder::foreign_init_name = "__foreign_init__";
   2013 const char* AsmWasmBuilder::single_function_name = "__single_function__";
   2014 
   2015 }  // namespace wasm
   2016 }  // namespace internal
   2017 }  // namespace v8
   2018