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