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