LCOV - code coverage report
Current view: top level - src/asmjs - asm-wasm-builder.cc (source / functions) Hit Total Coverage
Test: app.info Lines: 846 915 92.5 %
Date: 2017-04-26 Functions: 66 92 71.7 %

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

Generated by: LCOV version 1.10