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