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