blob: 30f84642f82acd53cc9b88b3f1e37c47d858ab29 [file] [log] [blame]
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001// 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#include "src/wasm/asm-wasm-builder.h"
8#include "src/wasm/wasm-macro-gen.h"
9#include "src/wasm/wasm-opcodes.h"
10
11#include "src/ast/ast.h"
12#include "src/ast/scopes.h"
13#include "src/codegen.h"
14#include "src/type-cache.h"
15
16namespace v8 {
17namespace internal {
18namespace wasm {
19
20#define RECURSE(call) \
21 do { \
22 DCHECK(!HasStackOverflow()); \
23 call; \
24 if (HasStackOverflow()) return; \
25 } while (false)
26
27
28class AsmWasmBuilderImpl : public AstVisitor {
29 public:
30 AsmWasmBuilderImpl(Isolate* isolate, Zone* zone, FunctionLiteral* literal)
31 : local_variables_(HashMap::PointersMatch,
32 ZoneHashMap::kDefaultHashMapCapacity,
33 ZoneAllocationPolicy(zone)),
34 functions_(HashMap::PointersMatch, ZoneHashMap::kDefaultHashMapCapacity,
35 ZoneAllocationPolicy(zone)),
36 global_variables_(HashMap::PointersMatch,
37 ZoneHashMap::kDefaultHashMapCapacity,
38 ZoneAllocationPolicy(zone)),
39 in_function_(false),
40 is_set_op_(false),
41 marking_exported(false),
42 builder_(new (zone) WasmModuleBuilder(zone)),
43 current_function_builder_(nullptr),
44 literal_(literal),
45 isolate_(isolate),
46 zone_(zone),
47 cache_(TypeCache::Get()),
48 breakable_blocks_(zone),
49 block_size_(0),
50 init_function_index(0) {
51 InitializeAstVisitor(isolate);
52 }
53
54 void InitializeInitFunction() {
55 unsigned char init[] = "__init__";
56 init_function_index = builder_->AddFunction();
57 current_function_builder_ = builder_->FunctionAt(init_function_index);
58 current_function_builder_->SetName(init, 8);
59 current_function_builder_->ReturnType(kAstStmt);
60 current_function_builder_->Exported(1);
61 current_function_builder_ = nullptr;
62 }
63
64 void Compile() {
65 InitializeInitFunction();
66 RECURSE(VisitFunctionLiteral(literal_));
67 }
68
69 void VisitVariableDeclaration(VariableDeclaration* decl) {}
70
71 void VisitFunctionDeclaration(FunctionDeclaration* decl) {
72 DCHECK(!in_function_);
73 DCHECK(current_function_builder_ == nullptr);
74 uint16_t index = LookupOrInsertFunction(decl->proxy()->var());
75 current_function_builder_ = builder_->FunctionAt(index);
76 in_function_ = true;
77 RECURSE(Visit(decl->fun()));
78 in_function_ = false;
79 current_function_builder_ = nullptr;
80 local_variables_.Clear();
81 }
82
83 void VisitImportDeclaration(ImportDeclaration* decl) {}
84
85 void VisitExportDeclaration(ExportDeclaration* decl) {}
86
87 void VisitStatements(ZoneList<Statement*>* stmts) {
88 for (int i = 0; i < stmts->length(); ++i) {
89 Statement* stmt = stmts->at(i);
90 RECURSE(Visit(stmt));
91 if (stmt->IsJump()) break;
92 }
93 }
94
95 void VisitBlock(Block* stmt) {
96 if (stmt->statements()->length() == 1) {
97 ExpressionStatement* expr =
98 stmt->statements()->at(0)->AsExpressionStatement();
99 if (expr != nullptr) {
100 if (expr->expression()->IsAssignment()) {
101 RECURSE(VisitExpressionStatement(expr));
102 return;
103 }
104 }
105 }
106 DCHECK(in_function_);
107 BlockVisitor visitor(this, stmt->AsBreakableStatement(), kExprBlock, false,
108 static_cast<byte>(stmt->statements()->length()));
109 RECURSE(VisitStatements(stmt->statements()));
110 DCHECK(block_size_ >= 0);
111 }
112
113 class BlockVisitor {
114 private:
115 int prev_block_size_;
116 uint32_t index_;
117 AsmWasmBuilderImpl* builder_;
118
119 public:
120 BlockVisitor(AsmWasmBuilderImpl* builder, BreakableStatement* stmt,
121 WasmOpcode opcode, bool is_loop, int initial_block_size)
122 : builder_(builder) {
123 builder_->breakable_blocks_.push_back(std::make_pair(stmt, is_loop));
124 builder_->current_function_builder_->Emit(opcode);
125 index_ = builder_->current_function_builder_->EmitEditableImmediate(0);
126 prev_block_size_ = builder_->block_size_;
127 builder_->block_size_ = initial_block_size;
128 }
129 ~BlockVisitor() {
130 builder_->current_function_builder_->EditImmediate(index_,
131 builder_->block_size_);
132 builder_->block_size_ = prev_block_size_;
133 builder_->breakable_blocks_.pop_back();
134 }
135 };
136
137 void VisitExpressionStatement(ExpressionStatement* stmt) {
138 RECURSE(Visit(stmt->expression()));
139 }
140
141 void VisitEmptyStatement(EmptyStatement* stmt) {}
142
143 void VisitEmptyParentheses(EmptyParentheses* paren) { UNREACHABLE(); }
144
145 void VisitIfStatement(IfStatement* stmt) {
146 DCHECK(in_function_);
147 if (stmt->HasElseStatement()) {
148 current_function_builder_->Emit(kExprIfElse);
149 } else {
150 current_function_builder_->Emit(kExprIf);
151 }
152 RECURSE(Visit(stmt->condition()));
153 if (stmt->HasThenStatement()) {
154 RECURSE(Visit(stmt->then_statement()));
155 } else {
156 current_function_builder_->Emit(kExprNop);
157 }
158 if (stmt->HasElseStatement()) {
159 RECURSE(Visit(stmt->else_statement()));
160 }
161 }
162
163 void VisitContinueStatement(ContinueStatement* stmt) {
164 DCHECK(in_function_);
165 DCHECK(stmt->target() != NULL);
166 int i = static_cast<int>(breakable_blocks_.size()) - 1;
167 int block_distance = 0;
168 for (; i >= 0; i--) {
169 auto elem = breakable_blocks_.at(i);
170 if (elem.first == stmt->target()) {
171 DCHECK(elem.second);
172 break;
173 } else if (elem.second) {
174 block_distance += 2;
175 } else {
176 block_distance += 1;
177 }
178 }
179 DCHECK(i >= 0);
180 current_function_builder_->EmitWithU8(kExprBr, block_distance);
181 current_function_builder_->Emit(kExprNop);
182 }
183
184 void VisitBreakStatement(BreakStatement* stmt) {
185 DCHECK(in_function_);
186 DCHECK(stmt->target() != NULL);
187 int i = static_cast<int>(breakable_blocks_.size()) - 1;
188 int block_distance = 0;
189 for (; i >= 0; i--) {
190 auto elem = breakable_blocks_.at(i);
191 if (elem.first == stmt->target()) {
192 if (elem.second) {
193 block_distance++;
194 }
195 break;
196 } else if (elem.second) {
197 block_distance += 2;
198 } else {
199 block_distance += 1;
200 }
201 }
202 DCHECK(i >= 0);
203 current_function_builder_->EmitWithU8(kExprBr, block_distance);
204 current_function_builder_->Emit(kExprNop);
205 }
206
207 void VisitReturnStatement(ReturnStatement* stmt) {
208 if (in_function_) {
209 current_function_builder_->Emit(kExprReturn);
210 } else {
211 marking_exported = true;
212 }
213 RECURSE(Visit(stmt->expression()));
214 if (!in_function_) {
215 marking_exported = false;
216 }
217 }
218
219 void VisitWithStatement(WithStatement* stmt) { UNREACHABLE(); }
220
221 void SetLocalTo(uint16_t index, int value) {
222 current_function_builder_->Emit(kExprSetLocal);
223 AddLeb128(index, true);
224 byte code[] = {WASM_I32(value)};
225 current_function_builder_->EmitCode(code, sizeof(code));
226 block_size_++;
227 }
228
229 void CompileCase(CaseClause* clause, uint16_t fall_through,
230 VariableProxy* tag) {
231 Literal* label = clause->label()->AsLiteral();
232 DCHECK(label != nullptr);
233 block_size_++;
234 current_function_builder_->Emit(kExprIf);
235 current_function_builder_->Emit(kExprI32Ior);
236 current_function_builder_->Emit(kExprI32Eq);
237 VisitVariableProxy(tag);
238 VisitLiteral(label);
239 current_function_builder_->Emit(kExprGetLocal);
240 AddLeb128(fall_through, true);
241 BlockVisitor visitor(this, nullptr, kExprBlock, false, 0);
242 SetLocalTo(fall_through, 1);
243 ZoneList<Statement*>* stmts = clause->statements();
244 block_size_ += stmts->length();
245 RECURSE(VisitStatements(stmts));
246 }
247
248 void VisitSwitchStatement(SwitchStatement* stmt) {
249 VariableProxy* tag = stmt->tag()->AsVariableProxy();
250 DCHECK(tag != NULL);
251 BlockVisitor visitor(this, stmt->AsBreakableStatement(), kExprBlock, false,
252 0);
253 uint16_t fall_through = current_function_builder_->AddLocal(kAstI32);
254 SetLocalTo(fall_through, 0);
255
256 ZoneList<CaseClause*>* clauses = stmt->cases();
257 for (int i = 0; i < clauses->length(); ++i) {
258 CaseClause* clause = clauses->at(i);
259 if (!clause->is_default()) {
260 CompileCase(clause, fall_through, tag);
261 } else {
262 ZoneList<Statement*>* stmts = clause->statements();
263 block_size_ += stmts->length();
264 RECURSE(VisitStatements(stmts));
265 }
266 }
267 }
268
269 void VisitCaseClause(CaseClause* clause) { UNREACHABLE(); }
270
271 void VisitDoWhileStatement(DoWhileStatement* stmt) {
272 DCHECK(in_function_);
273 BlockVisitor visitor(this, stmt->AsBreakableStatement(), kExprLoop, true,
274 2);
275 RECURSE(Visit(stmt->body()));
276 current_function_builder_->Emit(kExprIf);
277 RECURSE(Visit(stmt->cond()));
278 current_function_builder_->EmitWithU8(kExprBr, 0);
279 current_function_builder_->Emit(kExprNop);
280 }
281
282 void VisitWhileStatement(WhileStatement* stmt) {
283 DCHECK(in_function_);
284 BlockVisitor visitor(this, stmt->AsBreakableStatement(), kExprLoop, true,
285 1);
286 current_function_builder_->Emit(kExprIf);
287 RECURSE(Visit(stmt->cond()));
288 current_function_builder_->EmitWithU8(kExprBr, 0);
289 RECURSE(Visit(stmt->body()));
290 }
291
292 void VisitForStatement(ForStatement* stmt) {
293 DCHECK(in_function_);
294 if (stmt->init() != nullptr) {
295 block_size_++;
296 RECURSE(Visit(stmt->init()));
297 }
298 BlockVisitor visitor(this, stmt->AsBreakableStatement(), kExprLoop, true,
299 0);
300 if (stmt->cond() != nullptr) {
301 block_size_++;
302 current_function_builder_->Emit(kExprIf);
303 current_function_builder_->Emit(kExprBoolNot);
304 RECURSE(Visit(stmt->cond()));
305 current_function_builder_->EmitWithU8(kExprBr, 1);
306 current_function_builder_->Emit(kExprNop);
307 }
308 if (stmt->body() != nullptr) {
309 block_size_++;
310 RECURSE(Visit(stmt->body()));
311 }
312 if (stmt->next() != nullptr) {
313 block_size_++;
314 RECURSE(Visit(stmt->next()));
315 }
316 block_size_++;
317 current_function_builder_->EmitWithU8(kExprBr, 0);
318 current_function_builder_->Emit(kExprNop);
319 }
320
321 void VisitForInStatement(ForInStatement* stmt) { UNREACHABLE(); }
322
323 void VisitForOfStatement(ForOfStatement* stmt) { UNREACHABLE(); }
324
325 void VisitTryCatchStatement(TryCatchStatement* stmt) { UNREACHABLE(); }
326
327 void VisitTryFinallyStatement(TryFinallyStatement* stmt) { UNREACHABLE(); }
328
329 void VisitDebuggerStatement(DebuggerStatement* stmt) { UNREACHABLE(); }
330
331 void VisitFunctionLiteral(FunctionLiteral* expr) {
332 Scope* scope = expr->scope();
333 if (in_function_) {
334 if (expr->bounds().lower->IsFunction()) {
335 Type::FunctionType* func_type = expr->bounds().lower->AsFunction();
336 LocalType return_type = TypeFrom(func_type->Result());
337 current_function_builder_->ReturnType(return_type);
338 for (int i = 0; i < expr->parameter_count(); i++) {
339 LocalType type = TypeFrom(func_type->Parameter(i));
340 DCHECK(type != kAstStmt);
341 LookupOrInsertLocal(scope->parameter(i), type);
342 }
343 } else {
344 UNREACHABLE();
345 }
346 }
347 RECURSE(VisitDeclarations(scope->declarations()));
348 RECURSE(VisitStatements(expr->body()));
349 }
350
351 void VisitNativeFunctionLiteral(NativeFunctionLiteral* expr) {
352 UNREACHABLE();
353 }
354
355 void VisitConditional(Conditional* expr) {
356 DCHECK(in_function_);
357 current_function_builder_->Emit(kExprIfElse);
358 RECURSE(Visit(expr->condition()));
359 RECURSE(Visit(expr->then_expression()));
360 RECURSE(Visit(expr->else_expression()));
361 }
362
363 void VisitVariableProxy(VariableProxy* expr) {
364 if (in_function_) {
365 Variable* var = expr->var();
366 if (var->is_function()) {
367 DCHECK(!is_set_op_);
368 std::vector<uint8_t> index =
369 UnsignedLEB128From(LookupOrInsertFunction(var));
370 current_function_builder_->EmitCode(
371 &index[0], static_cast<uint32_t>(index.size()));
372 } else {
373 if (is_set_op_) {
374 if (var->IsContextSlot()) {
375 current_function_builder_->Emit(kExprStoreGlobal);
376 } else {
377 current_function_builder_->Emit(kExprSetLocal);
378 }
379 is_set_op_ = false;
380 } else {
381 if (var->IsContextSlot()) {
382 current_function_builder_->Emit(kExprLoadGlobal);
383 } else {
384 current_function_builder_->Emit(kExprGetLocal);
385 }
386 }
387 LocalType var_type = TypeOf(expr);
388 DCHECK(var_type != kAstStmt);
389 if (var->IsContextSlot()) {
390 AddLeb128(LookupOrInsertGlobal(var, var_type), false);
391 } else {
392 AddLeb128(LookupOrInsertLocal(var, var_type), true);
393 }
394 }
395 }
396 }
397
398 void VisitLiteral(Literal* expr) {
399 if (in_function_) {
400 if (expr->raw_value()->IsNumber()) {
401 LocalType type = TypeOf(expr);
402 switch (type) {
403 case kAstI32: {
404 int val = static_cast<int>(expr->raw_value()->AsNumber());
405 byte code[] = {WASM_I32(val)};
406 current_function_builder_->EmitCode(code, sizeof(code));
407 break;
408 }
409 case kAstF32: {
410 float val = static_cast<float>(expr->raw_value()->AsNumber());
411 byte code[] = {WASM_F32(val)};
412 current_function_builder_->EmitCode(code, sizeof(code));
413 break;
414 }
415 case kAstF64: {
416 double val = static_cast<double>(expr->raw_value()->AsNumber());
417 byte code[] = {WASM_F64(val)};
418 current_function_builder_->EmitCode(code, sizeof(code));
419 break;
420 }
421 default:
422 UNREACHABLE();
423 }
424 }
425 }
426 }
427
428 void VisitRegExpLiteral(RegExpLiteral* expr) { UNREACHABLE(); }
429
430 void VisitObjectLiteral(ObjectLiteral* expr) {
431 ZoneList<ObjectLiteralProperty*>* props = expr->properties();
432 for (int i = 0; i < props->length(); ++i) {
433 ObjectLiteralProperty* prop = props->at(i);
434 DCHECK(marking_exported);
435 VariableProxy* expr = prop->value()->AsVariableProxy();
436 DCHECK(expr != nullptr);
437 Variable* var = expr->var();
438 Literal* name = prop->key()->AsLiteral();
439 DCHECK(name != nullptr);
440 DCHECK(name->IsPropertyName());
441 const AstRawString* raw_name = name->AsRawPropertyName();
442 if (var->is_function()) {
443 uint16_t index = LookupOrInsertFunction(var);
444 builder_->FunctionAt(index)->Exported(1);
445 builder_->FunctionAt(index)
446 ->SetName(raw_name->raw_data(), raw_name->length());
447 }
448 }
449 }
450
451 void VisitArrayLiteral(ArrayLiteral* expr) { UNREACHABLE(); }
452
453 void LoadInitFunction() {
454 current_function_builder_ = builder_->FunctionAt(init_function_index);
455 in_function_ = true;
456 }
457
458 void UnLoadInitFunction() {
459 in_function_ = false;
460 current_function_builder_ = nullptr;
461 }
462
463 void VisitAssignment(Assignment* expr) {
464 bool in_init = false;
465 if (!in_function_) {
466 // TODO(bradnelson): Get rid of this.
467 if (TypeOf(expr->value()) == kAstStmt) {
468 return;
469 }
470 in_init = true;
471 LoadInitFunction();
472 }
473 BinaryOperation* value_op = expr->value()->AsBinaryOperation();
474 if (value_op != nullptr && MatchBinaryOperation(value_op) == kAsIs) {
475 VariableProxy* target_var = expr->target()->AsVariableProxy();
476 VariableProxy* effective_value_var = GetLeft(value_op)->AsVariableProxy();
477 if (target_var != nullptr && effective_value_var != nullptr &&
478 target_var->var() == effective_value_var->var()) {
479 block_size_--;
480 return;
481 }
482 }
483 is_set_op_ = true;
484 RECURSE(Visit(expr->target()));
485 DCHECK(!is_set_op_);
486 RECURSE(Visit(expr->value()));
487 if (in_init) {
488 UnLoadInitFunction();
489 }
490 }
491
492 void VisitYield(Yield* expr) { UNREACHABLE(); }
493
494 void VisitThrow(Throw* expr) { UNREACHABLE(); }
495
496 void VisitProperty(Property* expr) {
497 Expression* obj = expr->obj();
498 DCHECK(obj->bounds().lower == obj->bounds().upper);
499 TypeImpl<ZoneTypeConfig>* type = obj->bounds().lower;
500 MachineType mtype;
501 int size;
502 if (type->Is(cache_.kUint8Array)) {
503 mtype = MachineType::Uint8();
504 size = 1;
505 } else if (type->Is(cache_.kInt8Array)) {
506 mtype = MachineType::Int8();
507 size = 1;
508 } else if (type->Is(cache_.kUint16Array)) {
509 mtype = MachineType::Uint16();
510 size = 2;
511 } else if (type->Is(cache_.kInt16Array)) {
512 mtype = MachineType::Int16();
513 size = 2;
514 } else if (type->Is(cache_.kUint32Array)) {
515 mtype = MachineType::Uint32();
516 size = 4;
517 } else if (type->Is(cache_.kInt32Array)) {
518 mtype = MachineType::Int32();
519 size = 4;
520 } else if (type->Is(cache_.kUint32Array)) {
521 mtype = MachineType::Uint32();
522 size = 4;
523 } else if (type->Is(cache_.kFloat32Array)) {
524 mtype = MachineType::Float32();
525 size = 4;
526 } else if (type->Is(cache_.kFloat64Array)) {
527 mtype = MachineType::Float64();
528 size = 8;
529 } else {
530 UNREACHABLE();
531 }
532 current_function_builder_->EmitWithU8(
533 WasmOpcodes::LoadStoreOpcodeOf(mtype, is_set_op_),
534 WasmOpcodes::LoadStoreAccessOf(false));
535 is_set_op_ = false;
536 Literal* value = expr->key()->AsLiteral();
537 if (value) {
538 DCHECK(value->raw_value()->IsNumber());
539 DCHECK(kAstI32 == TypeOf(value));
540 int val = static_cast<int>(value->raw_value()->AsNumber());
541 byte code[] = {WASM_I32(val * size)};
542 current_function_builder_->EmitCode(code, sizeof(code));
543 return;
544 }
545 BinaryOperation* binop = expr->key()->AsBinaryOperation();
546 if (binop) {
547 DCHECK(Token::SAR == binop->op());
548 DCHECK(binop->right()->AsLiteral()->raw_value()->IsNumber());
549 DCHECK(kAstI32 == TypeOf(binop->right()->AsLiteral()));
550 DCHECK(size ==
551 1 << static_cast<int>(
552 binop->right()->AsLiteral()->raw_value()->AsNumber()));
553 // Mask bottom bits to match asm.js behavior.
554 current_function_builder_->Emit(kExprI32And);
555 byte code[] = {WASM_I8(~(size - 1))};
556 current_function_builder_->EmitCode(code, sizeof(code));
557 RECURSE(Visit(binop->left()));
558 return;
559 }
560 UNREACHABLE();
561 }
562
563 void VisitCall(Call* expr) {
564 Call::CallType call_type = expr->GetCallType(isolate_);
565 switch (call_type) {
566 case Call::OTHER_CALL: {
567 DCHECK(in_function_);
568 current_function_builder_->Emit(kExprCallFunction);
569 RECURSE(Visit(expr->expression()));
570 ZoneList<Expression*>* args = expr->arguments();
571 for (int i = 0; i < args->length(); ++i) {
572 Expression* arg = args->at(i);
573 RECURSE(Visit(arg));
574 }
575 break;
576 }
577 default:
578 UNREACHABLE();
579 }
580 }
581
582 void VisitCallNew(CallNew* expr) { UNREACHABLE(); }
583
584 void VisitCallRuntime(CallRuntime* expr) { UNREACHABLE(); }
585
586 void VisitUnaryOperation(UnaryOperation* expr) {
587 switch (expr->op()) {
588 case Token::NOT: {
589 DCHECK(TypeOf(expr->expression()) == kAstI32);
590 current_function_builder_->Emit(kExprBoolNot);
591 break;
592 }
593 default:
594 UNREACHABLE();
595 }
596 RECURSE(Visit(expr->expression()));
597 }
598
599 void VisitCountOperation(CountOperation* expr) { UNREACHABLE(); }
600
601 bool MatchIntBinaryOperation(BinaryOperation* expr, Token::Value op,
602 int32_t val) {
603 DCHECK(expr->right() != nullptr);
604 if (expr->op() == op && expr->right()->IsLiteral() &&
605 TypeOf(expr) == kAstI32) {
606 Literal* right = expr->right()->AsLiteral();
607 DCHECK(right->raw_value()->IsNumber());
608 if (static_cast<int32_t>(right->raw_value()->AsNumber()) == val) {
609 return true;
610 }
611 }
612 return false;
613 }
614
615 bool MatchDoubleBinaryOperation(BinaryOperation* expr, Token::Value op,
616 double val) {
617 DCHECK(expr->right() != nullptr);
618 if (expr->op() == op && expr->right()->IsLiteral() &&
619 TypeOf(expr) == kAstF64) {
620 Literal* right = expr->right()->AsLiteral();
621 DCHECK(right->raw_value()->IsNumber());
622 if (right->raw_value()->AsNumber() == val) {
623 return true;
624 }
625 }
626 return false;
627 }
628
629 enum ConvertOperation { kNone, kAsIs, kToInt, kToDouble };
630
631 ConvertOperation MatchOr(BinaryOperation* expr) {
632 if (MatchIntBinaryOperation(expr, Token::BIT_OR, 0)) {
633 return (TypeOf(expr->left()) == kAstI32) ? kAsIs : kToInt;
634 } else {
635 return kNone;
636 }
637 }
638
639 ConvertOperation MatchShr(BinaryOperation* expr) {
640 if (MatchIntBinaryOperation(expr, Token::SHR, 0)) {
641 // TODO(titzer): this probably needs to be kToUint
642 return (TypeOf(expr->left()) == kAstI32) ? kAsIs : kToInt;
643 } else {
644 return kNone;
645 }
646 }
647
648 ConvertOperation MatchXor(BinaryOperation* expr) {
649 if (MatchIntBinaryOperation(expr, Token::BIT_XOR, 0xffffffff)) {
650 DCHECK(TypeOf(expr->left()) == kAstI32);
651 DCHECK(TypeOf(expr->right()) == kAstI32);
652 BinaryOperation* op = expr->left()->AsBinaryOperation();
653 if (op != nullptr) {
654 if (MatchIntBinaryOperation(op, Token::BIT_XOR, 0xffffffff)) {
655 DCHECK(TypeOf(op->right()) == kAstI32);
656 if (TypeOf(op->left()) != kAstI32) {
657 return kToInt;
658 } else {
659 return kAsIs;
660 }
661 }
662 }
663 }
664 return kNone;
665 }
666
667 ConvertOperation MatchMul(BinaryOperation* expr) {
668 if (MatchDoubleBinaryOperation(expr, Token::MUL, 1.0)) {
669 DCHECK(TypeOf(expr->right()) == kAstF64);
670 if (TypeOf(expr->left()) != kAstF64) {
671 return kToDouble;
672 } else {
673 return kAsIs;
674 }
675 } else {
676 return kNone;
677 }
678 }
679
680 ConvertOperation MatchBinaryOperation(BinaryOperation* expr) {
681 switch (expr->op()) {
682 case Token::BIT_OR:
683 return MatchOr(expr);
684 case Token::SHR:
685 return MatchShr(expr);
686 case Token::BIT_XOR:
687 return MatchXor(expr);
688 case Token::MUL:
689 return MatchMul(expr);
690 default:
691 return kNone;
692 }
693 }
694
695// Work around Mul + Div being defined in PPC assembler.
696#ifdef Mul
697#undef Mul
698#endif
699#ifdef Div
700#undef Div
701#endif
702
703#define NON_SIGNED_BINOP(op) \
704 static WasmOpcode opcodes[] = { \
705 kExprI32##op, \
706 kExprI32##op, \
707 kExprF32##op, \
708 kExprF64##op \
709 }
710
711#define SIGNED_BINOP(op) \
712 static WasmOpcode opcodes[] = { \
713 kExprI32##op##S, \
714 kExprI32##op##U, \
715 kExprF32##op, \
716 kExprF64##op \
717 }
718
719#define NON_SIGNED_INT_BINOP(op) \
720 static WasmOpcode opcodes[] = { kExprI32##op, kExprI32##op }
721
722#define BINOP_CASE(token, op, V, ignore_sign) \
723 case token: { \
724 V(op); \
725 int type = TypeIndexOf(expr->left(), expr->right(), ignore_sign); \
726 current_function_builder_->Emit(opcodes[type]); \
727 break; \
728 }
729
730 Expression* GetLeft(BinaryOperation* expr) {
731 if (expr->op() == Token::BIT_XOR) {
732 return expr->left()->AsBinaryOperation()->left();
733 } else {
734 return expr->left();
735 }
736 }
737
738 void VisitBinaryOperation(BinaryOperation* expr) {
739 ConvertOperation convertOperation = MatchBinaryOperation(expr);
740 if (convertOperation == kToDouble) {
741 TypeIndex type = TypeIndexOf(expr->left());
742 if (type == kInt32 || type == kFixnum) {
743 current_function_builder_->Emit(kExprF64SConvertI32);
744 } else if (type == kUint32) {
745 current_function_builder_->Emit(kExprF64UConvertI32);
746 } else if (type == kFloat32) {
747 current_function_builder_->Emit(kExprF64ConvertF32);
748 } else {
749 UNREACHABLE();
750 }
751 RECURSE(Visit(expr->left()));
752 } else if (convertOperation == kToInt) {
753 TypeIndex type = TypeIndexOf(GetLeft(expr));
754 if (type == kFloat32) {
755 current_function_builder_->Emit(kExprI32SConvertF32);
756 } else if (type == kFloat64) {
757 current_function_builder_->Emit(kExprI32SConvertF64);
758 } else {
759 UNREACHABLE();
760 }
761 RECURSE(Visit(GetLeft(expr)));
762 } else if (convertOperation == kAsIs) {
763 RECURSE(Visit(GetLeft(expr)));
764 } else {
765 switch (expr->op()) {
766 BINOP_CASE(Token::ADD, Add, NON_SIGNED_BINOP, true);
767 BINOP_CASE(Token::SUB, Sub, NON_SIGNED_BINOP, true);
768 BINOP_CASE(Token::MUL, Mul, NON_SIGNED_BINOP, true);
769 BINOP_CASE(Token::DIV, Div, SIGNED_BINOP, false);
770 BINOP_CASE(Token::BIT_OR, Ior, NON_SIGNED_INT_BINOP, true);
771 BINOP_CASE(Token::BIT_XOR, Xor, NON_SIGNED_INT_BINOP, true);
772 BINOP_CASE(Token::SHL, Shl, NON_SIGNED_INT_BINOP, true);
773 BINOP_CASE(Token::SAR, ShrS, NON_SIGNED_INT_BINOP, true);
774 BINOP_CASE(Token::SHR, ShrU, NON_SIGNED_INT_BINOP, true);
775 case Token::MOD: {
776 TypeIndex type = TypeIndexOf(expr->left(), expr->right(), false);
777 if (type == kInt32) {
778 current_function_builder_->Emit(kExprI32RemS);
779 } else if (type == kUint32) {
780 current_function_builder_->Emit(kExprI32RemU);
781 } else if (type == kFloat64) {
782 ModF64(expr);
783 return;
784 } else {
785 UNREACHABLE();
786 }
787 break;
788 }
789 default:
790 UNREACHABLE();
791 }
792 RECURSE(Visit(expr->left()));
793 RECURSE(Visit(expr->right()));
794 }
795 }
796
797 void ModF64(BinaryOperation* expr) {
798 current_function_builder_->EmitWithU8(kExprBlock, 3);
799 uint16_t index_0 = current_function_builder_->AddLocal(kAstF64);
800 uint16_t index_1 = current_function_builder_->AddLocal(kAstF64);
801 current_function_builder_->Emit(kExprSetLocal);
802 AddLeb128(index_0, true);
803 RECURSE(Visit(expr->left()));
804 current_function_builder_->Emit(kExprSetLocal);
805 AddLeb128(index_1, true);
806 RECURSE(Visit(expr->right()));
807 current_function_builder_->Emit(kExprF64Sub);
808 current_function_builder_->Emit(kExprGetLocal);
809 AddLeb128(index_0, true);
810 current_function_builder_->Emit(kExprF64Mul);
811 current_function_builder_->Emit(kExprGetLocal);
812 AddLeb128(index_1, true);
813 // Use trunc instead of two casts
814 current_function_builder_->Emit(kExprF64SConvertI32);
815 current_function_builder_->Emit(kExprI32SConvertF64);
816 current_function_builder_->Emit(kExprF64Div);
817 current_function_builder_->Emit(kExprGetLocal);
818 AddLeb128(index_0, true);
819 current_function_builder_->Emit(kExprGetLocal);
820 AddLeb128(index_1, true);
821 }
822
823 void AddLeb128(uint32_t index, bool is_local) {
824 std::vector<uint8_t> index_vec = UnsignedLEB128From(index);
825 if (is_local) {
826 uint32_t pos_of_index[1] = {0};
827 current_function_builder_->EmitCode(
828 &index_vec[0], static_cast<uint32_t>(index_vec.size()), pos_of_index,
829 1);
830 } else {
831 current_function_builder_->EmitCode(
832 &index_vec[0], static_cast<uint32_t>(index_vec.size()));
833 }
834 }
835
836 void VisitCompareOperation(CompareOperation* expr) {
837 switch (expr->op()) {
838 BINOP_CASE(Token::EQ, Eq, NON_SIGNED_BINOP, false);
839 BINOP_CASE(Token::LT, Lt, SIGNED_BINOP, false);
840 BINOP_CASE(Token::LTE, Le, SIGNED_BINOP, false);
841 BINOP_CASE(Token::GT, Gt, SIGNED_BINOP, false);
842 BINOP_CASE(Token::GTE, Ge, SIGNED_BINOP, false);
843 default:
844 UNREACHABLE();
845 }
846 RECURSE(Visit(expr->left()));
847 RECURSE(Visit(expr->right()));
848 }
849
850#undef BINOP_CASE
851#undef NON_SIGNED_INT_BINOP
852#undef SIGNED_BINOP
853#undef NON_SIGNED_BINOP
854
855 enum TypeIndex {
856 kInt32 = 0,
857 kUint32 = 1,
858 kFloat32 = 2,
859 kFloat64 = 3,
860 kFixnum = 4
861 };
862
863 TypeIndex TypeIndexOf(Expression* left, Expression* right, bool ignore_sign) {
864 TypeIndex left_index = TypeIndexOf(left);
865 TypeIndex right_index = TypeIndexOf(right);
866 if (left_index == kFixnum) {
867 left_index = right_index;
868 }
869 if (right_index == kFixnum) {
870 right_index = left_index;
871 }
872 if (left_index == kFixnum && right_index == kFixnum) {
873 left_index = kInt32;
874 right_index = kInt32;
875 }
876 DCHECK((left_index == right_index) ||
877 (ignore_sign && (left_index <= 1) && (right_index <= 1)));
878 return left_index;
879 }
880
881 TypeIndex TypeIndexOf(Expression* expr) {
882 DCHECK(expr->bounds().lower == expr->bounds().upper);
883 TypeImpl<ZoneTypeConfig>* type = expr->bounds().lower;
884 if (type->Is(cache_.kAsmFixnum)) {
885 return kFixnum;
886 } else if (type->Is(cache_.kAsmSigned)) {
887 return kInt32;
888 } else if (type->Is(cache_.kAsmUnsigned)) {
889 return kUint32;
890 } else if (type->Is(cache_.kAsmInt)) {
891 return kInt32;
892 } else if (type->Is(cache_.kAsmFloat)) {
893 return kFloat32;
894 } else if (type->Is(cache_.kAsmDouble)) {
895 return kFloat64;
896 } else {
897 UNREACHABLE();
898 return kInt32;
899 }
900 }
901
902#undef CASE
903#undef NON_SIGNED_INT
904#undef SIGNED
905#undef NON_SIGNED
906
907 void VisitThisFunction(ThisFunction* expr) { UNREACHABLE(); }
908
909 void VisitDeclarations(ZoneList<Declaration*>* decls) {
910 for (int i = 0; i < decls->length(); ++i) {
911 Declaration* decl = decls->at(i);
912 RECURSE(Visit(decl));
913 }
914 }
915
916 void VisitClassLiteral(ClassLiteral* expr) { UNREACHABLE(); }
917
918 void VisitSpread(Spread* expr) { UNREACHABLE(); }
919
920 void VisitSuperPropertyReference(SuperPropertyReference* expr) {
921 UNREACHABLE();
922 }
923
924 void VisitSuperCallReference(SuperCallReference* expr) { UNREACHABLE(); }
925
926 void VisitSloppyBlockFunctionStatement(SloppyBlockFunctionStatement* expr) {
927 UNREACHABLE();
928 }
929
930 void VisitDoExpression(DoExpression* expr) { UNREACHABLE(); }
931
932 void VisitRewritableAssignmentExpression(
933 RewritableAssignmentExpression* expr) {
934 UNREACHABLE();
935 }
936
937 struct IndexContainer : public ZoneObject {
938 uint16_t index;
939 };
940
941 uint16_t LookupOrInsertLocal(Variable* v, LocalType type) {
942 DCHECK(current_function_builder_ != nullptr);
943 ZoneHashMap::Entry* entry =
944 local_variables_.Lookup(v, ComputePointerHash(v));
945 if (entry == nullptr) {
946 uint16_t index;
947 if (v->IsParameter()) {
948 index = current_function_builder_->AddParam(type);
949 } else {
950 index = current_function_builder_->AddLocal(type);
951 }
952 IndexContainer* container = new (zone()) IndexContainer();
953 container->index = index;
954 entry = local_variables_.LookupOrInsert(v, ComputePointerHash(v),
955 ZoneAllocationPolicy(zone()));
956 entry->value = container;
957 }
958 return (reinterpret_cast<IndexContainer*>(entry->value))->index;
959 }
960
961 uint16_t LookupOrInsertGlobal(Variable* v, LocalType type) {
962 ZoneHashMap::Entry* entry =
963 global_variables_.Lookup(v, ComputePointerHash(v));
964 if (entry == nullptr) {
965 uint16_t index =
966 builder_->AddGlobal(WasmOpcodes::MachineTypeFor(type), 0);
967 IndexContainer* container = new (zone()) IndexContainer();
968 container->index = index;
969 entry = global_variables_.LookupOrInsert(v, ComputePointerHash(v),
970 ZoneAllocationPolicy(zone()));
971 entry->value = container;
972 }
973 return (reinterpret_cast<IndexContainer*>(entry->value))->index;
974 }
975
976 uint16_t LookupOrInsertFunction(Variable* v) {
977 DCHECK(builder_ != nullptr);
978 ZoneHashMap::Entry* entry = functions_.Lookup(v, ComputePointerHash(v));
979 if (entry == nullptr) {
980 uint16_t index = builder_->AddFunction();
981 IndexContainer* container = new (zone()) IndexContainer();
982 container->index = index;
983 entry = functions_.LookupOrInsert(v, ComputePointerHash(v),
984 ZoneAllocationPolicy(zone()));
985 entry->value = container;
986 }
987 return (reinterpret_cast<IndexContainer*>(entry->value))->index;
988 }
989
990 LocalType TypeOf(Expression* expr) {
991 DCHECK(expr->bounds().lower == expr->bounds().upper);
992 return TypeFrom(expr->bounds().lower);
993 }
994
995 LocalType TypeFrom(TypeImpl<ZoneTypeConfig>* type) {
996 if (type->Is(cache_.kAsmInt)) {
997 return kAstI32;
998 } else if (type->Is(cache_.kAsmFloat)) {
999 return kAstF32;
1000 } else if (type->Is(cache_.kAsmDouble)) {
1001 return kAstF64;
1002 } else {
1003 return kAstStmt;
1004 }
1005 }
1006
1007 Zone* zone() { return zone_; }
1008
1009 ZoneHashMap local_variables_;
1010 ZoneHashMap functions_;
1011 ZoneHashMap global_variables_;
1012 bool in_function_;
1013 bool is_set_op_;
1014 bool marking_exported;
1015 WasmModuleBuilder* builder_;
1016 WasmFunctionBuilder* current_function_builder_;
1017 FunctionLiteral* literal_;
1018 Isolate* isolate_;
1019 Zone* zone_;
1020 TypeCache const& cache_;
1021 ZoneVector<std::pair<BreakableStatement*, bool>> breakable_blocks_;
1022 int block_size_;
1023 uint16_t init_function_index;
1024
1025 DEFINE_AST_VISITOR_SUBCLASS_MEMBERS();
1026
1027 private:
1028 DISALLOW_COPY_AND_ASSIGN(AsmWasmBuilderImpl);
1029};
1030
1031AsmWasmBuilder::AsmWasmBuilder(Isolate* isolate, Zone* zone,
1032 FunctionLiteral* literal)
1033 : isolate_(isolate), zone_(zone), literal_(literal) {}
1034
1035// TODO(aseemgarg): probably should take zone (to write wasm to) as input so
1036// that zone in constructor may be thrown away once wasm module is written.
1037WasmModuleIndex* AsmWasmBuilder::Run() {
1038 AsmWasmBuilderImpl impl(isolate_, zone_, literal_);
1039 impl.Compile();
1040 WasmModuleWriter* writer = impl.builder_->Build(zone_);
1041 return writer->WriteTo(zone_);
1042}
1043} // namespace wasm
1044} // namespace internal
1045} // namespace v8