blob: 958fd0c389a2d9f0665f331fbd47a101c285fe9f [file] [log] [blame]
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001// Copyright 2015 the V8 project authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5#include "src/v8.h"
6
Ben Murdochda12d292016-06-02 14:46:10 +01007// 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 Murdoch4a90d5f2016-03-22 12:00:34 +000013#include "src/wasm/asm-wasm-builder.h"
Ben Murdochc5610432016-08-08 18:44:38 +010014#include "src/wasm/switch-logic.h"
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000015#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
23namespace v8 {
24namespace internal {
25namespace wasm {
26
27#define RECURSE(call) \
28 do { \
29 DCHECK(!HasStackOverflow()); \
30 call; \
31 if (HasStackOverflow()) return; \
32 } while (false)
33
Ben Murdochc5610432016-08-08 18:44:38 +010034enum AsmScope { kModuleScope, kInitScope, kFuncScope, kExportScope };
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000035
Ben Murdoch61f157c2016-09-16 13:49:30 +010036struct ForeignVariable {
37 Handle<Name> name;
38 Variable* var;
39 LocalType type;
40};
41
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000042class AsmWasmBuilderImpl : public AstVisitor {
43 public:
Ben Murdoch097c5b22016-05-18 11:27:45 +010044 AsmWasmBuilderImpl(Isolate* isolate, Zone* zone, FunctionLiteral* literal,
Ben Murdoch61f157c2016-09-16 13:49:30 +010045 AsmTyper* typer)
46 : local_variables_(base::HashMap::PointersMatch,
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000047 ZoneHashMap::kDefaultHashMapCapacity,
48 ZoneAllocationPolicy(zone)),
Ben Murdoch61f157c2016-09-16 13:49:30 +010049 functions_(base::HashMap::PointersMatch,
50 ZoneHashMap::kDefaultHashMapCapacity,
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000051 ZoneAllocationPolicy(zone)),
Ben Murdoch61f157c2016-09-16 13:49:30 +010052 global_variables_(base::HashMap::PointersMatch,
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000053 ZoneHashMap::kDefaultHashMapCapacity,
54 ZoneAllocationPolicy(zone)),
Ben Murdochc5610432016-08-08 18:44:38 +010055 scope_(kModuleScope),
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000056 builder_(new (zone) WasmModuleBuilder(zone)),
57 current_function_builder_(nullptr),
58 literal_(literal),
59 isolate_(isolate),
60 zone_(zone),
Ben Murdochda12d292016-06-02 14:46:10 +010061 typer_(typer),
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000062 cache_(TypeCache::Get()),
63 breakable_blocks_(zone),
Ben Murdoch61f157c2016-09-16 13:49:30 +010064 foreign_variables_(zone),
Ben Murdoch097c5b22016-05-18 11:27:45 +010065 init_function_index_(0),
Ben Murdoch61f157c2016-09-16 13:49:30 +010066 foreign_init_function_index_(0),
Ben Murdoch097c5b22016-05-18 11:27:45 +010067 next_table_index_(0),
Ben Murdoch61f157c2016-09-16 13:49:30 +010068 function_tables_(base::HashMap::PointersMatch,
Ben Murdoch097c5b22016-05-18 11:27:45 +010069 ZoneHashMap::kDefaultHashMapCapacity,
70 ZoneAllocationPolicy(zone)),
Ben Murdochc5610432016-08-08 18:44:38 +010071 imported_function_table_(this),
72 bounds_(typer->bounds()) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000073 InitializeAstVisitor(isolate);
74 }
75
76 void InitializeInitFunction() {
Ben Murdoch097c5b22016-05-18 11:27:45 +010077 init_function_index_ = builder_->AddFunction();
Ben Murdochc5610432016-08-08 18:44:38 +010078 FunctionSig::Builder b(zone(), 0, 0);
Ben Murdoch097c5b22016-05-18 11:27:45 +010079 current_function_builder_ = builder_->FunctionAt(init_function_index_);
Ben Murdochc5610432016-08-08 18:44:38 +010080 current_function_builder_->SetSignature(b.Build());
Ben Murdochda12d292016-06-02 14:46:10 +010081 builder_->MarkStartFunction(init_function_index_);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000082 current_function_builder_ = nullptr;
83 }
84
Ben Murdoch61f157c2016-09-16 13:49:30 +010085 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 Murdoch4a90d5f2016-03-22 12:00:34 +0000106 }
107
Ben Murdoch61f157c2016-09-16 13:49:30 +0100108 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 Murdoch4a90d5f2016-03-22 12:00:34 +0000117
Ben Murdoch61f157c2016-09-16 13:49:30 +0100118 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 Murdochc5610432016-08-08 18:44:38 +0100127 DCHECK_EQ(kModuleScope, scope_);
Ben Murdoch097c5b22016-05-18 11:27:45 +0100128 DCHECK_NULL(current_function_builder_);
Ben Murdochc5610432016-08-08 18:44:38 +0100129 uint32_t index = LookupOrInsertFunction(decl->proxy()->var());
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000130 current_function_builder_ = builder_->FunctionAt(index);
Ben Murdochc5610432016-08-08 18:44:38 +0100131 scope_ = kFuncScope;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000132 RECURSE(Visit(decl->fun()));
Ben Murdochc5610432016-08-08 18:44:38 +0100133 scope_ = kModuleScope;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000134 current_function_builder_ = nullptr;
135 local_variables_.Clear();
136 }
137
Ben Murdoch61f157c2016-09-16 13:49:30 +0100138 void VisitImportDeclaration(ImportDeclaration* decl) override {}
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000139
Ben Murdoch61f157c2016-09-16 13:49:30 +0100140 void VisitExportDeclaration(ExportDeclaration* decl) override {}
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000141
Ben Murdoch61f157c2016-09-16 13:49:30 +0100142 void VisitStatements(ZoneList<Statement*>* stmts) override {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000143 for (int i = 0; i < stmts->length(); ++i) {
144 Statement* stmt = stmts->at(i);
Ben Murdochc5610432016-08-08 18:44:38 +0100145 ExpressionStatement* e = stmt->AsExpressionStatement();
146 if (e != nullptr && e->expression()->IsUndefinedLiteral()) {
147 continue;
148 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000149 RECURSE(Visit(stmt));
150 if (stmt->IsJump()) break;
151 }
152 }
153
Ben Murdoch61f157c2016-09-16 13:49:30 +0100154 void VisitBlock(Block* stmt) override {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000155 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 Murdochc5610432016-08-08 18:44:38 +0100165 if (scope_ == kFuncScope) {
Ben Murdoch097c5b22016-05-18 11:27:45 +0100166 BlockVisitor visitor(this, stmt->AsBreakableStatement(), kExprBlock,
Ben Murdochc5610432016-08-08 18:44:38 +0100167 false);
Ben Murdoch097c5b22016-05-18 11:27:45 +0100168 RECURSE(VisitStatements(stmt->statements()));
Ben Murdoch097c5b22016-05-18 11:27:45 +0100169 } else {
170 RECURSE(VisitStatements(stmt->statements()));
171 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000172 }
173
174 class BlockVisitor {
175 private:
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000176 AsmWasmBuilderImpl* builder_;
177
178 public:
179 BlockVisitor(AsmWasmBuilderImpl* builder, BreakableStatement* stmt,
Ben Murdochc5610432016-08-08 18:44:38 +0100180 WasmOpcode opcode, bool is_loop)
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000181 : builder_(builder) {
182 builder_->breakable_blocks_.push_back(std::make_pair(stmt, is_loop));
183 builder_->current_function_builder_->Emit(opcode);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000184 }
185 ~BlockVisitor() {
Ben Murdochc5610432016-08-08 18:44:38 +0100186 builder_->current_function_builder_->Emit(kExprEnd);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000187 builder_->breakable_blocks_.pop_back();
188 }
189 };
190
Ben Murdoch61f157c2016-09-16 13:49:30 +0100191 void VisitExpressionStatement(ExpressionStatement* stmt) override {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000192 RECURSE(Visit(stmt->expression()));
193 }
194
Ben Murdoch61f157c2016-09-16 13:49:30 +0100195 void VisitEmptyStatement(EmptyStatement* stmt) override {}
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000196
Ben Murdoch61f157c2016-09-16 13:49:30 +0100197 void VisitEmptyParentheses(EmptyParentheses* paren) override {
198 UNREACHABLE();
199 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000200
Ben Murdoch61f157c2016-09-16 13:49:30 +0100201 void VisitIfStatement(IfStatement* stmt) override {
Ben Murdochc5610432016-08-08 18:44:38 +0100202 DCHECK_EQ(kFuncScope, scope_);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000203 RECURSE(Visit(stmt->condition()));
Ben Murdochc5610432016-08-08 18:44:38 +0100204 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 Murdoch4a90d5f2016-03-22 12:00:34 +0000207 if (stmt->HasThenStatement()) {
208 RECURSE(Visit(stmt->then_statement()));
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000209 }
210 if (stmt->HasElseStatement()) {
Ben Murdochc5610432016-08-08 18:44:38 +0100211 current_function_builder_->Emit(kExprElse);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000212 RECURSE(Visit(stmt->else_statement()));
213 }
Ben Murdochc5610432016-08-08 18:44:38 +0100214 current_function_builder_->Emit(kExprEnd);
215 breakable_blocks_.pop_back();
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000216 }
217
Ben Murdoch61f157c2016-09-16 13:49:30 +0100218 void VisitContinueStatement(ContinueStatement* stmt) override {
Ben Murdochc5610432016-08-08 18:44:38 +0100219 DCHECK_EQ(kFuncScope, scope_);
Ben Murdoch097c5b22016-05-18 11:27:45 +0100220 DCHECK_NOT_NULL(stmt->target());
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000221 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 Murdochc5610432016-08-08 18:44:38 +0100235 current_function_builder_->EmitWithU8(kExprBr, ARITY_0);
236 current_function_builder_->EmitVarInt(block_distance);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000237 }
238
Ben Murdoch61f157c2016-09-16 13:49:30 +0100239 void VisitBreakStatement(BreakStatement* stmt) override {
Ben Murdochc5610432016-08-08 18:44:38 +0100240 DCHECK_EQ(kFuncScope, scope_);
Ben Murdoch097c5b22016-05-18 11:27:45 +0100241 DCHECK_NOT_NULL(stmt->target());
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000242 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 Murdochc5610432016-08-08 18:44:38 +0100258 current_function_builder_->EmitWithU8(kExprBr, ARITY_0);
259 current_function_builder_->EmitVarInt(block_distance);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000260 }
261
Ben Murdoch61f157c2016-09-16 13:49:30 +0100262 void VisitReturnStatement(ReturnStatement* stmt) override {
Ben Murdochc5610432016-08-08 18:44:38 +0100263 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 Murdoch4a90d5f2016-03-22 12:00:34 +0000272 } else {
Ben Murdochc5610432016-08-08 18:44:38 +0100273 UNREACHABLE();
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000274 }
275 }
276
Ben Murdoch61f157c2016-09-16 13:49:30 +0100277 void VisitWithStatement(WithStatement* stmt) override { UNREACHABLE(); }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000278
Ben Murdochc5610432016-08-08 18:44:38 +0100279 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 Murdoch4a90d5f2016-03-22 12:00:34 +0000338
Ben Murdochc5610432016-08-08 18:44:38 +0100339 while (if_depth-- != prev_if_depth) {
340 breakable_blocks_.pop_back();
341 current_function_builder_->Emit(kExprEnd);
342 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000343 }
344
Ben Murdoch61f157c2016-09-16 13:49:30 +0100345 void VisitSwitchStatement(SwitchStatement* stmt) override {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000346 VariableProxy* tag = stmt->tag()->AsVariableProxy();
Ben Murdoch097c5b22016-05-18 11:27:45 +0100347 DCHECK_NOT_NULL(tag);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000348 ZoneList<CaseClause*>* clauses = stmt->cases();
Ben Murdochc5610432016-08-08 18:44:38 +0100349 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 Murdoch4a90d5f2016-03-22 12:00:34 +0000359 CaseClause* clause = clauses->at(i);
Ben Murdochc5610432016-08-08 18:44:38 +0100360 blocks.push_back(new BlockVisitor(this, nullptr, kExprBlock, false));
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000361 if (!clause->is_default()) {
Ben Murdochc5610432016-08-08 18:44:38 +0100362 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 Murdoch4a90d5f2016-03-22 12:00:34 +0000372 } else {
Ben Murdochc5610432016-08-08 18:44:38 +0100373 DCHECK_EQ(i, case_count - 1);
374 has_default = true;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000375 }
376 }
Ben Murdochc5610432016-08-08 18:44:38 +0100377 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 Murdoch61f157c2016-09-16 13:49:30 +0100388 for (int i = 0; i < case_count; ++i) {
Ben Murdochc5610432016-08-08 18:44:38 +0100389 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 Murdoch4a90d5f2016-03-22 12:00:34 +0000395 }
396
Ben Murdoch61f157c2016-09-16 13:49:30 +0100397 void VisitCaseClause(CaseClause* clause) override { UNREACHABLE(); }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000398
Ben Murdoch61f157c2016-09-16 13:49:30 +0100399 void VisitDoWhileStatement(DoWhileStatement* stmt) override {
Ben Murdochc5610432016-08-08 18:44:38 +0100400 DCHECK_EQ(kFuncScope, scope_);
401 BlockVisitor visitor(this, stmt->AsBreakableStatement(), kExprLoop, true);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000402 RECURSE(Visit(stmt->body()));
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000403 RECURSE(Visit(stmt->cond()));
Ben Murdochc5610432016-08-08 18:44:38 +0100404 current_function_builder_->Emit(kExprIf);
405 current_function_builder_->EmitWithU8U8(kExprBr, ARITY_0, 1);
406 current_function_builder_->Emit(kExprEnd);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000407 }
408
Ben Murdoch61f157c2016-09-16 13:49:30 +0100409 void VisitWhileStatement(WhileStatement* stmt) override {
Ben Murdochc5610432016-08-08 18:44:38 +0100410 DCHECK_EQ(kFuncScope, scope_);
411 BlockVisitor visitor(this, stmt->AsBreakableStatement(), kExprLoop, true);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000412 RECURSE(Visit(stmt->cond()));
Ben Murdochc5610432016-08-08 18:44:38 +0100413 breakable_blocks_.push_back(std::make_pair(nullptr, false));
414 current_function_builder_->Emit(kExprIf);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000415 RECURSE(Visit(stmt->body()));
Ben Murdochc5610432016-08-08 18:44:38 +0100416 current_function_builder_->EmitWithU8U8(kExprBr, ARITY_0, 1);
417 current_function_builder_->Emit(kExprEnd);
418 breakable_blocks_.pop_back();
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000419 }
420
Ben Murdoch61f157c2016-09-16 13:49:30 +0100421 void VisitForStatement(ForStatement* stmt) override {
Ben Murdochc5610432016-08-08 18:44:38 +0100422 DCHECK_EQ(kFuncScope, scope_);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000423 if (stmt->init() != nullptr) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000424 RECURSE(Visit(stmt->init()));
425 }
Ben Murdochc5610432016-08-08 18:44:38 +0100426 BlockVisitor visitor(this, stmt->AsBreakableStatement(), kExprLoop, true);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000427 if (stmt->cond() != nullptr) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000428 RECURSE(Visit(stmt->cond()));
Ben Murdochc5610432016-08-08 18:44:38 +0100429 current_function_builder_->Emit(kExprI32Eqz);
430 current_function_builder_->Emit(kExprIf);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000431 current_function_builder_->Emit(kExprNop);
Ben Murdochc5610432016-08-08 18:44:38 +0100432 current_function_builder_->EmitWithU8U8(kExprBr, ARITY_0, 2);
433 current_function_builder_->Emit(kExprEnd);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000434 }
435 if (stmt->body() != nullptr) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000436 RECURSE(Visit(stmt->body()));
437 }
438 if (stmt->next() != nullptr) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000439 RECURSE(Visit(stmt->next()));
440 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000441 current_function_builder_->Emit(kExprNop);
Ben Murdochc5610432016-08-08 18:44:38 +0100442 current_function_builder_->EmitWithU8U8(kExprBr, ARITY_0, 0);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000443 }
444
Ben Murdoch61f157c2016-09-16 13:49:30 +0100445 void VisitForInStatement(ForInStatement* stmt) override { UNREACHABLE(); }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000446
Ben Murdoch61f157c2016-09-16 13:49:30 +0100447 void VisitForOfStatement(ForOfStatement* stmt) override { UNREACHABLE(); }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000448
Ben Murdoch61f157c2016-09-16 13:49:30 +0100449 void VisitTryCatchStatement(TryCatchStatement* stmt) override {
450 UNREACHABLE();
451 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000452
Ben Murdoch61f157c2016-09-16 13:49:30 +0100453 void VisitTryFinallyStatement(TryFinallyStatement* stmt) override {
454 UNREACHABLE();
455 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000456
Ben Murdoch61f157c2016-09-16 13:49:30 +0100457 void VisitDebuggerStatement(DebuggerStatement* stmt) override {
458 UNREACHABLE();
459 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000460
Ben Murdoch61f157c2016-09-16 13:49:30 +0100461 void VisitFunctionLiteral(FunctionLiteral* expr) override {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000462 Scope* scope = expr->scope();
Ben Murdochc5610432016-08-08 18:44:38 +0100463 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 Murdoch4a90d5f2016-03-22 12:00:34 +0000467 LocalType return_type = TypeFrom(func_type->Result());
Ben Murdochc5610432016-08-08 18:44:38 +0100468 FunctionSig::Builder b(zone(), return_type == kAstStmt ? 0 : 1,
469 func_type->Arity());
470 if (return_type != kAstStmt) b.AddReturn(return_type);
Ben Murdoch61f157c2016-09-16 13:49:30 +0100471 for (int i = 0; i < expr->parameter_count(); ++i) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000472 LocalType type = TypeFrom(func_type->Parameter(i));
Ben Murdoch097c5b22016-05-18 11:27:45 +0100473 DCHECK_NE(kAstStmt, type);
Ben Murdochc5610432016-08-08 18:44:38 +0100474 b.AddParam(type);
475 InsertParameter(scope->parameter(i), type, i);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000476 }
Ben Murdochc5610432016-08-08 18:44:38 +0100477 current_function_builder_->SetSignature(b.Build());
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000478 } else {
479 UNREACHABLE();
480 }
481 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000482 RECURSE(VisitStatements(expr->body()));
Ben Murdoch097c5b22016-05-18 11:27:45 +0100483 RECURSE(VisitDeclarations(scope->declarations()));
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000484 }
485
Ben Murdoch61f157c2016-09-16 13:49:30 +0100486 void VisitNativeFunctionLiteral(NativeFunctionLiteral* expr) override {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000487 UNREACHABLE();
488 }
489
Ben Murdoch61f157c2016-09-16 13:49:30 +0100490 void VisitConditional(Conditional* expr) override {
Ben Murdochc5610432016-08-08 18:44:38 +0100491 DCHECK_EQ(kFuncScope, scope_);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000492 RECURSE(Visit(expr->condition()));
Ben Murdochc5610432016-08-08 18:44:38 +0100493 // 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 Murdoch4a90d5f2016-03-22 12:00:34 +0000496 RECURSE(Visit(expr->then_expression()));
Ben Murdochc5610432016-08-08 18:44:38 +0100497 current_function_builder_->Emit(kExprElse);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000498 RECURSE(Visit(expr->else_expression()));
Ben Murdochc5610432016-08-08 18:44:38 +0100499 current_function_builder_->Emit(kExprEnd);
500 breakable_blocks_.pop_back();
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000501 }
502
Ben Murdochda12d292016-06-02 14:46:10 +0100503 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 Murdoch61f157c2016-09-16 13:49:30 +0100555 void VisitVariableProxy(VariableProxy* expr) override {
Ben Murdochc5610432016-08-08 18:44:38 +0100556 if (scope_ == kFuncScope || scope_ == kInitScope) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000557 Variable* var = expr->var();
Ben Murdochc5610432016-08-08 18:44:38 +0100558 if (VisitStdlibConstant(var)) {
559 return;
Ben Murdoch097c5b22016-05-18 11:27:45 +0100560 }
561 LocalType var_type = TypeOf(expr);
562 DCHECK_NE(kAstStmt, var_type);
563 if (var->IsContextSlot()) {
Ben Murdochc5610432016-08-08 18:44:38 +0100564 current_function_builder_->EmitWithVarInt(
565 kExprLoadGlobal, LookupOrInsertGlobal(var, var_type));
Ben Murdoch097c5b22016-05-18 11:27:45 +0100566 } else {
Ben Murdochc5610432016-08-08 18:44:38 +0100567 current_function_builder_->EmitGetLocal(
568 LookupOrInsertLocal(var, var_type));
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000569 }
570 }
571 }
572
Ben Murdoch61f157c2016-09-16 13:49:30 +0100573 void VisitLiteral(Literal* expr) override {
Ben Murdochda12d292016-06-02 14:46:10 +0100574 Handle<Object> value = expr->value();
Ben Murdochc5610432016-08-08 18:44:38 +0100575 if (!value->IsNumber() || (scope_ != kFuncScope && scope_ != kInitScope)) {
Ben Murdochda12d292016-06-02 14:46:10 +0100576 return;
577 }
Ben Murdochc5610432016-08-08 18:44:38 +0100578 Type* type = bounds_->get(expr).upper;
Ben Murdochda12d292016-06-02 14:46:10 +0100579 if (type->Is(cache_.kAsmSigned)) {
580 int32_t i = 0;
581 if (!value->ToInt32(&i)) {
582 UNREACHABLE();
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000583 }
Ben Murdochda12d292016-06-02 14:46:10 +0100584 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 Murdoch4a90d5f2016-03-22 12:00:34 +0000600 }
601 }
602
Ben Murdoch61f157c2016-09-16 13:49:30 +0100603 void VisitRegExpLiteral(RegExpLiteral* expr) override { UNREACHABLE(); }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000604
Ben Murdoch61f157c2016-09-16 13:49:30 +0100605 void VisitObjectLiteral(ObjectLiteral* expr) override {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000606 ZoneList<ObjectLiteralProperty*>* props = expr->properties();
607 for (int i = 0; i < props->length(); ++i) {
608 ObjectLiteralProperty* prop = props->at(i);
Ben Murdochc5610432016-08-08 18:44:38 +0100609 DCHECK_EQ(kExportScope, scope_);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000610 VariableProxy* expr = prop->value()->AsVariableProxy();
Ben Murdoch097c5b22016-05-18 11:27:45 +0100611 DCHECK_NOT_NULL(expr);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000612 Variable* var = expr->var();
613 Literal* name = prop->key()->AsLiteral();
Ben Murdoch097c5b22016-05-18 11:27:45 +0100614 DCHECK_NOT_NULL(name);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000615 DCHECK(name->IsPropertyName());
616 const AstRawString* raw_name = name->AsRawPropertyName();
617 if (var->is_function()) {
Ben Murdochc5610432016-08-08 18:44:38 +0100618 uint32_t index = LookupOrInsertFunction(var);
Ben Murdoch61f157c2016-09-16 13:49:30 +0100619 builder_->FunctionAt(index)->SetExported();
Ben Murdochc5610432016-08-08 18:44:38 +0100620 builder_->FunctionAt(index)->SetName(
621 reinterpret_cast<const char*>(raw_name->raw_data()),
622 raw_name->length());
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000623 }
624 }
625 }
626
Ben Murdoch61f157c2016-09-16 13:49:30 +0100627 void VisitArrayLiteral(ArrayLiteral* expr) override { UNREACHABLE(); }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000628
629 void LoadInitFunction() {
Ben Murdoch097c5b22016-05-18 11:27:45 +0100630 current_function_builder_ = builder_->FunctionAt(init_function_index_);
Ben Murdochc5610432016-08-08 18:44:38 +0100631 scope_ = kInitScope;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000632 }
633
634 void UnLoadInitFunction() {
Ben Murdochc5610432016-08-08 18:44:38 +0100635 scope_ = kModuleScope;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000636 current_function_builder_ = nullptr;
637 }
638
Ben Murdoch097c5b22016-05-18 11:27:45 +0100639 void AddFunctionTable(VariableProxy* table, ArrayLiteral* funcs) {
640 FunctionType* func_type =
Ben Murdochc5610432016-08-08 18:44:38 +0100641 bounds_->get(funcs).lower->AsArray()->Element()->AsFunction();
Ben Murdoch097c5b22016-05-18 11:27:45 +0100642 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 Murdoch61f157c2016-09-16 13:49:30 +0100648 for (int i = 0; i < func_type->Arity(); ++i) {
Ben Murdoch097c5b22016-05-18 11:27:45 +0100649 sig.AddParam(TypeFrom(func_type->Parameter(i)));
650 }
Ben Murdochc5610432016-08-08 18:44:38 +0100651 uint32_t signature_index = builder_->AddSignature(sig.Build());
Ben Murdoch097c5b22016-05-18 11:27:45 +0100652 InsertFunctionTable(table->var(), next_table_index_, signature_index);
653 next_table_index_ += funcs->values()->length();
Ben Murdoch61f157c2016-09-16 13:49:30 +0100654 for (int i = 0; i < funcs->values()->length(); ++i) {
Ben Murdoch097c5b22016-05-18 11:27:45 +0100655 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 Murdochc5610432016-08-08 18:44:38 +0100663 uint32_t signature_index;
Ben Murdoch097c5b22016-05-18 11:27:45 +0100664 };
665
666 void InsertFunctionTable(Variable* v, uint32_t start_index,
Ben Murdochc5610432016-08-08 18:44:38 +0100667 uint32_t signature_index) {
Ben Murdoch097c5b22016-05-18 11:27:45 +0100668 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 Murdochc5610432016-08-08 18:44:38 +0100687 const char* name_;
Ben Murdoch097c5b22016-05-18 11:27:45 +0100688 int name_length_;
689 WasmModuleBuilder::SignatureMap signature_to_index_;
690
Ben Murdochc5610432016-08-08 18:44:38 +0100691 ImportedFunctionIndices(const char* name, int name_length, Zone* zone)
Ben Murdoch097c5b22016-05-18 11:27:45 +0100692 : 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 Murdoch61f157c2016-09-16 13:49:30 +0100699 : table_(base::HashMap::PointersMatch,
700 ZoneHashMap::kDefaultHashMapCapacity,
Ben Murdoch097c5b22016-05-18 11:27:45 +0100701 ZoneAllocationPolicy(builder->zone())),
702 builder_(builder) {}
703
Ben Murdochc5610432016-08-08 18:44:38 +0100704 void AddImport(Variable* v, const char* name, int name_length) {
Ben Murdoch097c5b22016-05-18 11:27:45 +0100705 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 Murdochc5610432016-08-08 18:44:38 +0100712 uint32_t GetFunctionIndex(Variable* v, FunctionSig* sig) {
Ben Murdoch097c5b22016-05-18 11:27:45 +0100713 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 Murdochc5610432016-08-08 18:44:38 +0100722 uint32_t index = builder_->builder_->AddImport(
723 indices->name_, indices->name_length_, sig);
Ben Murdoch097c5b22016-05-18 11:27:45 +0100724 indices->signature_to_index_[sig] = index;
Ben Murdoch097c5b22016-05-18 11:27:45 +0100725 return index;
726 }
727 }
728 };
729
Ben Murdochc5610432016-08-08 18:44:38 +0100730 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 Murdoch097c5b22016-05-18 11:27:45 +0100755 Property* prop = binop->left()->AsProperty();
Ben Murdoch097c5b22016-05-18 11:27:45 +0100756 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 Murdoch61f157c2016-09-16 13:49:30 +0100760 DCHECK(target->IsVariableProxy());
761 VisitForeignVariable(true, target->AsVariableProxy()->var(), prop);
762 *is_nop = true;
Ben Murdochc5610432016-08-08 18:44:38 +0100763 return;
Ben Murdoch097c5b22016-05-18 11:27:45 +0100764 } 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 Murdoch61f157c2016-09-16 13:49:30 +0100768 DCHECK(target->IsVariableProxy());
769 VisitForeignVariable(false, target->AsVariableProxy()->var(), prop);
770 *is_nop = true;
Ben Murdochc5610432016-08-08 18:44:38 +0100771 return;
Ben Murdoch097c5b22016-05-18 11:27:45 +0100772 } else {
773 UNREACHABLE();
774 }
Ben Murdoch097c5b22016-05-18 11:27:45 +0100775 }
Ben Murdochc5610432016-08-08 18:44:38 +0100776 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 Murdoch61f157c2016-09-16 13:49:30 +0100842 void VisitAssignment(Assignment* expr) override {
Ben Murdochc5610432016-08-08 18:44:38 +0100843 bool as_init = false;
844 if (scope_ == kModuleScope) {
Ben Murdochda12d292016-06-02 14:46:10 +0100845 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 Murdochc5610432016-08-08 18:44:38 +0100851 if (bounds_->get(target).lower->Is(Type::Function())) {
Ben Murdochda12d292016-06-02 14:46:10 +0100852 const AstRawString* name =
853 prop->key()->AsLiteral()->AsRawPropertyName();
Ben Murdochc5610432016-08-08 18:44:38 +0100854 imported_function_table_.AddImport(
855 target->var(), reinterpret_cast<const char*>(name->raw_data()),
856 name->length());
Ben Murdoch097c5b22016-05-18 11:27:45 +0100857 }
858 }
Ben Murdochda12d292016-06-02 14:46:10 +0100859 // 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 Murdochc5610432016-08-08 18:44:38 +0100864 bounds_->get(funcs).lower->AsArray()->Element()->IsFunction()) {
Ben Murdochda12d292016-06-02 14:46:10 +0100865 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 Murdoch4a90d5f2016-03-22 12:00:34 +0000873 return;
874 }
Ben Murdochc5610432016-08-08 18:44:38 +0100875 as_init = true;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000876 }
Ben Murdochc5610432016-08-08 18:44:38 +0100877
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 Murdoch4a90d5f2016-03-22 12:00:34 +0000885 }
Ben Murdochc5610432016-08-08 18:44:38 +0100886 if (as_init) UnLoadInitFunction();
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000887 }
888
Ben Murdoch61f157c2016-09-16 13:49:30 +0100889 void VisitYield(Yield* expr) override { UNREACHABLE(); }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000890
Ben Murdoch61f157c2016-09-16 13:49:30 +0100891 void VisitThrow(Throw* expr) override { UNREACHABLE(); }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000892
Ben Murdoch61f157c2016-09-16 13:49:30 +0100893 void VisitForeignVariable(bool is_float, Variable* var, Property* expr) {
Ben Murdoch097c5b22016-05-18 11:27:45 +0100894 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 Murdoch61f157c2016-09-16 13:49:30 +0100900 if (!key_literal->value().is_null()) {
Ben Murdoch097c5b22016-05-18 11:27:45 +0100901 Handle<Name> name =
902 i::Object::ToName(isolate_, key_literal->value()).ToHandleChecked();
Ben Murdoch61f157c2016-09-16 13:49:30 +0100903 LocalType type = is_float ? kAstF64 : kAstI32;
904 foreign_variables_.push_back({name, var, type});
Ben Murdoch097c5b22016-05-18 11:27:45 +0100905 }
906 }
907
Ben Murdochc5610432016-08-08 18:44:38 +0100908 void VisitPropertyAndEmitIndex(Property* expr, MachineType* mtype) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000909 Expression* obj = expr->obj();
Ben Murdochc5610432016-08-08 18:44:38 +0100910 DCHECK_EQ(bounds_->get(obj).lower, bounds_->get(obj).upper);
911 Type* type = bounds_->get(obj).lower;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000912 int size;
913 if (type->Is(cache_.kUint8Array)) {
Ben Murdochc5610432016-08-08 18:44:38 +0100914 *mtype = MachineType::Uint8();
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000915 size = 1;
916 } else if (type->Is(cache_.kInt8Array)) {
Ben Murdochc5610432016-08-08 18:44:38 +0100917 *mtype = MachineType::Int8();
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000918 size = 1;
919 } else if (type->Is(cache_.kUint16Array)) {
Ben Murdochc5610432016-08-08 18:44:38 +0100920 *mtype = MachineType::Uint16();
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000921 size = 2;
922 } else if (type->Is(cache_.kInt16Array)) {
Ben Murdochc5610432016-08-08 18:44:38 +0100923 *mtype = MachineType::Int16();
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000924 size = 2;
925 } else if (type->Is(cache_.kUint32Array)) {
Ben Murdochc5610432016-08-08 18:44:38 +0100926 *mtype = MachineType::Uint32();
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000927 size = 4;
928 } else if (type->Is(cache_.kInt32Array)) {
Ben Murdochc5610432016-08-08 18:44:38 +0100929 *mtype = MachineType::Int32();
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000930 size = 4;
931 } else if (type->Is(cache_.kUint32Array)) {
Ben Murdochc5610432016-08-08 18:44:38 +0100932 *mtype = MachineType::Uint32();
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000933 size = 4;
934 } else if (type->Is(cache_.kFloat32Array)) {
Ben Murdochc5610432016-08-08 18:44:38 +0100935 *mtype = MachineType::Float32();
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000936 size = 4;
937 } else if (type->Is(cache_.kFloat64Array)) {
Ben Murdochc5610432016-08-08 18:44:38 +0100938 *mtype = MachineType::Float64();
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000939 size = 8;
940 } else {
941 UNREACHABLE();
942 }
Ben Murdoch097c5b22016-05-18 11:27:45 +0100943 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 Murdoch4a90d5f2016-03-22 12:00:34 +0000949 return;
Ben Murdochc5610432016-08-08 18:44:38 +0100950 }
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 Murdoch4a90d5f2016-03-22 12:00:34 +0000975 }
976 UNREACHABLE();
977 }
978
Ben Murdoch61f157c2016-09-16 13:49:30 +0100979 void VisitProperty(Property* expr) override {
Ben Murdochc5610432016-08-08 18:44:38 +0100980 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 Murdochda12d292016-06-02 14:46:10 +01001006 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 Murdochc5610432016-08-08 18:44:38 +01001012
Ben Murdochda12d292016-06-02 14:46:10 +01001013 switch (standard_object) {
1014 case AsmTyper::kNone: {
1015 return false;
1016 }
1017 case AsmTyper::kMathAcos: {
Ben Murdochc5610432016-08-08 18:44:38 +01001018 VisitCallArgs(call);
Ben Murdochda12d292016-06-02 14:46:10 +01001019 DCHECK_EQ(kAstF64, call_type);
1020 current_function_builder_->Emit(kExprF64Acos);
1021 break;
1022 }
1023 case AsmTyper::kMathAsin: {
Ben Murdochc5610432016-08-08 18:44:38 +01001024 VisitCallArgs(call);
Ben Murdochda12d292016-06-02 14:46:10 +01001025 DCHECK_EQ(kAstF64, call_type);
1026 current_function_builder_->Emit(kExprF64Asin);
1027 break;
1028 }
1029 case AsmTyper::kMathAtan: {
Ben Murdochc5610432016-08-08 18:44:38 +01001030 VisitCallArgs(call);
Ben Murdochda12d292016-06-02 14:46:10 +01001031 DCHECK_EQ(kAstF64, call_type);
1032 current_function_builder_->Emit(kExprF64Atan);
1033 break;
1034 }
1035 case AsmTyper::kMathCos: {
Ben Murdochc5610432016-08-08 18:44:38 +01001036 VisitCallArgs(call);
Ben Murdochda12d292016-06-02 14:46:10 +01001037 DCHECK_EQ(kAstF64, call_type);
1038 current_function_builder_->Emit(kExprF64Cos);
1039 break;
1040 }
1041 case AsmTyper::kMathSin: {
Ben Murdochc5610432016-08-08 18:44:38 +01001042 VisitCallArgs(call);
Ben Murdochda12d292016-06-02 14:46:10 +01001043 DCHECK_EQ(kAstF64, call_type);
1044 current_function_builder_->Emit(kExprF64Sin);
1045 break;
1046 }
1047 case AsmTyper::kMathTan: {
Ben Murdochc5610432016-08-08 18:44:38 +01001048 VisitCallArgs(call);
Ben Murdochda12d292016-06-02 14:46:10 +01001049 DCHECK_EQ(kAstF64, call_type);
1050 current_function_builder_->Emit(kExprF64Tan);
1051 break;
1052 }
1053 case AsmTyper::kMathExp: {
Ben Murdochc5610432016-08-08 18:44:38 +01001054 VisitCallArgs(call);
Ben Murdochda12d292016-06-02 14:46:10 +01001055 DCHECK_EQ(kAstF64, call_type);
1056 current_function_builder_->Emit(kExprF64Exp);
1057 break;
1058 }
1059 case AsmTyper::kMathLog: {
Ben Murdochc5610432016-08-08 18:44:38 +01001060 VisitCallArgs(call);
Ben Murdochda12d292016-06-02 14:46:10 +01001061 DCHECK_EQ(kAstF64, call_type);
1062 current_function_builder_->Emit(kExprF64Log);
1063 break;
1064 }
1065 case AsmTyper::kMathCeil: {
Ben Murdochc5610432016-08-08 18:44:38 +01001066 VisitCallArgs(call);
Ben Murdochda12d292016-06-02 14:46:10 +01001067 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 Murdochc5610432016-08-08 18:44:38 +01001077 VisitCallArgs(call);
Ben Murdochda12d292016-06-02 14:46:10 +01001078 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 Murdochc5610432016-08-08 18:44:38 +01001088 VisitCallArgs(call);
Ben Murdochda12d292016-06-02 14:46:10 +01001089 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 Murdochda12d292016-06-02 14:46:10 +01001099 if (call_type == kAstI32) {
Ben Murdochc5610432016-08-08 18:44:38 +01001100 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 Murdochda12d292016-06-02 14:46:10 +01001105 byte code[] = {WASM_I8(0)};
1106 current_function_builder_->EmitCode(code, sizeof(code));
Ben Murdochc5610432016-08-08 18:44:38 +01001107 current_function_builder_->Emit(kExprI32LtS);
1108 current_function_builder_->Emit(kExprIf);
1109
1110 // then (0 - tmp)
Ben Murdochda12d292016-06-02 14:46:10 +01001111 current_function_builder_->EmitCode(code, sizeof(code));
Ben Murdochc5610432016-08-08 18:44:38 +01001112 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 Murdochda12d292016-06-02 14:46:10 +01001121 } else if (call_type == kAstF32) {
Ben Murdochc5610432016-08-08 18:44:38 +01001122 VisitCallArgs(call);
Ben Murdochda12d292016-06-02 14:46:10 +01001123 current_function_builder_->Emit(kExprF32Abs);
1124 } else if (call_type == kAstF64) {
Ben Murdochc5610432016-08-08 18:44:38 +01001125 VisitCallArgs(call);
Ben Murdochda12d292016-06-02 14:46:10 +01001126 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 Murdochc5610432016-08-08 18:44:38 +01001135 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 Murdochda12d292016-06-02 14:46:10 +01001145 current_function_builder_->Emit(kExprI32LeS);
Ben Murdochc5610432016-08-08 18:44:38 +01001146 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 Murdochda12d292016-06-02 14:46:10 +01001156 } else if (call_type == kAstF32) {
Ben Murdochc5610432016-08-08 18:44:38 +01001157 VisitCallArgs(call);
Ben Murdochda12d292016-06-02 14:46:10 +01001158 current_function_builder_->Emit(kExprF32Min);
1159 } else if (call_type == kAstF64) {
Ben Murdochc5610432016-08-08 18:44:38 +01001160 VisitCallArgs(call);
Ben Murdochda12d292016-06-02 14:46:10 +01001161 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 Murdochc5610432016-08-08 18:44:38 +01001170 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 Murdochda12d292016-06-02 14:46:10 +01001192 } else if (call_type == kAstF32) {
Ben Murdochc5610432016-08-08 18:44:38 +01001193 VisitCallArgs(call);
Ben Murdochda12d292016-06-02 14:46:10 +01001194 current_function_builder_->Emit(kExprF32Max);
1195 } else if (call_type == kAstF64) {
Ben Murdochc5610432016-08-08 18:44:38 +01001196 VisitCallArgs(call);
Ben Murdochda12d292016-06-02 14:46:10 +01001197 current_function_builder_->Emit(kExprF64Max);
1198 } else {
1199 UNREACHABLE();
1200 }
1201 break;
1202 }
1203 case AsmTyper::kMathAtan2: {
Ben Murdochc5610432016-08-08 18:44:38 +01001204 VisitCallArgs(call);
Ben Murdochda12d292016-06-02 14:46:10 +01001205 DCHECK_EQ(kAstF64, call_type);
1206 current_function_builder_->Emit(kExprF64Atan2);
1207 break;
1208 }
1209 case AsmTyper::kMathPow: {
Ben Murdochc5610432016-08-08 18:44:38 +01001210 VisitCallArgs(call);
Ben Murdochda12d292016-06-02 14:46:10 +01001211 DCHECK_EQ(kAstF64, call_type);
1212 current_function_builder_->Emit(kExprF64Pow);
1213 break;
1214 }
1215 case AsmTyper::kMathImul: {
Ben Murdochc5610432016-08-08 18:44:38 +01001216 VisitCallArgs(call);
Ben Murdochda12d292016-06-02 14:46:10 +01001217 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 Murdochc5610432016-08-08 18:44:38 +01001224 // constant fold Math.fround(#const);
Ben Murdochda12d292016-06-02 14:46:10 +01001225 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 Murdochc5610432016-08-08 18:44:38 +01001232 VisitCallArgs(call);
Ben Murdochda12d292016-06-02 14:46:10 +01001233 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 Murdochda12d292016-06-02 14:46:10 +01001256 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 Murdoch61f157c2016-09-16 13:49:30 +01001267 void VisitCall(Call* expr) override {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001268 Call::CallType call_type = expr->GetCallType(isolate_);
1269 switch (call_type) {
1270 case Call::OTHER_CALL: {
Ben Murdochc5610432016-08-08 18:44:38 +01001271 DCHECK_EQ(kFuncScope, scope_);
Ben Murdochda12d292016-06-02 14:46:10 +01001272 VariableProxy* proxy = expr->expression()->AsVariableProxy();
1273 if (proxy != nullptr) {
1274 if (VisitStdlibFunction(expr, proxy)) {
1275 return;
1276 }
1277 }
Ben Murdochc5610432016-08-08 18:44:38 +01001278 uint32_t index;
Ben Murdoch097c5b22016-05-18 11:27:45 +01001279 VariableProxy* vp = expr->expression()->AsVariableProxy();
1280 if (vp != nullptr &&
Ben Murdochc5610432016-08-08 18:44:38 +01001281 Type::Any()->Is(bounds_->get(vp).lower->AsFunction()->Result())) {
Ben Murdoch097c5b22016-05-18 11:27:45 +01001282 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 Murdoch61f157c2016-09-16 13:49:30 +01001289 for (int i = 0; i < args->length(); ++i) {
Ben Murdoch097c5b22016-05-18 11:27:45 +01001290 sig.AddParam(TypeOf(args->at(i)));
1291 }
1292 index =
1293 imported_function_table_.GetFunctionIndex(vp->var(), sig.Build());
Ben Murdochc5610432016-08-08 18:44:38 +01001294 VisitCallArgs(expr);
1295 current_function_builder_->Emit(kExprCallImport);
1296 current_function_builder_->EmitVarInt(expr->arguments()->length());
1297 current_function_builder_->EmitVarInt(index);
Ben Murdoch097c5b22016-05-18 11:27:45 +01001298 } else {
1299 index = LookupOrInsertFunction(vp->var());
Ben Murdochc5610432016-08-08 18:44:38 +01001300 VisitCallArgs(expr);
1301 current_function_builder_->Emit(kExprCallFunction);
1302 current_function_builder_->EmitVarInt(expr->arguments()->length());
1303 current_function_builder_->EmitVarInt(index);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001304 }
Ben Murdoch097c5b22016-05-18 11:27:45 +01001305 break;
1306 }
1307 case Call::KEYED_PROPERTY_CALL: {
Ben Murdochc5610432016-08-08 18:44:38 +01001308 DCHECK_EQ(kFuncScope, scope_);
Ben Murdoch097c5b22016-05-18 11:27:45 +01001309 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 Murdoch097c5b22016-05-18 11:27:45 +01001314 RECURSE(Visit(p->key()));
Ben Murdochc5610432016-08-08 18:44:38 +01001315 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 Murdoch4a90d5f2016-03-22 12:00:34 +00001321 break;
1322 }
1323 default:
1324 UNREACHABLE();
1325 }
1326 }
1327
Ben Murdoch61f157c2016-09-16 13:49:30 +01001328 void VisitCallNew(CallNew* expr) override { UNREACHABLE(); }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001329
Ben Murdoch61f157c2016-09-16 13:49:30 +01001330 void VisitCallRuntime(CallRuntime* expr) override { UNREACHABLE(); }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001331
Ben Murdoch61f157c2016-09-16 13:49:30 +01001332 void VisitUnaryOperation(UnaryOperation* expr) override {
Ben Murdochc5610432016-08-08 18:44:38 +01001333 RECURSE(Visit(expr->expression()));
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001334 switch (expr->op()) {
1335 case Token::NOT: {
Ben Murdoch097c5b22016-05-18 11:27:45 +01001336 DCHECK_EQ(kAstI32, TypeOf(expr->expression()));
Ben Murdochda12d292016-06-02 14:46:10 +01001337 current_function_builder_->Emit(kExprI32Eqz);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001338 break;
1339 }
1340 default:
1341 UNREACHABLE();
1342 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001343 }
1344
Ben Murdoch61f157c2016-09-16 13:49:30 +01001345 void VisitCountOperation(CountOperation* expr) override { UNREACHABLE(); }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001346
1347 bool MatchIntBinaryOperation(BinaryOperation* expr, Token::Value op,
1348 int32_t val) {
Ben Murdoch097c5b22016-05-18 11:27:45 +01001349 DCHECK_NOT_NULL(expr->right());
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001350 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 Murdoch097c5b22016-05-18 11:27:45 +01001363 DCHECK_NOT_NULL(expr->right());
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001364 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 Murdoch097c5b22016-05-18 11:27:45 +01001378 if (MatchIntBinaryOperation(expr, Token::BIT_OR, 0) &&
1379 (TypeOf(expr->left()) == kAstI32)) {
1380 return kAsIs;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001381 } 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 Murdoch097c5b22016-05-18 11:27:45 +01001397 DCHECK_EQ(kAstI32, TypeOf(expr->left()));
1398 DCHECK_EQ(kAstI32, TypeOf(expr->right()));
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001399 BinaryOperation* op = expr->left()->AsBinaryOperation();
1400 if (op != nullptr) {
1401 if (MatchIntBinaryOperation(op, Token::BIT_XOR, 0xffffffff)) {
Ben Murdoch097c5b22016-05-18 11:27:45 +01001402 DCHECK_EQ(kAstI32, TypeOf(op->right()));
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001403 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 Murdoch097c5b22016-05-18 11:27:45 +01001416 DCHECK_EQ(kAstF64, TypeOf(expr->right()));
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001417 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 Murdoch4a90d5f2016-03-22 12:00:34 +00001446
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 Murdoch61f157c2016-09-16 13:49:30 +01001482 void VisitBinaryOperation(BinaryOperation* expr) override {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001483 ConvertOperation convertOperation = MatchBinaryOperation(expr);
1484 if (convertOperation == kToDouble) {
Ben Murdochc5610432016-08-08 18:44:38 +01001485 RECURSE(Visit(expr->left()));
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001486 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 Murdoch4a90d5f2016-03-22 12:00:34 +00001496 } else if (convertOperation == kToInt) {
Ben Murdochc5610432016-08-08 18:44:38 +01001497 RECURSE(Visit(GetLeft(expr)));
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001498 TypeIndex type = TypeIndexOf(GetLeft(expr));
1499 if (type == kFloat32) {
Ben Murdochc5610432016-08-08 18:44:38 +01001500 current_function_builder_->Emit(kExprI32AsmjsSConvertF32);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001501 } else if (type == kFloat64) {
Ben Murdochc5610432016-08-08 18:44:38 +01001502 current_function_builder_->Emit(kExprI32AsmjsSConvertF64);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001503 } else {
1504 UNREACHABLE();
1505 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001506 } else if (convertOperation == kAsIs) {
1507 RECURSE(Visit(GetLeft(expr)));
1508 } else {
Ben Murdochc5610432016-08-08 18:44:38 +01001509 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 Murdoch4a90d5f2016-03-22 12:00:34 +00001520 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 Murdoch4a90d5f2016-03-22 12:00:34 +00001524 BINOP_CASE(Token::BIT_OR, Ior, NON_SIGNED_INT_BINOP, true);
Ben Murdoch097c5b22016-05-18 11:27:45 +01001525 BINOP_CASE(Token::BIT_AND, And, NON_SIGNED_INT_BINOP, true);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001526 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 Murdochc5610432016-08-08 18:44:38 +01001530 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 Murdoch4a90d5f2016-03-22 12:00:34 +00001537 case Token::MOD: {
1538 TypeIndex type = TypeIndexOf(expr->left(), expr->right(), false);
1539 if (type == kInt32) {
Ben Murdochc5610432016-08-08 18:44:38 +01001540 current_function_builder_->Emit(kExprI32AsmjsRemS);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001541 } else if (type == kUint32) {
Ben Murdochc5610432016-08-08 18:44:38 +01001542 current_function_builder_->Emit(kExprI32AsmjsRemU);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001543 } else if (type == kFloat64) {
Ben Murdochda12d292016-06-02 14:46:10 +01001544 current_function_builder_->Emit(kExprF64Mod);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001545 return;
1546 } else {
1547 UNREACHABLE();
1548 }
1549 break;
1550 }
Ben Murdoch097c5b22016-05-18 11:27:45 +01001551 case Token::COMMA: {
Ben Murdoch097c5b22016-05-18 11:27:45 +01001552 break;
1553 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001554 default:
1555 UNREACHABLE();
1556 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001557 }
1558 }
1559
Ben Murdoch61f157c2016-09-16 13:49:30 +01001560 void VisitCompareOperation(CompareOperation* expr) override {
Ben Murdochc5610432016-08-08 18:44:38 +01001561 RECURSE(Visit(expr->left()));
1562 RECURSE(Visit(expr->right()));
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001563 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 Murdoch4a90d5f2016-03-22 12:00:34 +00001572 }
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 Murdochc5610432016-08-08 18:44:38 +01001606 DCHECK_EQ(bounds_->get(expr).lower, bounds_->get(expr).upper);
1607 Type* type = bounds_->get(expr).lower;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001608 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 Murdoch61f157c2016-09-16 13:49:30 +01001631 void VisitThisFunction(ThisFunction* expr) override { UNREACHABLE(); }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001632
Ben Murdoch61f157c2016-09-16 13:49:30 +01001633 void VisitDeclarations(ZoneList<Declaration*>* decls) override {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001634 for (int i = 0; i < decls->length(); ++i) {
1635 Declaration* decl = decls->at(i);
1636 RECURSE(Visit(decl));
1637 }
1638 }
1639
Ben Murdoch61f157c2016-09-16 13:49:30 +01001640 void VisitClassLiteral(ClassLiteral* expr) override { UNREACHABLE(); }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001641
Ben Murdoch61f157c2016-09-16 13:49:30 +01001642 void VisitSpread(Spread* expr) override { UNREACHABLE(); }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001643
Ben Murdoch61f157c2016-09-16 13:49:30 +01001644 void VisitSuperPropertyReference(SuperPropertyReference* expr) override {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001645 UNREACHABLE();
1646 }
1647
Ben Murdoch61f157c2016-09-16 13:49:30 +01001648 void VisitSuperCallReference(SuperCallReference* expr) override {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001649 UNREACHABLE();
1650 }
1651
Ben Murdoch61f157c2016-09-16 13:49:30 +01001652 void VisitSloppyBlockFunctionStatement(
1653 SloppyBlockFunctionStatement* expr) override {
1654 UNREACHABLE();
1655 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001656
Ben Murdoch61f157c2016-09-16 13:49:30 +01001657 void VisitDoExpression(DoExpression* expr) override { UNREACHABLE(); }
1658
1659 void VisitRewritableExpression(RewritableExpression* expr) override {
1660 UNREACHABLE();
1661 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001662
1663 struct IndexContainer : public ZoneObject {
Ben Murdochc5610432016-08-08 18:44:38 +01001664 uint32_t index;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001665 };
1666
Ben Murdochc5610432016-08-08 18:44:38 +01001667 uint32_t LookupOrInsertLocal(Variable* v, LocalType type) {
Ben Murdoch097c5b22016-05-18 11:27:45 +01001668 DCHECK_NOT_NULL(current_function_builder_);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001669 ZoneHashMap::Entry* entry =
1670 local_variables_.Lookup(v, ComputePointerHash(v));
1671 if (entry == nullptr) {
Ben Murdochc5610432016-08-08 18:44:38 +01001672 uint32_t index;
1673 DCHECK(!v->IsParameter());
1674 index = current_function_builder_->AddLocal(type);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001675 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 Murdochc5610432016-08-08 18:44:38 +01001684 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 Murdoch4a90d5f2016-03-22 12:00:34 +00001698 ZoneHashMap::Entry* entry =
1699 global_variables_.Lookup(v, ComputePointerHash(v));
1700 if (entry == nullptr) {
Ben Murdochc5610432016-08-08 18:44:38 +01001701 uint32_t index =
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001702 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 Murdochc5610432016-08-08 18:44:38 +01001712 uint32_t LookupOrInsertFunction(Variable* v) {
Ben Murdoch097c5b22016-05-18 11:27:45 +01001713 DCHECK_NOT_NULL(builder_);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001714 ZoneHashMap::Entry* entry = functions_.Lookup(v, ComputePointerHash(v));
1715 if (entry == nullptr) {
Ben Murdochc5610432016-08-08 18:44:38 +01001716 uint32_t index = builder_->AddFunction();
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001717 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 Murdochc5610432016-08-08 18:44:38 +01001727 DCHECK_EQ(bounds_->get(expr).lower, bounds_->get(expr).upper);
1728 return TypeFrom(bounds_->get(expr).lower);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001729 }
1730
Ben Murdoch097c5b22016-05-18 11:27:45 +01001731 LocalType TypeFrom(Type* type) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001732 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 Murdochc5610432016-08-08 18:44:38 +01001748 AsmScope scope_;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001749 WasmModuleBuilder* builder_;
1750 WasmFunctionBuilder* current_function_builder_;
1751 FunctionLiteral* literal_;
1752 Isolate* isolate_;
1753 Zone* zone_;
Ben Murdochda12d292016-06-02 14:46:10 +01001754 AsmTyper* typer_;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001755 TypeCache const& cache_;
1756 ZoneVector<std::pair<BreakableStatement*, bool>> breakable_blocks_;
Ben Murdoch61f157c2016-09-16 13:49:30 +01001757 ZoneVector<ForeignVariable> foreign_variables_;
Ben Murdochc5610432016-08-08 18:44:38 +01001758 uint32_t init_function_index_;
Ben Murdoch61f157c2016-09-16 13:49:30 +01001759 uint32_t foreign_init_function_index_;
Ben Murdoch097c5b22016-05-18 11:27:45 +01001760 uint32_t next_table_index_;
1761 ZoneHashMap function_tables_;
1762 ImportedFunctionTable imported_function_table_;
Ben Murdochc5610432016-08-08 18:44:38 +01001763 const AstTypeBounds* bounds_;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001764
1765 DEFINE_AST_VISITOR_SUBCLASS_MEMBERS();
1766
1767 private:
1768 DISALLOW_COPY_AND_ASSIGN(AsmWasmBuilderImpl);
1769};
1770
1771AsmWasmBuilder::AsmWasmBuilder(Isolate* isolate, Zone* zone,
Ben Murdoch61f157c2016-09-16 13:49:30 +01001772 FunctionLiteral* literal, AsmTyper* typer)
1773 : isolate_(isolate), zone_(zone), literal_(literal), typer_(typer) {}
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001774
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 Murdoch61f157c2016-09-16 13:49:30 +01001777ZoneBuffer* 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 Murdoch4a90d5f2016-03-22 12:00:34 +00001784}
1785} // namespace wasm
1786} // namespace internal
1787} // namespace v8