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