blob: 325058c6db116d509108839fcf704e9900b03062 [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
36class AsmWasmBuilderImpl : public AstVisitor {
37 public:
Ben Murdoch097c5b22016-05-18 11:27:45 +010038 AsmWasmBuilderImpl(Isolate* isolate, Zone* zone, FunctionLiteral* literal,
Ben Murdochda12d292016-06-02 14:46:10 +010039 Handle<Object> foreign, AsmTyper* typer)
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000040 : local_variables_(HashMap::PointersMatch,
41 ZoneHashMap::kDefaultHashMapCapacity,
42 ZoneAllocationPolicy(zone)),
43 functions_(HashMap::PointersMatch, ZoneHashMap::kDefaultHashMapCapacity,
44 ZoneAllocationPolicy(zone)),
45 global_variables_(HashMap::PointersMatch,
46 ZoneHashMap::kDefaultHashMapCapacity,
47 ZoneAllocationPolicy(zone)),
Ben Murdochc5610432016-08-08 18:44:38 +010048 scope_(kModuleScope),
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000049 builder_(new (zone) WasmModuleBuilder(zone)),
50 current_function_builder_(nullptr),
51 literal_(literal),
52 isolate_(isolate),
53 zone_(zone),
Ben Murdoch097c5b22016-05-18 11:27:45 +010054 foreign_(foreign),
Ben Murdochda12d292016-06-02 14:46:10 +010055 typer_(typer),
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000056 cache_(TypeCache::Get()),
57 breakable_blocks_(zone),
Ben Murdoch097c5b22016-05-18 11:27:45 +010058 init_function_index_(0),
59 next_table_index_(0),
60 function_tables_(HashMap::PointersMatch,
61 ZoneHashMap::kDefaultHashMapCapacity,
62 ZoneAllocationPolicy(zone)),
Ben Murdochc5610432016-08-08 18:44:38 +010063 imported_function_table_(this),
64 bounds_(typer->bounds()) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000065 InitializeAstVisitor(isolate);
66 }
67
68 void InitializeInitFunction() {
Ben Murdoch097c5b22016-05-18 11:27:45 +010069 init_function_index_ = builder_->AddFunction();
Ben Murdochc5610432016-08-08 18:44:38 +010070 FunctionSig::Builder b(zone(), 0, 0);
Ben Murdoch097c5b22016-05-18 11:27:45 +010071 current_function_builder_ = builder_->FunctionAt(init_function_index_);
Ben Murdochc5610432016-08-08 18:44:38 +010072 current_function_builder_->SetSignature(b.Build());
Ben Murdochda12d292016-06-02 14:46:10 +010073 builder_->MarkStartFunction(init_function_index_);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000074 current_function_builder_ = nullptr;
75 }
76
77 void Compile() {
78 InitializeInitFunction();
79 RECURSE(VisitFunctionLiteral(literal_));
80 }
81
82 void VisitVariableDeclaration(VariableDeclaration* decl) {}
83
84 void VisitFunctionDeclaration(FunctionDeclaration* decl) {
Ben Murdochc5610432016-08-08 18:44:38 +010085 DCHECK_EQ(kModuleScope, scope_);
Ben Murdoch097c5b22016-05-18 11:27:45 +010086 DCHECK_NULL(current_function_builder_);
Ben Murdochc5610432016-08-08 18:44:38 +010087 uint32_t index = LookupOrInsertFunction(decl->proxy()->var());
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000088 current_function_builder_ = builder_->FunctionAt(index);
Ben Murdochc5610432016-08-08 18:44:38 +010089 scope_ = kFuncScope;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000090 RECURSE(Visit(decl->fun()));
Ben Murdochc5610432016-08-08 18:44:38 +010091 scope_ = kModuleScope;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000092 current_function_builder_ = nullptr;
93 local_variables_.Clear();
94 }
95
96 void VisitImportDeclaration(ImportDeclaration* decl) {}
97
98 void VisitExportDeclaration(ExportDeclaration* decl) {}
99
100 void VisitStatements(ZoneList<Statement*>* stmts) {
101 for (int i = 0; i < stmts->length(); ++i) {
102 Statement* stmt = stmts->at(i);
Ben Murdochc5610432016-08-08 18:44:38 +0100103 ExpressionStatement* e = stmt->AsExpressionStatement();
104 if (e != nullptr && e->expression()->IsUndefinedLiteral()) {
105 continue;
106 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000107 RECURSE(Visit(stmt));
108 if (stmt->IsJump()) break;
109 }
110 }
111
112 void VisitBlock(Block* stmt) {
113 if (stmt->statements()->length() == 1) {
114 ExpressionStatement* expr =
115 stmt->statements()->at(0)->AsExpressionStatement();
116 if (expr != nullptr) {
117 if (expr->expression()->IsAssignment()) {
118 RECURSE(VisitExpressionStatement(expr));
119 return;
120 }
121 }
122 }
Ben Murdochc5610432016-08-08 18:44:38 +0100123 if (scope_ == kFuncScope) {
Ben Murdoch097c5b22016-05-18 11:27:45 +0100124 BlockVisitor visitor(this, stmt->AsBreakableStatement(), kExprBlock,
Ben Murdochc5610432016-08-08 18:44:38 +0100125 false);
Ben Murdoch097c5b22016-05-18 11:27:45 +0100126 RECURSE(VisitStatements(stmt->statements()));
Ben Murdoch097c5b22016-05-18 11:27:45 +0100127 } else {
128 RECURSE(VisitStatements(stmt->statements()));
129 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000130 }
131
132 class BlockVisitor {
133 private:
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000134 AsmWasmBuilderImpl* builder_;
135
136 public:
137 BlockVisitor(AsmWasmBuilderImpl* builder, BreakableStatement* stmt,
Ben Murdochc5610432016-08-08 18:44:38 +0100138 WasmOpcode opcode, bool is_loop)
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000139 : builder_(builder) {
140 builder_->breakable_blocks_.push_back(std::make_pair(stmt, is_loop));
141 builder_->current_function_builder_->Emit(opcode);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000142 }
143 ~BlockVisitor() {
Ben Murdochc5610432016-08-08 18:44:38 +0100144 builder_->current_function_builder_->Emit(kExprEnd);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000145 builder_->breakable_blocks_.pop_back();
146 }
147 };
148
149 void VisitExpressionStatement(ExpressionStatement* stmt) {
150 RECURSE(Visit(stmt->expression()));
151 }
152
153 void VisitEmptyStatement(EmptyStatement* stmt) {}
154
155 void VisitEmptyParentheses(EmptyParentheses* paren) { UNREACHABLE(); }
156
157 void VisitIfStatement(IfStatement* stmt) {
Ben Murdochc5610432016-08-08 18:44:38 +0100158 DCHECK_EQ(kFuncScope, scope_);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000159 RECURSE(Visit(stmt->condition()));
Ben Murdochc5610432016-08-08 18:44:38 +0100160 current_function_builder_->Emit(kExprIf);
161 // WASM ifs come with implement blocks for both arms.
162 breakable_blocks_.push_back(std::make_pair(nullptr, false));
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000163 if (stmt->HasThenStatement()) {
164 RECURSE(Visit(stmt->then_statement()));
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000165 }
166 if (stmt->HasElseStatement()) {
Ben Murdochc5610432016-08-08 18:44:38 +0100167 current_function_builder_->Emit(kExprElse);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000168 RECURSE(Visit(stmt->else_statement()));
169 }
Ben Murdochc5610432016-08-08 18:44:38 +0100170 current_function_builder_->Emit(kExprEnd);
171 breakable_blocks_.pop_back();
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000172 }
173
174 void VisitContinueStatement(ContinueStatement* stmt) {
Ben Murdochc5610432016-08-08 18:44:38 +0100175 DCHECK_EQ(kFuncScope, scope_);
Ben Murdoch097c5b22016-05-18 11:27:45 +0100176 DCHECK_NOT_NULL(stmt->target());
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000177 int i = static_cast<int>(breakable_blocks_.size()) - 1;
178 int block_distance = 0;
179 for (; i >= 0; i--) {
180 auto elem = breakable_blocks_.at(i);
181 if (elem.first == stmt->target()) {
182 DCHECK(elem.second);
183 break;
184 } else if (elem.second) {
185 block_distance += 2;
186 } else {
187 block_distance += 1;
188 }
189 }
190 DCHECK(i >= 0);
Ben Murdochc5610432016-08-08 18:44:38 +0100191 current_function_builder_->EmitWithU8(kExprBr, ARITY_0);
192 current_function_builder_->EmitVarInt(block_distance);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000193 }
194
195 void VisitBreakStatement(BreakStatement* stmt) {
Ben Murdochc5610432016-08-08 18:44:38 +0100196 DCHECK_EQ(kFuncScope, scope_);
Ben Murdoch097c5b22016-05-18 11:27:45 +0100197 DCHECK_NOT_NULL(stmt->target());
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000198 int i = static_cast<int>(breakable_blocks_.size()) - 1;
199 int block_distance = 0;
200 for (; i >= 0; i--) {
201 auto elem = breakable_blocks_.at(i);
202 if (elem.first == stmt->target()) {
203 if (elem.second) {
204 block_distance++;
205 }
206 break;
207 } else if (elem.second) {
208 block_distance += 2;
209 } else {
210 block_distance += 1;
211 }
212 }
213 DCHECK(i >= 0);
Ben Murdochc5610432016-08-08 18:44:38 +0100214 current_function_builder_->EmitWithU8(kExprBr, ARITY_0);
215 current_function_builder_->EmitVarInt(block_distance);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000216 }
217
218 void VisitReturnStatement(ReturnStatement* stmt) {
Ben Murdochc5610432016-08-08 18:44:38 +0100219 if (scope_ == kModuleScope) {
220 scope_ = kExportScope;
221 RECURSE(Visit(stmt->expression()));
222 scope_ = kModuleScope;
223 } else if (scope_ == kFuncScope) {
224 RECURSE(Visit(stmt->expression()));
225 uint8_t arity =
226 TypeOf(stmt->expression()) == kAstStmt ? ARITY_0 : ARITY_1;
227 current_function_builder_->EmitWithU8(kExprReturn, arity);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000228 } else {
Ben Murdochc5610432016-08-08 18:44:38 +0100229 UNREACHABLE();
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000230 }
231 }
232
233 void VisitWithStatement(WithStatement* stmt) { UNREACHABLE(); }
234
Ben Murdochc5610432016-08-08 18:44:38 +0100235 void HandleCase(CaseNode* node,
236 const ZoneMap<int, unsigned int>& case_to_block,
237 VariableProxy* tag, int default_block, int if_depth) {
238 int prev_if_depth = if_depth;
239 if (node->left != nullptr) {
240 VisitVariableProxy(tag);
241 current_function_builder_->EmitI32Const(node->begin);
242 current_function_builder_->Emit(kExprI32LtS);
243 current_function_builder_->Emit(kExprIf);
244 if_depth++;
245 breakable_blocks_.push_back(std::make_pair(nullptr, false));
246 HandleCase(node->left, case_to_block, tag, default_block, if_depth);
247 current_function_builder_->Emit(kExprElse);
248 }
249 if (node->right != nullptr) {
250 VisitVariableProxy(tag);
251 current_function_builder_->EmitI32Const(node->end);
252 current_function_builder_->Emit(kExprI32GtS);
253 current_function_builder_->Emit(kExprIf);
254 if_depth++;
255 breakable_blocks_.push_back(std::make_pair(nullptr, false));
256 HandleCase(node->right, case_to_block, tag, default_block, if_depth);
257 current_function_builder_->Emit(kExprElse);
258 }
259 if (node->begin == node->end) {
260 VisitVariableProxy(tag);
261 current_function_builder_->EmitI32Const(node->begin);
262 current_function_builder_->Emit(kExprI32Eq);
263 current_function_builder_->Emit(kExprIf);
264 DCHECK(case_to_block.find(node->begin) != case_to_block.end());
265 current_function_builder_->EmitWithU8(kExprBr, ARITY_0);
266 current_function_builder_->EmitVarInt(1 + if_depth +
267 case_to_block.at(node->begin));
268 current_function_builder_->Emit(kExprEnd);
269 } else {
270 if (node->begin != 0) {
271 VisitVariableProxy(tag);
272 current_function_builder_->EmitI32Const(node->begin);
273 current_function_builder_->Emit(kExprI32Sub);
274 } else {
275 VisitVariableProxy(tag);
276 }
277 current_function_builder_->EmitWithU8(kExprBrTable, ARITY_0);
278 current_function_builder_->EmitVarInt(node->end - node->begin + 1);
279 for (int v = node->begin; v <= node->end; v++) {
280 if (case_to_block.find(v) != case_to_block.end()) {
281 byte break_code[] = {BR_TARGET(if_depth + case_to_block.at(v))};
282 current_function_builder_->EmitCode(break_code, sizeof(break_code));
283 } else {
284 byte break_code[] = {BR_TARGET(if_depth + default_block)};
285 current_function_builder_->EmitCode(break_code, sizeof(break_code));
286 }
287 if (v == kMaxInt) {
288 break;
289 }
290 }
291 byte break_code[] = {BR_TARGET(if_depth + default_block)};
292 current_function_builder_->EmitCode(break_code, sizeof(break_code));
293 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000294
Ben Murdochc5610432016-08-08 18:44:38 +0100295 while (if_depth-- != prev_if_depth) {
296 breakable_blocks_.pop_back();
297 current_function_builder_->Emit(kExprEnd);
298 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000299 }
300
301 void VisitSwitchStatement(SwitchStatement* stmt) {
302 VariableProxy* tag = stmt->tag()->AsVariableProxy();
Ben Murdoch097c5b22016-05-18 11:27:45 +0100303 DCHECK_NOT_NULL(tag);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000304 ZoneList<CaseClause*>* clauses = stmt->cases();
Ben Murdochc5610432016-08-08 18:44:38 +0100305 int case_count = clauses->length();
306 if (case_count == 0) {
307 return;
308 }
309 BlockVisitor visitor(this, stmt->AsBreakableStatement(), kExprBlock, false);
310 ZoneVector<BlockVisitor*> blocks(zone_);
311 ZoneVector<int32_t> cases(zone_);
312 ZoneMap<int, unsigned int> case_to_block(zone_);
313 bool has_default = false;
314 for (int i = case_count - 1; i >= 0; i--) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000315 CaseClause* clause = clauses->at(i);
Ben Murdochc5610432016-08-08 18:44:38 +0100316 blocks.push_back(new BlockVisitor(this, nullptr, kExprBlock, false));
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000317 if (!clause->is_default()) {
Ben Murdochc5610432016-08-08 18:44:38 +0100318 Literal* label = clause->label()->AsLiteral();
319 Handle<Object> value = label->value();
320 DCHECK(value->IsNumber() &&
321 bounds_->get(label).upper->Is(cache_.kAsmSigned));
322 int32_t label_value;
323 if (!value->ToInt32(&label_value)) {
324 UNREACHABLE();
325 }
326 case_to_block[label_value] = i;
327 cases.push_back(label_value);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000328 } else {
Ben Murdochc5610432016-08-08 18:44:38 +0100329 DCHECK_EQ(i, case_count - 1);
330 has_default = true;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000331 }
332 }
Ben Murdochc5610432016-08-08 18:44:38 +0100333 if (!has_default || case_count > 1) {
334 int default_block = has_default ? case_count - 1 : case_count;
335 BlockVisitor switch_logic_block(this, nullptr, kExprBlock, false);
336 CaseNode* root = OrderCases(&cases, zone_);
337 HandleCase(root, case_to_block, tag, default_block, 0);
338 if (root->left != nullptr || root->right != nullptr ||
339 root->begin == root->end) {
340 current_function_builder_->EmitWithU8(kExprBr, ARITY_0);
341 current_function_builder_->EmitVarInt(default_block);
342 }
343 }
344 for (int i = 0; i < case_count; i++) {
345 CaseClause* clause = clauses->at(i);
346 RECURSE(VisitStatements(clause->statements()));
347 BlockVisitor* v = blocks.at(case_count - i - 1);
348 blocks.pop_back();
349 delete v;
350 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000351 }
352
353 void VisitCaseClause(CaseClause* clause) { UNREACHABLE(); }
354
355 void VisitDoWhileStatement(DoWhileStatement* stmt) {
Ben Murdochc5610432016-08-08 18:44:38 +0100356 DCHECK_EQ(kFuncScope, scope_);
357 BlockVisitor visitor(this, stmt->AsBreakableStatement(), kExprLoop, true);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000358 RECURSE(Visit(stmt->body()));
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000359 RECURSE(Visit(stmt->cond()));
Ben Murdochc5610432016-08-08 18:44:38 +0100360 current_function_builder_->Emit(kExprIf);
361 current_function_builder_->EmitWithU8U8(kExprBr, ARITY_0, 1);
362 current_function_builder_->Emit(kExprEnd);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000363 }
364
365 void VisitWhileStatement(WhileStatement* stmt) {
Ben Murdochc5610432016-08-08 18:44:38 +0100366 DCHECK_EQ(kFuncScope, scope_);
367 BlockVisitor visitor(this, stmt->AsBreakableStatement(), kExprLoop, true);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000368 RECURSE(Visit(stmt->cond()));
Ben Murdochc5610432016-08-08 18:44:38 +0100369 breakable_blocks_.push_back(std::make_pair(nullptr, false));
370 current_function_builder_->Emit(kExprIf);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000371 RECURSE(Visit(stmt->body()));
Ben Murdochc5610432016-08-08 18:44:38 +0100372 current_function_builder_->EmitWithU8U8(kExprBr, ARITY_0, 1);
373 current_function_builder_->Emit(kExprEnd);
374 breakable_blocks_.pop_back();
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000375 }
376
377 void VisitForStatement(ForStatement* stmt) {
Ben Murdochc5610432016-08-08 18:44:38 +0100378 DCHECK_EQ(kFuncScope, scope_);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000379 if (stmt->init() != nullptr) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000380 RECURSE(Visit(stmt->init()));
381 }
Ben Murdochc5610432016-08-08 18:44:38 +0100382 BlockVisitor visitor(this, stmt->AsBreakableStatement(), kExprLoop, true);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000383 if (stmt->cond() != nullptr) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000384 RECURSE(Visit(stmt->cond()));
Ben Murdochc5610432016-08-08 18:44:38 +0100385 current_function_builder_->Emit(kExprI32Eqz);
386 current_function_builder_->Emit(kExprIf);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000387 current_function_builder_->Emit(kExprNop);
Ben Murdochc5610432016-08-08 18:44:38 +0100388 current_function_builder_->EmitWithU8U8(kExprBr, ARITY_0, 2);
389 current_function_builder_->Emit(kExprEnd);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000390 }
391 if (stmt->body() != nullptr) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000392 RECURSE(Visit(stmt->body()));
393 }
394 if (stmt->next() != nullptr) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000395 RECURSE(Visit(stmt->next()));
396 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000397 current_function_builder_->Emit(kExprNop);
Ben Murdochc5610432016-08-08 18:44:38 +0100398 current_function_builder_->EmitWithU8U8(kExprBr, ARITY_0, 0);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000399 }
400
401 void VisitForInStatement(ForInStatement* stmt) { UNREACHABLE(); }
402
403 void VisitForOfStatement(ForOfStatement* stmt) { UNREACHABLE(); }
404
405 void VisitTryCatchStatement(TryCatchStatement* stmt) { UNREACHABLE(); }
406
407 void VisitTryFinallyStatement(TryFinallyStatement* stmt) { UNREACHABLE(); }
408
409 void VisitDebuggerStatement(DebuggerStatement* stmt) { UNREACHABLE(); }
410
411 void VisitFunctionLiteral(FunctionLiteral* expr) {
412 Scope* scope = expr->scope();
Ben Murdochc5610432016-08-08 18:44:38 +0100413 if (scope_ == kFuncScope) {
414 if (bounds_->get(expr).lower->IsFunction()) {
415 // Build the signature for the function.
416 FunctionType* func_type = bounds_->get(expr).lower->AsFunction();
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000417 LocalType return_type = TypeFrom(func_type->Result());
Ben Murdochc5610432016-08-08 18:44:38 +0100418 FunctionSig::Builder b(zone(), return_type == kAstStmt ? 0 : 1,
419 func_type->Arity());
420 if (return_type != kAstStmt) b.AddReturn(return_type);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000421 for (int i = 0; i < expr->parameter_count(); i++) {
422 LocalType type = TypeFrom(func_type->Parameter(i));
Ben Murdoch097c5b22016-05-18 11:27:45 +0100423 DCHECK_NE(kAstStmt, type);
Ben Murdochc5610432016-08-08 18:44:38 +0100424 b.AddParam(type);
425 InsertParameter(scope->parameter(i), type, i);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000426 }
Ben Murdochc5610432016-08-08 18:44:38 +0100427 current_function_builder_->SetSignature(b.Build());
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000428 } else {
429 UNREACHABLE();
430 }
431 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000432 RECURSE(VisitStatements(expr->body()));
Ben Murdoch097c5b22016-05-18 11:27:45 +0100433 RECURSE(VisitDeclarations(scope->declarations()));
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000434 }
435
436 void VisitNativeFunctionLiteral(NativeFunctionLiteral* expr) {
437 UNREACHABLE();
438 }
439
440 void VisitConditional(Conditional* expr) {
Ben Murdochc5610432016-08-08 18:44:38 +0100441 DCHECK_EQ(kFuncScope, scope_);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000442 RECURSE(Visit(expr->condition()));
Ben Murdochc5610432016-08-08 18:44:38 +0100443 // WASM ifs come with implicit blocks for both arms.
444 breakable_blocks_.push_back(std::make_pair(nullptr, false));
445 current_function_builder_->Emit(kExprIf);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000446 RECURSE(Visit(expr->then_expression()));
Ben Murdochc5610432016-08-08 18:44:38 +0100447 current_function_builder_->Emit(kExprElse);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000448 RECURSE(Visit(expr->else_expression()));
Ben Murdochc5610432016-08-08 18:44:38 +0100449 current_function_builder_->Emit(kExprEnd);
450 breakable_blocks_.pop_back();
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000451 }
452
Ben Murdochda12d292016-06-02 14:46:10 +0100453 bool VisitStdlibConstant(Variable* var) {
454 AsmTyper::StandardMember standard_object =
455 typer_->VariableAsStandardMember(var);
456 double value;
457 switch (standard_object) {
458 case AsmTyper::kInfinity: {
459 value = std::numeric_limits<double>::infinity();
460 break;
461 }
462 case AsmTyper::kNaN: {
463 value = std::numeric_limits<double>::quiet_NaN();
464 break;
465 }
466 case AsmTyper::kMathE: {
467 value = M_E;
468 break;
469 }
470 case AsmTyper::kMathLN10: {
471 value = M_LN10;
472 break;
473 }
474 case AsmTyper::kMathLN2: {
475 value = M_LN2;
476 break;
477 }
478 case AsmTyper::kMathLOG10E: {
479 value = M_LOG10E;
480 break;
481 }
482 case AsmTyper::kMathLOG2E: {
483 value = M_LOG2E;
484 break;
485 }
486 case AsmTyper::kMathPI: {
487 value = M_PI;
488 break;
489 }
490 case AsmTyper::kMathSQRT1_2: {
491 value = M_SQRT1_2;
492 break;
493 }
494 case AsmTyper::kMathSQRT2: {
495 value = M_SQRT2;
496 break;
497 }
498 default: { return false; }
499 }
500 byte code[] = {WASM_F64(value)};
501 current_function_builder_->EmitCode(code, sizeof(code));
502 return true;
503 }
504
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000505 void VisitVariableProxy(VariableProxy* expr) {
Ben Murdochc5610432016-08-08 18:44:38 +0100506 if (scope_ == kFuncScope || scope_ == kInitScope) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000507 Variable* var = expr->var();
Ben Murdochc5610432016-08-08 18:44:38 +0100508 if (VisitStdlibConstant(var)) {
509 return;
Ben Murdoch097c5b22016-05-18 11:27:45 +0100510 }
511 LocalType var_type = TypeOf(expr);
512 DCHECK_NE(kAstStmt, var_type);
513 if (var->IsContextSlot()) {
Ben Murdochc5610432016-08-08 18:44:38 +0100514 current_function_builder_->EmitWithVarInt(
515 kExprLoadGlobal, LookupOrInsertGlobal(var, var_type));
Ben Murdoch097c5b22016-05-18 11:27:45 +0100516 } else {
Ben Murdochc5610432016-08-08 18:44:38 +0100517 current_function_builder_->EmitGetLocal(
518 LookupOrInsertLocal(var, var_type));
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000519 }
520 }
521 }
522
523 void VisitLiteral(Literal* expr) {
Ben Murdochda12d292016-06-02 14:46:10 +0100524 Handle<Object> value = expr->value();
Ben Murdochc5610432016-08-08 18:44:38 +0100525 if (!value->IsNumber() || (scope_ != kFuncScope && scope_ != kInitScope)) {
Ben Murdochda12d292016-06-02 14:46:10 +0100526 return;
527 }
Ben Murdochc5610432016-08-08 18:44:38 +0100528 Type* type = bounds_->get(expr).upper;
Ben Murdochda12d292016-06-02 14:46:10 +0100529 if (type->Is(cache_.kAsmSigned)) {
530 int32_t i = 0;
531 if (!value->ToInt32(&i)) {
532 UNREACHABLE();
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000533 }
Ben Murdochda12d292016-06-02 14:46:10 +0100534 byte code[] = {WASM_I32V(i)};
535 current_function_builder_->EmitCode(code, sizeof(code));
536 } else if (type->Is(cache_.kAsmUnsigned) || type->Is(cache_.kAsmFixnum)) {
537 uint32_t u = 0;
538 if (!value->ToUint32(&u)) {
539 UNREACHABLE();
540 }
541 int32_t i = static_cast<int32_t>(u);
542 byte code[] = {WASM_I32V(i)};
543 current_function_builder_->EmitCode(code, sizeof(code));
544 } else if (type->Is(cache_.kAsmDouble)) {
545 double val = expr->raw_value()->AsNumber();
546 byte code[] = {WASM_F64(val)};
547 current_function_builder_->EmitCode(code, sizeof(code));
548 } else {
549 UNREACHABLE();
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000550 }
551 }
552
553 void VisitRegExpLiteral(RegExpLiteral* expr) { UNREACHABLE(); }
554
555 void VisitObjectLiteral(ObjectLiteral* expr) {
556 ZoneList<ObjectLiteralProperty*>* props = expr->properties();
557 for (int i = 0; i < props->length(); ++i) {
558 ObjectLiteralProperty* prop = props->at(i);
Ben Murdochc5610432016-08-08 18:44:38 +0100559 DCHECK_EQ(kExportScope, scope_);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000560 VariableProxy* expr = prop->value()->AsVariableProxy();
Ben Murdoch097c5b22016-05-18 11:27:45 +0100561 DCHECK_NOT_NULL(expr);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000562 Variable* var = expr->var();
563 Literal* name = prop->key()->AsLiteral();
Ben Murdoch097c5b22016-05-18 11:27:45 +0100564 DCHECK_NOT_NULL(name);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000565 DCHECK(name->IsPropertyName());
566 const AstRawString* raw_name = name->AsRawPropertyName();
567 if (var->is_function()) {
Ben Murdochc5610432016-08-08 18:44:38 +0100568 uint32_t index = LookupOrInsertFunction(var);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000569 builder_->FunctionAt(index)->Exported(1);
Ben Murdochc5610432016-08-08 18:44:38 +0100570 builder_->FunctionAt(index)->SetName(
571 reinterpret_cast<const char*>(raw_name->raw_data()),
572 raw_name->length());
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000573 }
574 }
575 }
576
577 void VisitArrayLiteral(ArrayLiteral* expr) { UNREACHABLE(); }
578
579 void LoadInitFunction() {
Ben Murdoch097c5b22016-05-18 11:27:45 +0100580 current_function_builder_ = builder_->FunctionAt(init_function_index_);
Ben Murdochc5610432016-08-08 18:44:38 +0100581 scope_ = kInitScope;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000582 }
583
584 void UnLoadInitFunction() {
Ben Murdochc5610432016-08-08 18:44:38 +0100585 scope_ = kModuleScope;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000586 current_function_builder_ = nullptr;
587 }
588
Ben Murdoch097c5b22016-05-18 11:27:45 +0100589 void AddFunctionTable(VariableProxy* table, ArrayLiteral* funcs) {
590 FunctionType* func_type =
Ben Murdochc5610432016-08-08 18:44:38 +0100591 bounds_->get(funcs).lower->AsArray()->Element()->AsFunction();
Ben Murdoch097c5b22016-05-18 11:27:45 +0100592 LocalType return_type = TypeFrom(func_type->Result());
593 FunctionSig::Builder sig(zone(), return_type == kAstStmt ? 0 : 1,
594 func_type->Arity());
595 if (return_type != kAstStmt) {
596 sig.AddReturn(static_cast<LocalType>(return_type));
597 }
598 for (int i = 0; i < func_type->Arity(); i++) {
599 sig.AddParam(TypeFrom(func_type->Parameter(i)));
600 }
Ben Murdochc5610432016-08-08 18:44:38 +0100601 uint32_t signature_index = builder_->AddSignature(sig.Build());
Ben Murdoch097c5b22016-05-18 11:27:45 +0100602 InsertFunctionTable(table->var(), next_table_index_, signature_index);
603 next_table_index_ += funcs->values()->length();
604 for (int i = 0; i < funcs->values()->length(); i++) {
605 VariableProxy* func = funcs->values()->at(i)->AsVariableProxy();
606 DCHECK_NOT_NULL(func);
607 builder_->AddIndirectFunction(LookupOrInsertFunction(func->var()));
608 }
609 }
610
611 struct FunctionTableIndices : public ZoneObject {
612 uint32_t start_index;
Ben Murdochc5610432016-08-08 18:44:38 +0100613 uint32_t signature_index;
Ben Murdoch097c5b22016-05-18 11:27:45 +0100614 };
615
616 void InsertFunctionTable(Variable* v, uint32_t start_index,
Ben Murdochc5610432016-08-08 18:44:38 +0100617 uint32_t signature_index) {
Ben Murdoch097c5b22016-05-18 11:27:45 +0100618 FunctionTableIndices* container = new (zone()) FunctionTableIndices();
619 container->start_index = start_index;
620 container->signature_index = signature_index;
621 ZoneHashMap::Entry* entry = function_tables_.LookupOrInsert(
622 v, ComputePointerHash(v), ZoneAllocationPolicy(zone()));
623 entry->value = container;
624 }
625
626 FunctionTableIndices* LookupFunctionTable(Variable* v) {
627 ZoneHashMap::Entry* entry =
628 function_tables_.Lookup(v, ComputePointerHash(v));
629 DCHECK_NOT_NULL(entry);
630 return reinterpret_cast<FunctionTableIndices*>(entry->value);
631 }
632
633 class ImportedFunctionTable {
634 private:
635 class ImportedFunctionIndices : public ZoneObject {
636 public:
Ben Murdochc5610432016-08-08 18:44:38 +0100637 const char* name_;
Ben Murdoch097c5b22016-05-18 11:27:45 +0100638 int name_length_;
639 WasmModuleBuilder::SignatureMap signature_to_index_;
640
Ben Murdochc5610432016-08-08 18:44:38 +0100641 ImportedFunctionIndices(const char* name, int name_length, Zone* zone)
Ben Murdoch097c5b22016-05-18 11:27:45 +0100642 : name_(name), name_length_(name_length), signature_to_index_(zone) {}
643 };
644 ZoneHashMap table_;
645 AsmWasmBuilderImpl* builder_;
646
647 public:
648 explicit ImportedFunctionTable(AsmWasmBuilderImpl* builder)
649 : table_(HashMap::PointersMatch, ZoneHashMap::kDefaultHashMapCapacity,
650 ZoneAllocationPolicy(builder->zone())),
651 builder_(builder) {}
652
Ben Murdochc5610432016-08-08 18:44:38 +0100653 void AddImport(Variable* v, const char* name, int name_length) {
Ben Murdoch097c5b22016-05-18 11:27:45 +0100654 ImportedFunctionIndices* indices = new (builder_->zone())
655 ImportedFunctionIndices(name, name_length, builder_->zone());
656 ZoneHashMap::Entry* entry = table_.LookupOrInsert(
657 v, ComputePointerHash(v), ZoneAllocationPolicy(builder_->zone()));
658 entry->value = indices;
659 }
660
Ben Murdochc5610432016-08-08 18:44:38 +0100661 uint32_t GetFunctionIndex(Variable* v, FunctionSig* sig) {
Ben Murdoch097c5b22016-05-18 11:27:45 +0100662 ZoneHashMap::Entry* entry = table_.Lookup(v, ComputePointerHash(v));
663 DCHECK_NOT_NULL(entry);
664 ImportedFunctionIndices* indices =
665 reinterpret_cast<ImportedFunctionIndices*>(entry->value);
666 WasmModuleBuilder::SignatureMap::iterator pos =
667 indices->signature_to_index_.find(sig);
668 if (pos != indices->signature_to_index_.end()) {
669 return pos->second;
670 } else {
Ben Murdochc5610432016-08-08 18:44:38 +0100671 uint32_t index = builder_->builder_->AddImport(
672 indices->name_, indices->name_length_, sig);
Ben Murdoch097c5b22016-05-18 11:27:45 +0100673 indices->signature_to_index_[sig] = index;
Ben Murdoch097c5b22016-05-18 11:27:45 +0100674 return index;
675 }
676 }
677 };
678
Ben Murdochc5610432016-08-08 18:44:38 +0100679 void EmitAssignmentLhs(Expression* target, MachineType* mtype) {
680 // Match the left hand side of the assignment.
681 VariableProxy* target_var = target->AsVariableProxy();
682 if (target_var != nullptr) {
683 // Left hand side is a local or a global variable, no code on LHS.
684 return;
685 }
686
687 Property* target_prop = target->AsProperty();
688 if (target_prop != nullptr) {
689 // Left hand side is a property access, i.e. the asm.js heap.
690 VisitPropertyAndEmitIndex(target_prop, mtype);
691 return;
692 }
693
694 if (target_var == nullptr && target_prop == nullptr) {
695 UNREACHABLE(); // invalid assignment.
696 }
697 }
698
699 void EmitAssignmentRhs(Expression* target, Expression* value, bool* is_nop) {
700 BinaryOperation* binop = value->AsBinaryOperation();
701 if (binop != nullptr) {
702 if (scope_ == kInitScope) {
703 // Handle foreign variables in the initialization scope.
Ben Murdoch097c5b22016-05-18 11:27:45 +0100704 Property* prop = binop->left()->AsProperty();
Ben Murdoch097c5b22016-05-18 11:27:45 +0100705 if (binop->op() == Token::MUL) {
706 DCHECK(binop->right()->IsLiteral());
707 DCHECK_EQ(1.0, binop->right()->AsLiteral()->raw_value()->AsNumber());
708 DCHECK(binop->right()->AsLiteral()->raw_value()->ContainsDot());
709 VisitForeignVariable(true, prop);
Ben Murdochc5610432016-08-08 18:44:38 +0100710 return;
Ben Murdoch097c5b22016-05-18 11:27:45 +0100711 } else if (binop->op() == Token::BIT_OR) {
712 DCHECK(binop->right()->IsLiteral());
713 DCHECK_EQ(0.0, binop->right()->AsLiteral()->raw_value()->AsNumber());
714 DCHECK(!binop->right()->AsLiteral()->raw_value()->ContainsDot());
715 VisitForeignVariable(false, prop);
Ben Murdochc5610432016-08-08 18:44:38 +0100716 return;
Ben Murdoch097c5b22016-05-18 11:27:45 +0100717 } else {
718 UNREACHABLE();
719 }
Ben Murdoch097c5b22016-05-18 11:27:45 +0100720 }
Ben Murdochc5610432016-08-08 18:44:38 +0100721 if (MatchBinaryOperation(binop) == kAsIs) {
722 VariableProxy* target_var = target->AsVariableProxy();
723 VariableProxy* effective_value_var = GetLeft(binop)->AsVariableProxy();
724 if (target_var != nullptr && effective_value_var != nullptr &&
725 target_var->var() == effective_value_var->var()) {
726 *is_nop = true;
727 return;
728 }
729 }
730 }
731 RECURSE(Visit(value));
732 }
733
734 void EmitAssignment(Assignment* expr, MachineType type) {
735 // Match the left hand side of the assignment.
736 VariableProxy* target_var = expr->target()->AsVariableProxy();
737 if (target_var != nullptr) {
738 // Left hand side is a local or a global variable.
739 Variable* var = target_var->var();
740 LocalType var_type = TypeOf(expr);
741 DCHECK_NE(kAstStmt, var_type);
742 if (var->IsContextSlot()) {
743 current_function_builder_->EmitWithVarInt(
744 kExprStoreGlobal, LookupOrInsertGlobal(var, var_type));
745 } else {
746 current_function_builder_->EmitSetLocal(
747 LookupOrInsertLocal(var, var_type));
748 }
749 }
750
751 Property* target_prop = expr->target()->AsProperty();
752 if (target_prop != nullptr) {
753 // Left hand side is a property access, i.e. the asm.js heap.
754 if (TypeOf(expr->value()) == kAstF64 && expr->target()->IsProperty() &&
755 bounds_->get(expr->target()->AsProperty()->obj())
756 .lower->Is(cache_.kFloat32Array)) {
757 current_function_builder_->Emit(kExprF32ConvertF64);
758 }
759 WasmOpcode opcode;
760 if (type == MachineType::Int8()) {
761 opcode = kExprI32AsmjsStoreMem8;
762 } else if (type == MachineType::Uint8()) {
763 opcode = kExprI32AsmjsStoreMem8;
764 } else if (type == MachineType::Int16()) {
765 opcode = kExprI32AsmjsStoreMem16;
766 } else if (type == MachineType::Uint16()) {
767 opcode = kExprI32AsmjsStoreMem16;
768 } else if (type == MachineType::Int32()) {
769 opcode = kExprI32AsmjsStoreMem;
770 } else if (type == MachineType::Uint32()) {
771 opcode = kExprI32AsmjsStoreMem;
772 } else if (type == MachineType::Float32()) {
773 opcode = kExprF32AsmjsStoreMem;
774 } else if (type == MachineType::Float64()) {
775 opcode = kExprF64AsmjsStoreMem;
776 } else {
777 UNREACHABLE();
778 }
779 current_function_builder_->Emit(opcode);
780 }
781
782 if (target_var == nullptr && target_prop == nullptr) {
783 UNREACHABLE(); // invalid assignment.
784 }
785 }
786
787 void VisitAssignment(Assignment* expr) {
788 bool as_init = false;
789 if (scope_ == kModuleScope) {
Ben Murdochda12d292016-06-02 14:46:10 +0100790 Property* prop = expr->value()->AsProperty();
791 if (prop != nullptr) {
792 VariableProxy* vp = prop->obj()->AsVariableProxy();
793 if (vp != nullptr && vp->var()->IsParameter() &&
794 vp->var()->index() == 1) {
795 VariableProxy* target = expr->target()->AsVariableProxy();
Ben Murdochc5610432016-08-08 18:44:38 +0100796 if (bounds_->get(target).lower->Is(Type::Function())) {
Ben Murdochda12d292016-06-02 14:46:10 +0100797 const AstRawString* name =
798 prop->key()->AsLiteral()->AsRawPropertyName();
Ben Murdochc5610432016-08-08 18:44:38 +0100799 imported_function_table_.AddImport(
800 target->var(), reinterpret_cast<const char*>(name->raw_data()),
801 name->length());
Ben Murdoch097c5b22016-05-18 11:27:45 +0100802 }
803 }
Ben Murdochda12d292016-06-02 14:46:10 +0100804 // Property values in module scope don't emit code, so return.
805 return;
806 }
807 ArrayLiteral* funcs = expr->value()->AsArrayLiteral();
808 if (funcs != nullptr &&
Ben Murdochc5610432016-08-08 18:44:38 +0100809 bounds_->get(funcs).lower->AsArray()->Element()->IsFunction()) {
Ben Murdochda12d292016-06-02 14:46:10 +0100810 VariableProxy* target = expr->target()->AsVariableProxy();
811 DCHECK_NOT_NULL(target);
812 AddFunctionTable(target, funcs);
813 // Only add to the function table. No init needed.
814 return;
815 }
816 if (expr->value()->IsCallNew()) {
817 // No init code to emit for CallNew nodes.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000818 return;
819 }
Ben Murdochc5610432016-08-08 18:44:38 +0100820 as_init = true;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000821 }
Ben Murdochc5610432016-08-08 18:44:38 +0100822
823 if (as_init) LoadInitFunction();
824 MachineType mtype;
825 bool is_nop = false;
826 EmitAssignmentLhs(expr->target(), &mtype);
827 EmitAssignmentRhs(expr->target(), expr->value(), &is_nop);
828 if (!is_nop) {
829 EmitAssignment(expr, mtype);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000830 }
Ben Murdochc5610432016-08-08 18:44:38 +0100831 if (as_init) UnLoadInitFunction();
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000832 }
833
834 void VisitYield(Yield* expr) { UNREACHABLE(); }
835
836 void VisitThrow(Throw* expr) { UNREACHABLE(); }
837
Ben Murdoch097c5b22016-05-18 11:27:45 +0100838 void VisitForeignVariable(bool is_float, Property* expr) {
839 DCHECK(expr->obj()->AsVariableProxy());
840 DCHECK(VariableLocation::PARAMETER ==
841 expr->obj()->AsVariableProxy()->var()->location());
842 DCHECK_EQ(1, expr->obj()->AsVariableProxy()->var()->index());
843 Literal* key_literal = expr->key()->AsLiteral();
844 DCHECK_NOT_NULL(key_literal);
845 if (!key_literal->value().is_null() && !foreign_.is_null() &&
846 foreign_->IsObject()) {
847 Handle<Name> name =
848 i::Object::ToName(isolate_, key_literal->value()).ToHandleChecked();
849 MaybeHandle<Object> maybe_value = i::Object::GetProperty(foreign_, name);
850 if (!maybe_value.is_null()) {
851 Handle<Object> value = maybe_value.ToHandleChecked();
852 if (is_float) {
853 MaybeHandle<Object> maybe_nvalue = i::Object::ToNumber(value);
854 if (!maybe_nvalue.is_null()) {
855 Handle<Object> nvalue = maybe_nvalue.ToHandleChecked();
856 if (nvalue->IsNumber()) {
857 double val = nvalue->Number();
858 byte code[] = {WASM_F64(val)};
859 current_function_builder_->EmitCode(code, sizeof(code));
860 return;
861 }
862 }
863 } else {
864 MaybeHandle<Object> maybe_nvalue =
865 i::Object::ToInt32(isolate_, value);
866 if (!maybe_nvalue.is_null()) {
867 Handle<Object> nvalue = maybe_nvalue.ToHandleChecked();
868 if (nvalue->IsNumber()) {
869 int32_t val = static_cast<int32_t>(nvalue->Number());
Ben Murdochc5610432016-08-08 18:44:38 +0100870 current_function_builder_->EmitI32Const(val);
Ben Murdoch097c5b22016-05-18 11:27:45 +0100871 return;
872 }
873 }
874 }
875 }
876 }
877 if (is_float) {
878 byte code[] = {WASM_F64(std::numeric_limits<double>::quiet_NaN())};
879 current_function_builder_->EmitCode(code, sizeof(code));
880 } else {
Ben Murdochda12d292016-06-02 14:46:10 +0100881 byte code[] = {WASM_I32V_1(0)};
Ben Murdoch097c5b22016-05-18 11:27:45 +0100882 current_function_builder_->EmitCode(code, sizeof(code));
883 }
884 }
885
Ben Murdochc5610432016-08-08 18:44:38 +0100886 void VisitPropertyAndEmitIndex(Property* expr, MachineType* mtype) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000887 Expression* obj = expr->obj();
Ben Murdochc5610432016-08-08 18:44:38 +0100888 DCHECK_EQ(bounds_->get(obj).lower, bounds_->get(obj).upper);
889 Type* type = bounds_->get(obj).lower;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000890 int size;
891 if (type->Is(cache_.kUint8Array)) {
Ben Murdochc5610432016-08-08 18:44:38 +0100892 *mtype = MachineType::Uint8();
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000893 size = 1;
894 } else if (type->Is(cache_.kInt8Array)) {
Ben Murdochc5610432016-08-08 18:44:38 +0100895 *mtype = MachineType::Int8();
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000896 size = 1;
897 } else if (type->Is(cache_.kUint16Array)) {
Ben Murdochc5610432016-08-08 18:44:38 +0100898 *mtype = MachineType::Uint16();
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000899 size = 2;
900 } else if (type->Is(cache_.kInt16Array)) {
Ben Murdochc5610432016-08-08 18:44:38 +0100901 *mtype = MachineType::Int16();
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000902 size = 2;
903 } else if (type->Is(cache_.kUint32Array)) {
Ben Murdochc5610432016-08-08 18:44:38 +0100904 *mtype = MachineType::Uint32();
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000905 size = 4;
906 } else if (type->Is(cache_.kInt32Array)) {
Ben Murdochc5610432016-08-08 18:44:38 +0100907 *mtype = MachineType::Int32();
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000908 size = 4;
909 } else if (type->Is(cache_.kUint32Array)) {
Ben Murdochc5610432016-08-08 18:44:38 +0100910 *mtype = MachineType::Uint32();
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000911 size = 4;
912 } else if (type->Is(cache_.kFloat32Array)) {
Ben Murdochc5610432016-08-08 18:44:38 +0100913 *mtype = MachineType::Float32();
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000914 size = 4;
915 } else if (type->Is(cache_.kFloat64Array)) {
Ben Murdochc5610432016-08-08 18:44:38 +0100916 *mtype = MachineType::Float64();
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000917 size = 8;
918 } else {
919 UNREACHABLE();
920 }
Ben Murdoch097c5b22016-05-18 11:27:45 +0100921 if (size == 1) {
922 // Allow more general expression in byte arrays than the spec
923 // strictly permits.
924 // Early versions of Emscripten emit HEAP8[HEAP32[..]|0] in
925 // places that strictly should be HEAP8[HEAP32[..]>>0].
926 RECURSE(Visit(expr->key()));
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000927 return;
Ben Murdochc5610432016-08-08 18:44:38 +0100928 }
929
930 Literal* value = expr->key()->AsLiteral();
931 if (value) {
932 DCHECK(value->raw_value()->IsNumber());
933 DCHECK_EQ(kAstI32, TypeOf(value));
934 int32_t val = static_cast<int32_t>(value->raw_value()->AsNumber());
935 // TODO(titzer): handle overflow here.
936 current_function_builder_->EmitI32Const(val * size);
937 return;
938 }
939 BinaryOperation* binop = expr->key()->AsBinaryOperation();
940 if (binop) {
941 DCHECK_EQ(Token::SAR, binop->op());
942 DCHECK(binop->right()->AsLiteral()->raw_value()->IsNumber());
943 DCHECK(kAstI32 == TypeOf(binop->right()->AsLiteral()));
944 DCHECK_EQ(size,
945 1 << static_cast<int>(
946 binop->right()->AsLiteral()->raw_value()->AsNumber()));
947 // Mask bottom bits to match asm.js behavior.
948 byte mask = static_cast<byte>(~(size - 1));
949 RECURSE(Visit(binop->left()));
950 current_function_builder_->EmitWithU8(kExprI8Const, mask);
951 current_function_builder_->Emit(kExprI32And);
952 return;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000953 }
954 UNREACHABLE();
955 }
956
Ben Murdochc5610432016-08-08 18:44:38 +0100957 void VisitProperty(Property* expr) {
958 MachineType type;
959 VisitPropertyAndEmitIndex(expr, &type);
960 WasmOpcode opcode;
961 if (type == MachineType::Int8()) {
962 opcode = kExprI32AsmjsLoadMem8S;
963 } else if (type == MachineType::Uint8()) {
964 opcode = kExprI32AsmjsLoadMem8U;
965 } else if (type == MachineType::Int16()) {
966 opcode = kExprI32AsmjsLoadMem16S;
967 } else if (type == MachineType::Uint16()) {
968 opcode = kExprI32AsmjsLoadMem16U;
969 } else if (type == MachineType::Int32()) {
970 opcode = kExprI32AsmjsLoadMem;
971 } else if (type == MachineType::Uint32()) {
972 opcode = kExprI32AsmjsLoadMem;
973 } else if (type == MachineType::Float32()) {
974 opcode = kExprF32AsmjsLoadMem;
975 } else if (type == MachineType::Float64()) {
976 opcode = kExprF64AsmjsLoadMem;
977 } else {
978 UNREACHABLE();
979 }
980
981 current_function_builder_->Emit(opcode);
982 }
983
Ben Murdochda12d292016-06-02 14:46:10 +0100984 bool VisitStdlibFunction(Call* call, VariableProxy* expr) {
985 Variable* var = expr->var();
986 AsmTyper::StandardMember standard_object =
987 typer_->VariableAsStandardMember(var);
988 ZoneList<Expression*>* args = call->arguments();
989 LocalType call_type = TypeOf(call);
Ben Murdochc5610432016-08-08 18:44:38 +0100990
Ben Murdochda12d292016-06-02 14:46:10 +0100991 switch (standard_object) {
992 case AsmTyper::kNone: {
993 return false;
994 }
995 case AsmTyper::kMathAcos: {
Ben Murdochc5610432016-08-08 18:44:38 +0100996 VisitCallArgs(call);
Ben Murdochda12d292016-06-02 14:46:10 +0100997 DCHECK_EQ(kAstF64, call_type);
998 current_function_builder_->Emit(kExprF64Acos);
999 break;
1000 }
1001 case AsmTyper::kMathAsin: {
Ben Murdochc5610432016-08-08 18:44:38 +01001002 VisitCallArgs(call);
Ben Murdochda12d292016-06-02 14:46:10 +01001003 DCHECK_EQ(kAstF64, call_type);
1004 current_function_builder_->Emit(kExprF64Asin);
1005 break;
1006 }
1007 case AsmTyper::kMathAtan: {
Ben Murdochc5610432016-08-08 18:44:38 +01001008 VisitCallArgs(call);
Ben Murdochda12d292016-06-02 14:46:10 +01001009 DCHECK_EQ(kAstF64, call_type);
1010 current_function_builder_->Emit(kExprF64Atan);
1011 break;
1012 }
1013 case AsmTyper::kMathCos: {
Ben Murdochc5610432016-08-08 18:44:38 +01001014 VisitCallArgs(call);
Ben Murdochda12d292016-06-02 14:46:10 +01001015 DCHECK_EQ(kAstF64, call_type);
1016 current_function_builder_->Emit(kExprF64Cos);
1017 break;
1018 }
1019 case AsmTyper::kMathSin: {
Ben Murdochc5610432016-08-08 18:44:38 +01001020 VisitCallArgs(call);
Ben Murdochda12d292016-06-02 14:46:10 +01001021 DCHECK_EQ(kAstF64, call_type);
1022 current_function_builder_->Emit(kExprF64Sin);
1023 break;
1024 }
1025 case AsmTyper::kMathTan: {
Ben Murdochc5610432016-08-08 18:44:38 +01001026 VisitCallArgs(call);
Ben Murdochda12d292016-06-02 14:46:10 +01001027 DCHECK_EQ(kAstF64, call_type);
1028 current_function_builder_->Emit(kExprF64Tan);
1029 break;
1030 }
1031 case AsmTyper::kMathExp: {
Ben Murdochc5610432016-08-08 18:44:38 +01001032 VisitCallArgs(call);
Ben Murdochda12d292016-06-02 14:46:10 +01001033 DCHECK_EQ(kAstF64, call_type);
1034 current_function_builder_->Emit(kExprF64Exp);
1035 break;
1036 }
1037 case AsmTyper::kMathLog: {
Ben Murdochc5610432016-08-08 18:44:38 +01001038 VisitCallArgs(call);
Ben Murdochda12d292016-06-02 14:46:10 +01001039 DCHECK_EQ(kAstF64, call_type);
1040 current_function_builder_->Emit(kExprF64Log);
1041 break;
1042 }
1043 case AsmTyper::kMathCeil: {
Ben Murdochc5610432016-08-08 18:44:38 +01001044 VisitCallArgs(call);
Ben Murdochda12d292016-06-02 14:46:10 +01001045 if (call_type == kAstF32) {
1046 current_function_builder_->Emit(kExprF32Ceil);
1047 } else if (call_type == kAstF64) {
1048 current_function_builder_->Emit(kExprF64Ceil);
1049 } else {
1050 UNREACHABLE();
1051 }
1052 break;
1053 }
1054 case AsmTyper::kMathFloor: {
Ben Murdochc5610432016-08-08 18:44:38 +01001055 VisitCallArgs(call);
Ben Murdochda12d292016-06-02 14:46:10 +01001056 if (call_type == kAstF32) {
1057 current_function_builder_->Emit(kExprF32Floor);
1058 } else if (call_type == kAstF64) {
1059 current_function_builder_->Emit(kExprF64Floor);
1060 } else {
1061 UNREACHABLE();
1062 }
1063 break;
1064 }
1065 case AsmTyper::kMathSqrt: {
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(kExprF32Sqrt);
1069 } else if (call_type == kAstF64) {
1070 current_function_builder_->Emit(kExprF64Sqrt);
1071 } else {
1072 UNREACHABLE();
1073 }
1074 break;
1075 }
1076 case AsmTyper::kMathAbs: {
Ben Murdochda12d292016-06-02 14:46:10 +01001077 if (call_type == kAstI32) {
Ben Murdochc5610432016-08-08 18:44:38 +01001078 uint32_t tmp = current_function_builder_->AddLocal(kAstI32);
1079
1080 // if set_local(tmp, x) < 0
1081 Visit(call->arguments()->at(0));
1082 current_function_builder_->EmitSetLocal(tmp);
Ben Murdochda12d292016-06-02 14:46:10 +01001083 byte code[] = {WASM_I8(0)};
1084 current_function_builder_->EmitCode(code, sizeof(code));
Ben Murdochc5610432016-08-08 18:44:38 +01001085 current_function_builder_->Emit(kExprI32LtS);
1086 current_function_builder_->Emit(kExprIf);
1087
1088 // then (0 - tmp)
Ben Murdochda12d292016-06-02 14:46:10 +01001089 current_function_builder_->EmitCode(code, sizeof(code));
Ben Murdochc5610432016-08-08 18:44:38 +01001090 current_function_builder_->EmitGetLocal(tmp);
1091 current_function_builder_->Emit(kExprI32Sub);
1092
1093 // else tmp
1094 current_function_builder_->Emit(kExprElse);
1095 current_function_builder_->EmitGetLocal(tmp);
1096 // end
1097 current_function_builder_->Emit(kExprEnd);
1098
Ben Murdochda12d292016-06-02 14:46:10 +01001099 } else if (call_type == kAstF32) {
Ben Murdochc5610432016-08-08 18:44:38 +01001100 VisitCallArgs(call);
Ben Murdochda12d292016-06-02 14:46:10 +01001101 current_function_builder_->Emit(kExprF32Abs);
1102 } else if (call_type == kAstF64) {
Ben Murdochc5610432016-08-08 18:44:38 +01001103 VisitCallArgs(call);
Ben Murdochda12d292016-06-02 14:46:10 +01001104 current_function_builder_->Emit(kExprF64Abs);
1105 } else {
1106 UNREACHABLE();
1107 }
1108 break;
1109 }
1110 case AsmTyper::kMathMin: {
1111 // TODO(bradnelson): Change wasm to match Math.min in asm.js mode.
1112 if (call_type == kAstI32) {
Ben Murdochc5610432016-08-08 18:44:38 +01001113 uint32_t tmp_x = current_function_builder_->AddLocal(kAstI32);
1114 uint32_t tmp_y = current_function_builder_->AddLocal(kAstI32);
1115
1116 // if set_local(tmp_x, x) < set_local(tmp_y, y)
1117 Visit(call->arguments()->at(0));
1118 current_function_builder_->EmitSetLocal(tmp_x);
1119
1120 Visit(call->arguments()->at(1));
1121 current_function_builder_->EmitSetLocal(tmp_y);
1122
Ben Murdochda12d292016-06-02 14:46:10 +01001123 current_function_builder_->Emit(kExprI32LeS);
Ben Murdochc5610432016-08-08 18:44:38 +01001124 current_function_builder_->Emit(kExprIf);
1125
1126 // then tmp_x
1127 current_function_builder_->EmitGetLocal(tmp_x);
1128
1129 // else tmp_y
1130 current_function_builder_->Emit(kExprElse);
1131 current_function_builder_->EmitGetLocal(tmp_y);
1132 current_function_builder_->Emit(kExprEnd);
1133
Ben Murdochda12d292016-06-02 14:46:10 +01001134 } else if (call_type == kAstF32) {
Ben Murdochc5610432016-08-08 18:44:38 +01001135 VisitCallArgs(call);
Ben Murdochda12d292016-06-02 14:46:10 +01001136 current_function_builder_->Emit(kExprF32Min);
1137 } else if (call_type == kAstF64) {
Ben Murdochc5610432016-08-08 18:44:38 +01001138 VisitCallArgs(call);
Ben Murdochda12d292016-06-02 14:46:10 +01001139 current_function_builder_->Emit(kExprF64Min);
1140 } else {
1141 UNREACHABLE();
1142 }
1143 break;
1144 }
1145 case AsmTyper::kMathMax: {
1146 // TODO(bradnelson): Change wasm to match Math.max in asm.js mode.
1147 if (call_type == kAstI32) {
Ben Murdochc5610432016-08-08 18:44:38 +01001148 uint32_t tmp_x = current_function_builder_->AddLocal(kAstI32);
1149 uint32_t tmp_y = current_function_builder_->AddLocal(kAstI32);
1150
1151 // if set_local(tmp_x, x) < set_local(tmp_y, y)
1152 Visit(call->arguments()->at(0));
1153
1154 current_function_builder_->EmitSetLocal(tmp_x);
1155
1156 Visit(call->arguments()->at(1));
1157 current_function_builder_->EmitSetLocal(tmp_y);
1158
1159 current_function_builder_->Emit(kExprI32LeS);
1160 current_function_builder_->Emit(kExprIf);
1161
1162 // then tmp_y
1163 current_function_builder_->EmitGetLocal(tmp_y);
1164
1165 // else tmp_x
1166 current_function_builder_->Emit(kExprElse);
1167 current_function_builder_->EmitGetLocal(tmp_x);
1168 current_function_builder_->Emit(kExprEnd);
1169
Ben Murdochda12d292016-06-02 14:46:10 +01001170 } else if (call_type == kAstF32) {
Ben Murdochc5610432016-08-08 18:44:38 +01001171 VisitCallArgs(call);
Ben Murdochda12d292016-06-02 14:46:10 +01001172 current_function_builder_->Emit(kExprF32Max);
1173 } else if (call_type == kAstF64) {
Ben Murdochc5610432016-08-08 18:44:38 +01001174 VisitCallArgs(call);
Ben Murdochda12d292016-06-02 14:46:10 +01001175 current_function_builder_->Emit(kExprF64Max);
1176 } else {
1177 UNREACHABLE();
1178 }
1179 break;
1180 }
1181 case AsmTyper::kMathAtan2: {
Ben Murdochc5610432016-08-08 18:44:38 +01001182 VisitCallArgs(call);
Ben Murdochda12d292016-06-02 14:46:10 +01001183 DCHECK_EQ(kAstF64, call_type);
1184 current_function_builder_->Emit(kExprF64Atan2);
1185 break;
1186 }
1187 case AsmTyper::kMathPow: {
Ben Murdochc5610432016-08-08 18:44:38 +01001188 VisitCallArgs(call);
Ben Murdochda12d292016-06-02 14:46:10 +01001189 DCHECK_EQ(kAstF64, call_type);
1190 current_function_builder_->Emit(kExprF64Pow);
1191 break;
1192 }
1193 case AsmTyper::kMathImul: {
Ben Murdochc5610432016-08-08 18:44:38 +01001194 VisitCallArgs(call);
Ben Murdochda12d292016-06-02 14:46:10 +01001195 current_function_builder_->Emit(kExprI32Mul);
1196 break;
1197 }
1198 case AsmTyper::kMathFround: {
1199 DCHECK(args->length() == 1);
1200 Literal* literal = args->at(0)->AsLiteral();
1201 if (literal != nullptr) {
Ben Murdochc5610432016-08-08 18:44:38 +01001202 // constant fold Math.fround(#const);
Ben Murdochda12d292016-06-02 14:46:10 +01001203 if (literal->raw_value()->IsNumber()) {
1204 float val = static_cast<float>(literal->raw_value()->AsNumber());
1205 byte code[] = {WASM_F32(val)};
1206 current_function_builder_->EmitCode(code, sizeof(code));
1207 return true;
1208 }
1209 }
Ben Murdochc5610432016-08-08 18:44:38 +01001210 VisitCallArgs(call);
Ben Murdochda12d292016-06-02 14:46:10 +01001211 switch (TypeIndexOf(args->at(0))) {
1212 case kInt32:
1213 case kFixnum:
1214 current_function_builder_->Emit(kExprF32SConvertI32);
1215 break;
1216 case kUint32:
1217 current_function_builder_->Emit(kExprF32UConvertI32);
1218 break;
1219 case kFloat32:
1220 break;
1221 case kFloat64:
1222 current_function_builder_->Emit(kExprF32ConvertF64);
1223 break;
1224 default:
1225 UNREACHABLE();
1226 }
1227 break;
1228 }
1229 default: {
1230 UNREACHABLE();
1231 break;
1232 }
1233 }
Ben Murdochda12d292016-06-02 14:46:10 +01001234 return true;
1235 }
1236
1237 void VisitCallArgs(Call* expr) {
1238 ZoneList<Expression*>* args = expr->arguments();
1239 for (int i = 0; i < args->length(); ++i) {
1240 Expression* arg = args->at(i);
1241 RECURSE(Visit(arg));
1242 }
1243 }
1244
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001245 void VisitCall(Call* expr) {
1246 Call::CallType call_type = expr->GetCallType(isolate_);
1247 switch (call_type) {
1248 case Call::OTHER_CALL: {
Ben Murdochc5610432016-08-08 18:44:38 +01001249 DCHECK_EQ(kFuncScope, scope_);
Ben Murdochda12d292016-06-02 14:46:10 +01001250 VariableProxy* proxy = expr->expression()->AsVariableProxy();
1251 if (proxy != nullptr) {
1252 if (VisitStdlibFunction(expr, proxy)) {
1253 return;
1254 }
1255 }
Ben Murdochc5610432016-08-08 18:44:38 +01001256 uint32_t index;
Ben Murdoch097c5b22016-05-18 11:27:45 +01001257 VariableProxy* vp = expr->expression()->AsVariableProxy();
1258 if (vp != nullptr &&
Ben Murdochc5610432016-08-08 18:44:38 +01001259 Type::Any()->Is(bounds_->get(vp).lower->AsFunction()->Result())) {
Ben Murdoch097c5b22016-05-18 11:27:45 +01001260 LocalType return_type = TypeOf(expr);
1261 ZoneList<Expression*>* args = expr->arguments();
1262 FunctionSig::Builder sig(zone(), return_type == kAstStmt ? 0 : 1,
1263 args->length());
1264 if (return_type != kAstStmt) {
1265 sig.AddReturn(return_type);
1266 }
1267 for (int i = 0; i < args->length(); i++) {
1268 sig.AddParam(TypeOf(args->at(i)));
1269 }
1270 index =
1271 imported_function_table_.GetFunctionIndex(vp->var(), sig.Build());
Ben Murdochc5610432016-08-08 18:44:38 +01001272 VisitCallArgs(expr);
1273 current_function_builder_->Emit(kExprCallImport);
1274 current_function_builder_->EmitVarInt(expr->arguments()->length());
1275 current_function_builder_->EmitVarInt(index);
Ben Murdoch097c5b22016-05-18 11:27:45 +01001276 } else {
1277 index = LookupOrInsertFunction(vp->var());
Ben Murdochc5610432016-08-08 18:44:38 +01001278 VisitCallArgs(expr);
1279 current_function_builder_->Emit(kExprCallFunction);
1280 current_function_builder_->EmitVarInt(expr->arguments()->length());
1281 current_function_builder_->EmitVarInt(index);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001282 }
Ben Murdoch097c5b22016-05-18 11:27:45 +01001283 break;
1284 }
1285 case Call::KEYED_PROPERTY_CALL: {
Ben Murdochc5610432016-08-08 18:44:38 +01001286 DCHECK_EQ(kFuncScope, scope_);
Ben Murdoch097c5b22016-05-18 11:27:45 +01001287 Property* p = expr->expression()->AsProperty();
1288 DCHECK_NOT_NULL(p);
1289 VariableProxy* var = p->obj()->AsVariableProxy();
1290 DCHECK_NOT_NULL(var);
1291 FunctionTableIndices* indices = LookupFunctionTable(var->var());
Ben Murdoch097c5b22016-05-18 11:27:45 +01001292 RECURSE(Visit(p->key()));
Ben Murdochc5610432016-08-08 18:44:38 +01001293 current_function_builder_->EmitI32Const(indices->start_index);
1294 current_function_builder_->Emit(kExprI32Add);
1295 VisitCallArgs(expr);
1296 current_function_builder_->Emit(kExprCallIndirect);
1297 current_function_builder_->EmitVarInt(expr->arguments()->length());
1298 current_function_builder_->EmitVarInt(indices->signature_index);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001299 break;
1300 }
1301 default:
1302 UNREACHABLE();
1303 }
1304 }
1305
1306 void VisitCallNew(CallNew* expr) { UNREACHABLE(); }
1307
1308 void VisitCallRuntime(CallRuntime* expr) { UNREACHABLE(); }
1309
1310 void VisitUnaryOperation(UnaryOperation* expr) {
Ben Murdochc5610432016-08-08 18:44:38 +01001311 RECURSE(Visit(expr->expression()));
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001312 switch (expr->op()) {
1313 case Token::NOT: {
Ben Murdoch097c5b22016-05-18 11:27:45 +01001314 DCHECK_EQ(kAstI32, TypeOf(expr->expression()));
Ben Murdochda12d292016-06-02 14:46:10 +01001315 current_function_builder_->Emit(kExprI32Eqz);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001316 break;
1317 }
1318 default:
1319 UNREACHABLE();
1320 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001321 }
1322
1323 void VisitCountOperation(CountOperation* expr) { UNREACHABLE(); }
1324
1325 bool MatchIntBinaryOperation(BinaryOperation* expr, Token::Value op,
1326 int32_t val) {
Ben Murdoch097c5b22016-05-18 11:27:45 +01001327 DCHECK_NOT_NULL(expr->right());
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001328 if (expr->op() == op && expr->right()->IsLiteral() &&
1329 TypeOf(expr) == kAstI32) {
1330 Literal* right = expr->right()->AsLiteral();
1331 DCHECK(right->raw_value()->IsNumber());
1332 if (static_cast<int32_t>(right->raw_value()->AsNumber()) == val) {
1333 return true;
1334 }
1335 }
1336 return false;
1337 }
1338
1339 bool MatchDoubleBinaryOperation(BinaryOperation* expr, Token::Value op,
1340 double val) {
Ben Murdoch097c5b22016-05-18 11:27:45 +01001341 DCHECK_NOT_NULL(expr->right());
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001342 if (expr->op() == op && expr->right()->IsLiteral() &&
1343 TypeOf(expr) == kAstF64) {
1344 Literal* right = expr->right()->AsLiteral();
1345 DCHECK(right->raw_value()->IsNumber());
1346 if (right->raw_value()->AsNumber() == val) {
1347 return true;
1348 }
1349 }
1350 return false;
1351 }
1352
1353 enum ConvertOperation { kNone, kAsIs, kToInt, kToDouble };
1354
1355 ConvertOperation MatchOr(BinaryOperation* expr) {
Ben Murdoch097c5b22016-05-18 11:27:45 +01001356 if (MatchIntBinaryOperation(expr, Token::BIT_OR, 0) &&
1357 (TypeOf(expr->left()) == kAstI32)) {
1358 return kAsIs;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001359 } else {
1360 return kNone;
1361 }
1362 }
1363
1364 ConvertOperation MatchShr(BinaryOperation* expr) {
1365 if (MatchIntBinaryOperation(expr, Token::SHR, 0)) {
1366 // TODO(titzer): this probably needs to be kToUint
1367 return (TypeOf(expr->left()) == kAstI32) ? kAsIs : kToInt;
1368 } else {
1369 return kNone;
1370 }
1371 }
1372
1373 ConvertOperation MatchXor(BinaryOperation* expr) {
1374 if (MatchIntBinaryOperation(expr, Token::BIT_XOR, 0xffffffff)) {
Ben Murdoch097c5b22016-05-18 11:27:45 +01001375 DCHECK_EQ(kAstI32, TypeOf(expr->left()));
1376 DCHECK_EQ(kAstI32, TypeOf(expr->right()));
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001377 BinaryOperation* op = expr->left()->AsBinaryOperation();
1378 if (op != nullptr) {
1379 if (MatchIntBinaryOperation(op, Token::BIT_XOR, 0xffffffff)) {
Ben Murdoch097c5b22016-05-18 11:27:45 +01001380 DCHECK_EQ(kAstI32, TypeOf(op->right()));
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001381 if (TypeOf(op->left()) != kAstI32) {
1382 return kToInt;
1383 } else {
1384 return kAsIs;
1385 }
1386 }
1387 }
1388 }
1389 return kNone;
1390 }
1391
1392 ConvertOperation MatchMul(BinaryOperation* expr) {
1393 if (MatchDoubleBinaryOperation(expr, Token::MUL, 1.0)) {
Ben Murdoch097c5b22016-05-18 11:27:45 +01001394 DCHECK_EQ(kAstF64, TypeOf(expr->right()));
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001395 if (TypeOf(expr->left()) != kAstF64) {
1396 return kToDouble;
1397 } else {
1398 return kAsIs;
1399 }
1400 } else {
1401 return kNone;
1402 }
1403 }
1404
1405 ConvertOperation MatchBinaryOperation(BinaryOperation* expr) {
1406 switch (expr->op()) {
1407 case Token::BIT_OR:
1408 return MatchOr(expr);
1409 case Token::SHR:
1410 return MatchShr(expr);
1411 case Token::BIT_XOR:
1412 return MatchXor(expr);
1413 case Token::MUL:
1414 return MatchMul(expr);
1415 default:
1416 return kNone;
1417 }
1418 }
1419
1420// Work around Mul + Div being defined in PPC assembler.
1421#ifdef Mul
1422#undef Mul
1423#endif
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001424
1425#define NON_SIGNED_BINOP(op) \
1426 static WasmOpcode opcodes[] = { \
1427 kExprI32##op, \
1428 kExprI32##op, \
1429 kExprF32##op, \
1430 kExprF64##op \
1431 }
1432
1433#define SIGNED_BINOP(op) \
1434 static WasmOpcode opcodes[] = { \
1435 kExprI32##op##S, \
1436 kExprI32##op##U, \
1437 kExprF32##op, \
1438 kExprF64##op \
1439 }
1440
1441#define NON_SIGNED_INT_BINOP(op) \
1442 static WasmOpcode opcodes[] = { kExprI32##op, kExprI32##op }
1443
1444#define BINOP_CASE(token, op, V, ignore_sign) \
1445 case token: { \
1446 V(op); \
1447 int type = TypeIndexOf(expr->left(), expr->right(), ignore_sign); \
1448 current_function_builder_->Emit(opcodes[type]); \
1449 break; \
1450 }
1451
1452 Expression* GetLeft(BinaryOperation* expr) {
1453 if (expr->op() == Token::BIT_XOR) {
1454 return expr->left()->AsBinaryOperation()->left();
1455 } else {
1456 return expr->left();
1457 }
1458 }
1459
1460 void VisitBinaryOperation(BinaryOperation* expr) {
1461 ConvertOperation convertOperation = MatchBinaryOperation(expr);
1462 if (convertOperation == kToDouble) {
Ben Murdochc5610432016-08-08 18:44:38 +01001463 RECURSE(Visit(expr->left()));
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001464 TypeIndex type = TypeIndexOf(expr->left());
1465 if (type == kInt32 || type == kFixnum) {
1466 current_function_builder_->Emit(kExprF64SConvertI32);
1467 } else if (type == kUint32) {
1468 current_function_builder_->Emit(kExprF64UConvertI32);
1469 } else if (type == kFloat32) {
1470 current_function_builder_->Emit(kExprF64ConvertF32);
1471 } else {
1472 UNREACHABLE();
1473 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001474 } else if (convertOperation == kToInt) {
Ben Murdochc5610432016-08-08 18:44:38 +01001475 RECURSE(Visit(GetLeft(expr)));
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001476 TypeIndex type = TypeIndexOf(GetLeft(expr));
1477 if (type == kFloat32) {
Ben Murdochc5610432016-08-08 18:44:38 +01001478 current_function_builder_->Emit(kExprI32AsmjsSConvertF32);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001479 } else if (type == kFloat64) {
Ben Murdochc5610432016-08-08 18:44:38 +01001480 current_function_builder_->Emit(kExprI32AsmjsSConvertF64);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001481 } else {
1482 UNREACHABLE();
1483 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001484 } else if (convertOperation == kAsIs) {
1485 RECURSE(Visit(GetLeft(expr)));
1486 } else {
Ben Murdochc5610432016-08-08 18:44:38 +01001487 if (expr->op() == Token::COMMA) {
1488 current_function_builder_->Emit(kExprBlock);
1489 }
1490
1491 RECURSE(Visit(expr->left()));
1492 RECURSE(Visit(expr->right()));
1493
1494 if (expr->op() == Token::COMMA) {
1495 current_function_builder_->Emit(kExprEnd);
1496 }
1497
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001498 switch (expr->op()) {
1499 BINOP_CASE(Token::ADD, Add, NON_SIGNED_BINOP, true);
1500 BINOP_CASE(Token::SUB, Sub, NON_SIGNED_BINOP, true);
1501 BINOP_CASE(Token::MUL, Mul, NON_SIGNED_BINOP, true);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001502 BINOP_CASE(Token::BIT_OR, Ior, NON_SIGNED_INT_BINOP, true);
Ben Murdoch097c5b22016-05-18 11:27:45 +01001503 BINOP_CASE(Token::BIT_AND, And, NON_SIGNED_INT_BINOP, true);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001504 BINOP_CASE(Token::BIT_XOR, Xor, NON_SIGNED_INT_BINOP, true);
1505 BINOP_CASE(Token::SHL, Shl, NON_SIGNED_INT_BINOP, true);
1506 BINOP_CASE(Token::SAR, ShrS, NON_SIGNED_INT_BINOP, true);
1507 BINOP_CASE(Token::SHR, ShrU, NON_SIGNED_INT_BINOP, true);
Ben Murdochc5610432016-08-08 18:44:38 +01001508 case Token::DIV: {
1509 static WasmOpcode opcodes[] = {kExprI32AsmjsDivS, kExprI32AsmjsDivU,
1510 kExprF32Div, kExprF64Div};
1511 int type = TypeIndexOf(expr->left(), expr->right(), false);
1512 current_function_builder_->Emit(opcodes[type]);
1513 break;
1514 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001515 case Token::MOD: {
1516 TypeIndex type = TypeIndexOf(expr->left(), expr->right(), false);
1517 if (type == kInt32) {
Ben Murdochc5610432016-08-08 18:44:38 +01001518 current_function_builder_->Emit(kExprI32AsmjsRemS);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001519 } else if (type == kUint32) {
Ben Murdochc5610432016-08-08 18:44:38 +01001520 current_function_builder_->Emit(kExprI32AsmjsRemU);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001521 } else if (type == kFloat64) {
Ben Murdochda12d292016-06-02 14:46:10 +01001522 current_function_builder_->Emit(kExprF64Mod);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001523 return;
1524 } else {
1525 UNREACHABLE();
1526 }
1527 break;
1528 }
Ben Murdoch097c5b22016-05-18 11:27:45 +01001529 case Token::COMMA: {
Ben Murdoch097c5b22016-05-18 11:27:45 +01001530 break;
1531 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001532 default:
1533 UNREACHABLE();
1534 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001535 }
1536 }
1537
1538 void VisitCompareOperation(CompareOperation* expr) {
Ben Murdochc5610432016-08-08 18:44:38 +01001539 RECURSE(Visit(expr->left()));
1540 RECURSE(Visit(expr->right()));
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001541 switch (expr->op()) {
1542 BINOP_CASE(Token::EQ, Eq, NON_SIGNED_BINOP, false);
1543 BINOP_CASE(Token::LT, Lt, SIGNED_BINOP, false);
1544 BINOP_CASE(Token::LTE, Le, SIGNED_BINOP, false);
1545 BINOP_CASE(Token::GT, Gt, SIGNED_BINOP, false);
1546 BINOP_CASE(Token::GTE, Ge, SIGNED_BINOP, false);
1547 default:
1548 UNREACHABLE();
1549 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001550 }
1551
1552#undef BINOP_CASE
1553#undef NON_SIGNED_INT_BINOP
1554#undef SIGNED_BINOP
1555#undef NON_SIGNED_BINOP
1556
1557 enum TypeIndex {
1558 kInt32 = 0,
1559 kUint32 = 1,
1560 kFloat32 = 2,
1561 kFloat64 = 3,
1562 kFixnum = 4
1563 };
1564
1565 TypeIndex TypeIndexOf(Expression* left, Expression* right, bool ignore_sign) {
1566 TypeIndex left_index = TypeIndexOf(left);
1567 TypeIndex right_index = TypeIndexOf(right);
1568 if (left_index == kFixnum) {
1569 left_index = right_index;
1570 }
1571 if (right_index == kFixnum) {
1572 right_index = left_index;
1573 }
1574 if (left_index == kFixnum && right_index == kFixnum) {
1575 left_index = kInt32;
1576 right_index = kInt32;
1577 }
1578 DCHECK((left_index == right_index) ||
1579 (ignore_sign && (left_index <= 1) && (right_index <= 1)));
1580 return left_index;
1581 }
1582
1583 TypeIndex TypeIndexOf(Expression* expr) {
Ben Murdochc5610432016-08-08 18:44:38 +01001584 DCHECK_EQ(bounds_->get(expr).lower, bounds_->get(expr).upper);
1585 Type* type = bounds_->get(expr).lower;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001586 if (type->Is(cache_.kAsmFixnum)) {
1587 return kFixnum;
1588 } else if (type->Is(cache_.kAsmSigned)) {
1589 return kInt32;
1590 } else if (type->Is(cache_.kAsmUnsigned)) {
1591 return kUint32;
1592 } else if (type->Is(cache_.kAsmInt)) {
1593 return kInt32;
1594 } else if (type->Is(cache_.kAsmFloat)) {
1595 return kFloat32;
1596 } else if (type->Is(cache_.kAsmDouble)) {
1597 return kFloat64;
1598 } else {
1599 UNREACHABLE();
1600 return kInt32;
1601 }
1602 }
1603
1604#undef CASE
1605#undef NON_SIGNED_INT
1606#undef SIGNED
1607#undef NON_SIGNED
1608
1609 void VisitThisFunction(ThisFunction* expr) { UNREACHABLE(); }
1610
1611 void VisitDeclarations(ZoneList<Declaration*>* decls) {
1612 for (int i = 0; i < decls->length(); ++i) {
1613 Declaration* decl = decls->at(i);
1614 RECURSE(Visit(decl));
1615 }
1616 }
1617
1618 void VisitClassLiteral(ClassLiteral* expr) { UNREACHABLE(); }
1619
1620 void VisitSpread(Spread* expr) { UNREACHABLE(); }
1621
1622 void VisitSuperPropertyReference(SuperPropertyReference* expr) {
1623 UNREACHABLE();
1624 }
1625
1626 void VisitSuperCallReference(SuperCallReference* expr) { UNREACHABLE(); }
1627
1628 void VisitSloppyBlockFunctionStatement(SloppyBlockFunctionStatement* expr) {
1629 UNREACHABLE();
1630 }
1631
1632 void VisitDoExpression(DoExpression* expr) { UNREACHABLE(); }
1633
Ben Murdoch097c5b22016-05-18 11:27:45 +01001634 void VisitRewritableExpression(RewritableExpression* expr) { UNREACHABLE(); }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001635
1636 struct IndexContainer : public ZoneObject {
Ben Murdochc5610432016-08-08 18:44:38 +01001637 uint32_t index;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001638 };
1639
Ben Murdochc5610432016-08-08 18:44:38 +01001640 uint32_t LookupOrInsertLocal(Variable* v, LocalType type) {
Ben Murdoch097c5b22016-05-18 11:27:45 +01001641 DCHECK_NOT_NULL(current_function_builder_);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001642 ZoneHashMap::Entry* entry =
1643 local_variables_.Lookup(v, ComputePointerHash(v));
1644 if (entry == nullptr) {
Ben Murdochc5610432016-08-08 18:44:38 +01001645 uint32_t index;
1646 DCHECK(!v->IsParameter());
1647 index = current_function_builder_->AddLocal(type);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001648 IndexContainer* container = new (zone()) IndexContainer();
1649 container->index = index;
1650 entry = local_variables_.LookupOrInsert(v, ComputePointerHash(v),
1651 ZoneAllocationPolicy(zone()));
1652 entry->value = container;
1653 }
1654 return (reinterpret_cast<IndexContainer*>(entry->value))->index;
1655 }
1656
Ben Murdochc5610432016-08-08 18:44:38 +01001657 void InsertParameter(Variable* v, LocalType type, uint32_t index) {
1658 DCHECK(v->IsParameter());
1659 DCHECK_NOT_NULL(current_function_builder_);
1660 ZoneHashMap::Entry* entry =
1661 local_variables_.Lookup(v, ComputePointerHash(v));
1662 DCHECK_NULL(entry);
1663 IndexContainer* container = new (zone()) IndexContainer();
1664 container->index = index;
1665 entry = local_variables_.LookupOrInsert(v, ComputePointerHash(v),
1666 ZoneAllocationPolicy(zone()));
1667 entry->value = container;
1668 }
1669
1670 uint32_t LookupOrInsertGlobal(Variable* v, LocalType type) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001671 ZoneHashMap::Entry* entry =
1672 global_variables_.Lookup(v, ComputePointerHash(v));
1673 if (entry == nullptr) {
Ben Murdochc5610432016-08-08 18:44:38 +01001674 uint32_t index =
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001675 builder_->AddGlobal(WasmOpcodes::MachineTypeFor(type), 0);
1676 IndexContainer* container = new (zone()) IndexContainer();
1677 container->index = index;
1678 entry = global_variables_.LookupOrInsert(v, ComputePointerHash(v),
1679 ZoneAllocationPolicy(zone()));
1680 entry->value = container;
1681 }
1682 return (reinterpret_cast<IndexContainer*>(entry->value))->index;
1683 }
1684
Ben Murdochc5610432016-08-08 18:44:38 +01001685 uint32_t LookupOrInsertFunction(Variable* v) {
Ben Murdoch097c5b22016-05-18 11:27:45 +01001686 DCHECK_NOT_NULL(builder_);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001687 ZoneHashMap::Entry* entry = functions_.Lookup(v, ComputePointerHash(v));
1688 if (entry == nullptr) {
Ben Murdochc5610432016-08-08 18:44:38 +01001689 uint32_t index = builder_->AddFunction();
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001690 IndexContainer* container = new (zone()) IndexContainer();
1691 container->index = index;
1692 entry = functions_.LookupOrInsert(v, ComputePointerHash(v),
1693 ZoneAllocationPolicy(zone()));
1694 entry->value = container;
1695 }
1696 return (reinterpret_cast<IndexContainer*>(entry->value))->index;
1697 }
1698
1699 LocalType TypeOf(Expression* expr) {
Ben Murdochc5610432016-08-08 18:44:38 +01001700 DCHECK_EQ(bounds_->get(expr).lower, bounds_->get(expr).upper);
1701 return TypeFrom(bounds_->get(expr).lower);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001702 }
1703
Ben Murdoch097c5b22016-05-18 11:27:45 +01001704 LocalType TypeFrom(Type* type) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001705 if (type->Is(cache_.kAsmInt)) {
1706 return kAstI32;
1707 } else if (type->Is(cache_.kAsmFloat)) {
1708 return kAstF32;
1709 } else if (type->Is(cache_.kAsmDouble)) {
1710 return kAstF64;
1711 } else {
1712 return kAstStmt;
1713 }
1714 }
1715
1716 Zone* zone() { return zone_; }
1717
1718 ZoneHashMap local_variables_;
1719 ZoneHashMap functions_;
1720 ZoneHashMap global_variables_;
Ben Murdochc5610432016-08-08 18:44:38 +01001721 AsmScope scope_;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001722 WasmModuleBuilder* builder_;
1723 WasmFunctionBuilder* current_function_builder_;
1724 FunctionLiteral* literal_;
1725 Isolate* isolate_;
1726 Zone* zone_;
Ben Murdoch097c5b22016-05-18 11:27:45 +01001727 Handle<Object> foreign_;
Ben Murdochda12d292016-06-02 14:46:10 +01001728 AsmTyper* typer_;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001729 TypeCache const& cache_;
1730 ZoneVector<std::pair<BreakableStatement*, bool>> breakable_blocks_;
Ben Murdochc5610432016-08-08 18:44:38 +01001731 uint32_t init_function_index_;
Ben Murdoch097c5b22016-05-18 11:27:45 +01001732 uint32_t next_table_index_;
1733 ZoneHashMap function_tables_;
1734 ImportedFunctionTable imported_function_table_;
Ben Murdochc5610432016-08-08 18:44:38 +01001735 const AstTypeBounds* bounds_;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001736
1737 DEFINE_AST_VISITOR_SUBCLASS_MEMBERS();
1738
1739 private:
1740 DISALLOW_COPY_AND_ASSIGN(AsmWasmBuilderImpl);
1741};
1742
1743AsmWasmBuilder::AsmWasmBuilder(Isolate* isolate, Zone* zone,
Ben Murdochda12d292016-06-02 14:46:10 +01001744 FunctionLiteral* literal, Handle<Object> foreign,
1745 AsmTyper* typer)
1746 : isolate_(isolate),
1747 zone_(zone),
1748 literal_(literal),
1749 foreign_(foreign),
1750 typer_(typer) {}
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001751
1752// TODO(aseemgarg): probably should take zone (to write wasm to) as input so
1753// that zone in constructor may be thrown away once wasm module is written.
1754WasmModuleIndex* AsmWasmBuilder::Run() {
Ben Murdochda12d292016-06-02 14:46:10 +01001755 AsmWasmBuilderImpl impl(isolate_, zone_, literal_, foreign_, typer_);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001756 impl.Compile();
1757 WasmModuleWriter* writer = impl.builder_->Build(zone_);
1758 return writer->WriteTo(zone_);
1759}
1760} // namespace wasm
1761} // namespace internal
1762} // namespace v8