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