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