Home | History | Annotate | Download | only in wasm
      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 #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 
     16 namespace v8 {
     17 namespace internal {
     18 namespace wasm {
     19 
     20 #define RECURSE(call)               \
     21   do {                              \
     22     DCHECK(!HasStackOverflow());    \
     23     call;                           \
     24     if (HasStackOverflow()) return; \
     25   } while (false)
     26 
     27 
     28 class 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 
   1031 AsmWasmBuilder::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.
   1037 WasmModuleIndex* 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
   1046