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