blob: d16d3a8bdd308e6aef95cb5c99cece7e34b73132 [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"
14#include "src/wasm/wasm-macro-gen.h"
15#include "src/wasm/wasm-opcodes.h"
16
17#include "src/ast/ast.h"
18#include "src/ast/scopes.h"
19#include "src/codegen.h"
20#include "src/type-cache.h"
21
22namespace v8 {
23namespace internal {
24namespace wasm {
25
26#define RECURSE(call) \
27 do { \
28 DCHECK(!HasStackOverflow()); \
29 call; \
30 if (HasStackOverflow()) return; \
31 } while (false)
32
33
34class AsmWasmBuilderImpl : public AstVisitor {
35 public:
Ben Murdoch097c5b22016-05-18 11:27:45 +010036 AsmWasmBuilderImpl(Isolate* isolate, Zone* zone, FunctionLiteral* literal,
Ben Murdochda12d292016-06-02 14:46:10 +010037 Handle<Object> foreign, AsmTyper* typer)
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000038 : local_variables_(HashMap::PointersMatch,
39 ZoneHashMap::kDefaultHashMapCapacity,
40 ZoneAllocationPolicy(zone)),
41 functions_(HashMap::PointersMatch, ZoneHashMap::kDefaultHashMapCapacity,
42 ZoneAllocationPolicy(zone)),
43 global_variables_(HashMap::PointersMatch,
44 ZoneHashMap::kDefaultHashMapCapacity,
45 ZoneAllocationPolicy(zone)),
46 in_function_(false),
47 is_set_op_(false),
48 marking_exported(false),
49 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),
58 block_size_(0),
Ben Murdoch097c5b22016-05-18 11:27:45 +010059 init_function_index_(0),
60 next_table_index_(0),
61 function_tables_(HashMap::PointersMatch,
62 ZoneHashMap::kDefaultHashMapCapacity,
63 ZoneAllocationPolicy(zone)),
64 imported_function_table_(this) {
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();
70 current_function_builder_ = builder_->FunctionAt(init_function_index_);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000071 current_function_builder_->ReturnType(kAstStmt);
Ben Murdochda12d292016-06-02 14:46:10 +010072 builder_->MarkStartFunction(init_function_index_);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000073 current_function_builder_ = nullptr;
74 }
75
76 void Compile() {
77 InitializeInitFunction();
78 RECURSE(VisitFunctionLiteral(literal_));
79 }
80
81 void VisitVariableDeclaration(VariableDeclaration* decl) {}
82
83 void VisitFunctionDeclaration(FunctionDeclaration* decl) {
84 DCHECK(!in_function_);
Ben Murdoch097c5b22016-05-18 11:27:45 +010085 DCHECK_NULL(current_function_builder_);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000086 uint16_t index = LookupOrInsertFunction(decl->proxy()->var());
87 current_function_builder_ = builder_->FunctionAt(index);
88 in_function_ = true;
89 RECURSE(Visit(decl->fun()));
90 in_function_ = false;
91 current_function_builder_ = nullptr;
92 local_variables_.Clear();
93 }
94
95 void VisitImportDeclaration(ImportDeclaration* decl) {}
96
97 void VisitExportDeclaration(ExportDeclaration* decl) {}
98
99 void VisitStatements(ZoneList<Statement*>* stmts) {
100 for (int i = 0; i < stmts->length(); ++i) {
101 Statement* stmt = stmts->at(i);
102 RECURSE(Visit(stmt));
103 if (stmt->IsJump()) break;
104 }
105 }
106
107 void VisitBlock(Block* stmt) {
108 if (stmt->statements()->length() == 1) {
109 ExpressionStatement* expr =
110 stmt->statements()->at(0)->AsExpressionStatement();
111 if (expr != nullptr) {
112 if (expr->expression()->IsAssignment()) {
113 RECURSE(VisitExpressionStatement(expr));
114 return;
115 }
116 }
117 }
Ben Murdoch097c5b22016-05-18 11:27:45 +0100118 if (in_function_) {
119 BlockVisitor visitor(this, stmt->AsBreakableStatement(), kExprBlock,
120 false,
121 static_cast<byte>(stmt->statements()->length()));
122 RECURSE(VisitStatements(stmt->statements()));
123 DCHECK(block_size_ >= 0);
124 } else {
125 RECURSE(VisitStatements(stmt->statements()));
126 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000127 }
128
129 class BlockVisitor {
130 private:
131 int prev_block_size_;
132 uint32_t index_;
133 AsmWasmBuilderImpl* builder_;
134
135 public:
136 BlockVisitor(AsmWasmBuilderImpl* builder, BreakableStatement* stmt,
137 WasmOpcode opcode, bool is_loop, int initial_block_size)
138 : builder_(builder) {
139 builder_->breakable_blocks_.push_back(std::make_pair(stmt, is_loop));
140 builder_->current_function_builder_->Emit(opcode);
Ben Murdochda12d292016-06-02 14:46:10 +0100141 index_ =
142 builder_->current_function_builder_->EmitEditableVarIntImmediate();
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000143 prev_block_size_ = builder_->block_size_;
144 builder_->block_size_ = initial_block_size;
145 }
146 ~BlockVisitor() {
Ben Murdochda12d292016-06-02 14:46:10 +0100147 builder_->current_function_builder_->EditVarIntImmediate(
148 index_, builder_->block_size_);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000149 builder_->block_size_ = prev_block_size_;
150 builder_->breakable_blocks_.pop_back();
151 }
152 };
153
154 void VisitExpressionStatement(ExpressionStatement* stmt) {
155 RECURSE(Visit(stmt->expression()));
156 }
157
158 void VisitEmptyStatement(EmptyStatement* stmt) {}
159
160 void VisitEmptyParentheses(EmptyParentheses* paren) { UNREACHABLE(); }
161
162 void VisitIfStatement(IfStatement* stmt) {
163 DCHECK(in_function_);
164 if (stmt->HasElseStatement()) {
165 current_function_builder_->Emit(kExprIfElse);
166 } else {
167 current_function_builder_->Emit(kExprIf);
168 }
169 RECURSE(Visit(stmt->condition()));
170 if (stmt->HasThenStatement()) {
171 RECURSE(Visit(stmt->then_statement()));
172 } else {
173 current_function_builder_->Emit(kExprNop);
174 }
175 if (stmt->HasElseStatement()) {
176 RECURSE(Visit(stmt->else_statement()));
177 }
178 }
179
180 void VisitContinueStatement(ContinueStatement* stmt) {
181 DCHECK(in_function_);
Ben Murdoch097c5b22016-05-18 11:27:45 +0100182 DCHECK_NOT_NULL(stmt->target());
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000183 int i = static_cast<int>(breakable_blocks_.size()) - 1;
184 int block_distance = 0;
185 for (; i >= 0; i--) {
186 auto elem = breakable_blocks_.at(i);
187 if (elem.first == stmt->target()) {
188 DCHECK(elem.second);
189 break;
190 } else if (elem.second) {
191 block_distance += 2;
192 } else {
193 block_distance += 1;
194 }
195 }
196 DCHECK(i >= 0);
Ben Murdochda12d292016-06-02 14:46:10 +0100197 current_function_builder_->EmitWithVarInt(kExprBr, block_distance);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000198 current_function_builder_->Emit(kExprNop);
199 }
200
201 void VisitBreakStatement(BreakStatement* stmt) {
202 DCHECK(in_function_);
Ben Murdoch097c5b22016-05-18 11:27:45 +0100203 DCHECK_NOT_NULL(stmt->target());
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000204 int i = static_cast<int>(breakable_blocks_.size()) - 1;
205 int block_distance = 0;
206 for (; i >= 0; i--) {
207 auto elem = breakable_blocks_.at(i);
208 if (elem.first == stmt->target()) {
209 if (elem.second) {
210 block_distance++;
211 }
212 break;
213 } else if (elem.second) {
214 block_distance += 2;
215 } else {
216 block_distance += 1;
217 }
218 }
219 DCHECK(i >= 0);
Ben Murdochda12d292016-06-02 14:46:10 +0100220 current_function_builder_->EmitWithVarInt(kExprBr, block_distance);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000221 current_function_builder_->Emit(kExprNop);
222 }
223
224 void VisitReturnStatement(ReturnStatement* stmt) {
225 if (in_function_) {
226 current_function_builder_->Emit(kExprReturn);
227 } else {
228 marking_exported = true;
229 }
230 RECURSE(Visit(stmt->expression()));
231 if (!in_function_) {
232 marking_exported = false;
233 }
234 }
235
236 void VisitWithStatement(WithStatement* stmt) { UNREACHABLE(); }
237
238 void SetLocalTo(uint16_t index, int value) {
239 current_function_builder_->Emit(kExprSetLocal);
240 AddLeb128(index, true);
Ben Murdochda12d292016-06-02 14:46:10 +0100241 // TODO(bradnelson): variable size
242 byte code[] = {WASM_I32V(value)};
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000243 current_function_builder_->EmitCode(code, sizeof(code));
244 block_size_++;
245 }
246
247 void CompileCase(CaseClause* clause, uint16_t fall_through,
248 VariableProxy* tag) {
249 Literal* label = clause->label()->AsLiteral();
Ben Murdoch097c5b22016-05-18 11:27:45 +0100250 DCHECK_NOT_NULL(label);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000251 block_size_++;
252 current_function_builder_->Emit(kExprIf);
253 current_function_builder_->Emit(kExprI32Ior);
254 current_function_builder_->Emit(kExprI32Eq);
255 VisitVariableProxy(tag);
256 VisitLiteral(label);
257 current_function_builder_->Emit(kExprGetLocal);
258 AddLeb128(fall_through, true);
259 BlockVisitor visitor(this, nullptr, kExprBlock, false, 0);
260 SetLocalTo(fall_through, 1);
261 ZoneList<Statement*>* stmts = clause->statements();
262 block_size_ += stmts->length();
263 RECURSE(VisitStatements(stmts));
264 }
265
266 void VisitSwitchStatement(SwitchStatement* stmt) {
267 VariableProxy* tag = stmt->tag()->AsVariableProxy();
Ben Murdoch097c5b22016-05-18 11:27:45 +0100268 DCHECK_NOT_NULL(tag);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000269 BlockVisitor visitor(this, stmt->AsBreakableStatement(), kExprBlock, false,
270 0);
271 uint16_t fall_through = current_function_builder_->AddLocal(kAstI32);
272 SetLocalTo(fall_through, 0);
273
274 ZoneList<CaseClause*>* clauses = stmt->cases();
275 for (int i = 0; i < clauses->length(); ++i) {
276 CaseClause* clause = clauses->at(i);
277 if (!clause->is_default()) {
278 CompileCase(clause, fall_through, tag);
279 } else {
280 ZoneList<Statement*>* stmts = clause->statements();
281 block_size_ += stmts->length();
282 RECURSE(VisitStatements(stmts));
283 }
284 }
285 }
286
287 void VisitCaseClause(CaseClause* clause) { UNREACHABLE(); }
288
289 void VisitDoWhileStatement(DoWhileStatement* stmt) {
290 DCHECK(in_function_);
291 BlockVisitor visitor(this, stmt->AsBreakableStatement(), kExprLoop, true,
292 2);
293 RECURSE(Visit(stmt->body()));
294 current_function_builder_->Emit(kExprIf);
295 RECURSE(Visit(stmt->cond()));
Ben Murdochda12d292016-06-02 14:46:10 +0100296 current_function_builder_->EmitWithVarInt(kExprBr, 0);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000297 current_function_builder_->Emit(kExprNop);
298 }
299
300 void VisitWhileStatement(WhileStatement* stmt) {
301 DCHECK(in_function_);
302 BlockVisitor visitor(this, stmt->AsBreakableStatement(), kExprLoop, true,
303 1);
304 current_function_builder_->Emit(kExprIf);
305 RECURSE(Visit(stmt->cond()));
Ben Murdochda12d292016-06-02 14:46:10 +0100306 current_function_builder_->EmitWithVarInt(kExprBr, 0);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000307 RECURSE(Visit(stmt->body()));
308 }
309
310 void VisitForStatement(ForStatement* stmt) {
311 DCHECK(in_function_);
312 if (stmt->init() != nullptr) {
313 block_size_++;
314 RECURSE(Visit(stmt->init()));
315 }
316 BlockVisitor visitor(this, stmt->AsBreakableStatement(), kExprLoop, true,
317 0);
318 if (stmt->cond() != nullptr) {
319 block_size_++;
320 current_function_builder_->Emit(kExprIf);
Ben Murdochda12d292016-06-02 14:46:10 +0100321 current_function_builder_->Emit(kExprI32Eqz);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000322 RECURSE(Visit(stmt->cond()));
Ben Murdochda12d292016-06-02 14:46:10 +0100323 current_function_builder_->EmitWithVarInt(kExprBr, 1);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000324 current_function_builder_->Emit(kExprNop);
325 }
326 if (stmt->body() != nullptr) {
327 block_size_++;
328 RECURSE(Visit(stmt->body()));
329 }
330 if (stmt->next() != nullptr) {
331 block_size_++;
332 RECURSE(Visit(stmt->next()));
333 }
334 block_size_++;
Ben Murdochda12d292016-06-02 14:46:10 +0100335 current_function_builder_->EmitWithVarInt(kExprBr, 0);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000336 current_function_builder_->Emit(kExprNop);
337 }
338
339 void VisitForInStatement(ForInStatement* stmt) { UNREACHABLE(); }
340
341 void VisitForOfStatement(ForOfStatement* stmt) { UNREACHABLE(); }
342
343 void VisitTryCatchStatement(TryCatchStatement* stmt) { UNREACHABLE(); }
344
345 void VisitTryFinallyStatement(TryFinallyStatement* stmt) { UNREACHABLE(); }
346
347 void VisitDebuggerStatement(DebuggerStatement* stmt) { UNREACHABLE(); }
348
349 void VisitFunctionLiteral(FunctionLiteral* expr) {
350 Scope* scope = expr->scope();
351 if (in_function_) {
352 if (expr->bounds().lower->IsFunction()) {
Ben Murdoch097c5b22016-05-18 11:27:45 +0100353 FunctionType* func_type = expr->bounds().lower->AsFunction();
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000354 LocalType return_type = TypeFrom(func_type->Result());
355 current_function_builder_->ReturnType(return_type);
356 for (int i = 0; i < expr->parameter_count(); i++) {
357 LocalType type = TypeFrom(func_type->Parameter(i));
Ben Murdoch097c5b22016-05-18 11:27:45 +0100358 DCHECK_NE(kAstStmt, type);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000359 LookupOrInsertLocal(scope->parameter(i), type);
360 }
361 } else {
362 UNREACHABLE();
363 }
364 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000365 RECURSE(VisitStatements(expr->body()));
Ben Murdoch097c5b22016-05-18 11:27:45 +0100366 RECURSE(VisitDeclarations(scope->declarations()));
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000367 }
368
369 void VisitNativeFunctionLiteral(NativeFunctionLiteral* expr) {
370 UNREACHABLE();
371 }
372
373 void VisitConditional(Conditional* expr) {
374 DCHECK(in_function_);
375 current_function_builder_->Emit(kExprIfElse);
376 RECURSE(Visit(expr->condition()));
377 RECURSE(Visit(expr->then_expression()));
378 RECURSE(Visit(expr->else_expression()));
379 }
380
Ben Murdochda12d292016-06-02 14:46:10 +0100381 bool VisitStdlibConstant(Variable* var) {
382 AsmTyper::StandardMember standard_object =
383 typer_->VariableAsStandardMember(var);
384 double value;
385 switch (standard_object) {
386 case AsmTyper::kInfinity: {
387 value = std::numeric_limits<double>::infinity();
388 break;
389 }
390 case AsmTyper::kNaN: {
391 value = std::numeric_limits<double>::quiet_NaN();
392 break;
393 }
394 case AsmTyper::kMathE: {
395 value = M_E;
396 break;
397 }
398 case AsmTyper::kMathLN10: {
399 value = M_LN10;
400 break;
401 }
402 case AsmTyper::kMathLN2: {
403 value = M_LN2;
404 break;
405 }
406 case AsmTyper::kMathLOG10E: {
407 value = M_LOG10E;
408 break;
409 }
410 case AsmTyper::kMathLOG2E: {
411 value = M_LOG2E;
412 break;
413 }
414 case AsmTyper::kMathPI: {
415 value = M_PI;
416 break;
417 }
418 case AsmTyper::kMathSQRT1_2: {
419 value = M_SQRT1_2;
420 break;
421 }
422 case AsmTyper::kMathSQRT2: {
423 value = M_SQRT2;
424 break;
425 }
426 default: { return false; }
427 }
428 byte code[] = {WASM_F64(value)};
429 current_function_builder_->EmitCode(code, sizeof(code));
430 return true;
431 }
432
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000433 void VisitVariableProxy(VariableProxy* expr) {
434 if (in_function_) {
435 Variable* var = expr->var();
Ben Murdoch097c5b22016-05-18 11:27:45 +0100436 if (is_set_op_) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000437 if (var->IsContextSlot()) {
Ben Murdoch097c5b22016-05-18 11:27:45 +0100438 current_function_builder_->Emit(kExprStoreGlobal);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000439 } else {
Ben Murdoch097c5b22016-05-18 11:27:45 +0100440 current_function_builder_->Emit(kExprSetLocal);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000441 }
Ben Murdoch097c5b22016-05-18 11:27:45 +0100442 is_set_op_ = false;
443 } else {
Ben Murdochda12d292016-06-02 14:46:10 +0100444 if (VisitStdlibConstant(var)) {
445 return;
446 }
Ben Murdoch097c5b22016-05-18 11:27:45 +0100447 if (var->IsContextSlot()) {
448 current_function_builder_->Emit(kExprLoadGlobal);
449 } else {
450 current_function_builder_->Emit(kExprGetLocal);
451 }
452 }
453 LocalType var_type = TypeOf(expr);
454 DCHECK_NE(kAstStmt, var_type);
455 if (var->IsContextSlot()) {
456 AddLeb128(LookupOrInsertGlobal(var, var_type), false);
457 } else {
458 AddLeb128(LookupOrInsertLocal(var, var_type), true);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000459 }
460 }
461 }
462
463 void VisitLiteral(Literal* expr) {
Ben Murdochda12d292016-06-02 14:46:10 +0100464 Handle<Object> value = expr->value();
465 if (!in_function_ || !value->IsNumber()) {
466 return;
467 }
468 Type* type = expr->bounds().upper;
469 if (type->Is(cache_.kAsmSigned)) {
470 int32_t i = 0;
471 if (!value->ToInt32(&i)) {
472 UNREACHABLE();
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000473 }
Ben Murdochda12d292016-06-02 14:46:10 +0100474 byte code[] = {WASM_I32V(i)};
475 current_function_builder_->EmitCode(code, sizeof(code));
476 } else if (type->Is(cache_.kAsmUnsigned) || type->Is(cache_.kAsmFixnum)) {
477 uint32_t u = 0;
478 if (!value->ToUint32(&u)) {
479 UNREACHABLE();
480 }
481 int32_t i = static_cast<int32_t>(u);
482 byte code[] = {WASM_I32V(i)};
483 current_function_builder_->EmitCode(code, sizeof(code));
484 } else if (type->Is(cache_.kAsmDouble)) {
485 double val = expr->raw_value()->AsNumber();
486 byte code[] = {WASM_F64(val)};
487 current_function_builder_->EmitCode(code, sizeof(code));
488 } else {
489 UNREACHABLE();
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000490 }
491 }
492
493 void VisitRegExpLiteral(RegExpLiteral* expr) { UNREACHABLE(); }
494
495 void VisitObjectLiteral(ObjectLiteral* expr) {
496 ZoneList<ObjectLiteralProperty*>* props = expr->properties();
497 for (int i = 0; i < props->length(); ++i) {
498 ObjectLiteralProperty* prop = props->at(i);
499 DCHECK(marking_exported);
500 VariableProxy* expr = prop->value()->AsVariableProxy();
Ben Murdoch097c5b22016-05-18 11:27:45 +0100501 DCHECK_NOT_NULL(expr);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000502 Variable* var = expr->var();
503 Literal* name = prop->key()->AsLiteral();
Ben Murdoch097c5b22016-05-18 11:27:45 +0100504 DCHECK_NOT_NULL(name);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000505 DCHECK(name->IsPropertyName());
506 const AstRawString* raw_name = name->AsRawPropertyName();
507 if (var->is_function()) {
508 uint16_t index = LookupOrInsertFunction(var);
509 builder_->FunctionAt(index)->Exported(1);
510 builder_->FunctionAt(index)
511 ->SetName(raw_name->raw_data(), raw_name->length());
512 }
513 }
514 }
515
516 void VisitArrayLiteral(ArrayLiteral* expr) { UNREACHABLE(); }
517
518 void LoadInitFunction() {
Ben Murdoch097c5b22016-05-18 11:27:45 +0100519 current_function_builder_ = builder_->FunctionAt(init_function_index_);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000520 in_function_ = true;
521 }
522
523 void UnLoadInitFunction() {
524 in_function_ = false;
525 current_function_builder_ = nullptr;
526 }
527
Ben Murdoch097c5b22016-05-18 11:27:45 +0100528 void AddFunctionTable(VariableProxy* table, ArrayLiteral* funcs) {
529 FunctionType* func_type =
530 funcs->bounds().lower->AsArray()->Element()->AsFunction();
531 LocalType return_type = TypeFrom(func_type->Result());
532 FunctionSig::Builder sig(zone(), return_type == kAstStmt ? 0 : 1,
533 func_type->Arity());
534 if (return_type != kAstStmt) {
535 sig.AddReturn(static_cast<LocalType>(return_type));
536 }
537 for (int i = 0; i < func_type->Arity(); i++) {
538 sig.AddParam(TypeFrom(func_type->Parameter(i)));
539 }
540 uint16_t signature_index = builder_->AddSignature(sig.Build());
541 InsertFunctionTable(table->var(), next_table_index_, signature_index);
542 next_table_index_ += funcs->values()->length();
543 for (int i = 0; i < funcs->values()->length(); i++) {
544 VariableProxy* func = funcs->values()->at(i)->AsVariableProxy();
545 DCHECK_NOT_NULL(func);
546 builder_->AddIndirectFunction(LookupOrInsertFunction(func->var()));
547 }
548 }
549
550 struct FunctionTableIndices : public ZoneObject {
551 uint32_t start_index;
552 uint16_t signature_index;
553 };
554
555 void InsertFunctionTable(Variable* v, uint32_t start_index,
556 uint16_t signature_index) {
557 FunctionTableIndices* container = new (zone()) FunctionTableIndices();
558 container->start_index = start_index;
559 container->signature_index = signature_index;
560 ZoneHashMap::Entry* entry = function_tables_.LookupOrInsert(
561 v, ComputePointerHash(v), ZoneAllocationPolicy(zone()));
562 entry->value = container;
563 }
564
565 FunctionTableIndices* LookupFunctionTable(Variable* v) {
566 ZoneHashMap::Entry* entry =
567 function_tables_.Lookup(v, ComputePointerHash(v));
568 DCHECK_NOT_NULL(entry);
569 return reinterpret_cast<FunctionTableIndices*>(entry->value);
570 }
571
572 class ImportedFunctionTable {
573 private:
574 class ImportedFunctionIndices : public ZoneObject {
575 public:
576 const unsigned char* name_;
577 int name_length_;
578 WasmModuleBuilder::SignatureMap signature_to_index_;
579
580 ImportedFunctionIndices(const unsigned char* name, int name_length,
581 Zone* zone)
582 : name_(name), name_length_(name_length), signature_to_index_(zone) {}
583 };
584 ZoneHashMap table_;
585 AsmWasmBuilderImpl* builder_;
586
587 public:
588 explicit ImportedFunctionTable(AsmWasmBuilderImpl* builder)
589 : table_(HashMap::PointersMatch, ZoneHashMap::kDefaultHashMapCapacity,
590 ZoneAllocationPolicy(builder->zone())),
591 builder_(builder) {}
592
593 void AddImport(Variable* v, const unsigned char* name, int name_length) {
594 ImportedFunctionIndices* indices = new (builder_->zone())
595 ImportedFunctionIndices(name, name_length, builder_->zone());
596 ZoneHashMap::Entry* entry = table_.LookupOrInsert(
597 v, ComputePointerHash(v), ZoneAllocationPolicy(builder_->zone()));
598 entry->value = indices;
599 }
600
601 uint16_t GetFunctionIndex(Variable* v, FunctionSig* sig) {
602 ZoneHashMap::Entry* entry = table_.Lookup(v, ComputePointerHash(v));
603 DCHECK_NOT_NULL(entry);
604 ImportedFunctionIndices* indices =
605 reinterpret_cast<ImportedFunctionIndices*>(entry->value);
606 WasmModuleBuilder::SignatureMap::iterator pos =
607 indices->signature_to_index_.find(sig);
608 if (pos != indices->signature_to_index_.end()) {
609 return pos->second;
610 } else {
611 uint16_t index = builder_->builder_->AddFunction();
612 indices->signature_to_index_[sig] = index;
613 WasmFunctionBuilder* function = builder_->builder_->FunctionAt(index);
614 function->External(1);
615 function->SetName(indices->name_, indices->name_length_);
616 if (sig->return_count() > 0) {
617 function->ReturnType(sig->GetReturn());
618 }
619 for (size_t i = 0; i < sig->parameter_count(); i++) {
620 function->AddParam(sig->GetParam(i));
621 }
622 return index;
623 }
624 }
625 };
626
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000627 void VisitAssignment(Assignment* expr) {
628 bool in_init = false;
629 if (!in_function_) {
Ben Murdoch097c5b22016-05-18 11:27:45 +0100630 BinaryOperation* binop = expr->value()->AsBinaryOperation();
631 if (binop != nullptr) {
632 Property* prop = binop->left()->AsProperty();
633 DCHECK_NOT_NULL(prop);
634 LoadInitFunction();
635 is_set_op_ = true;
636 RECURSE(Visit(expr->target()));
637 DCHECK(!is_set_op_);
638 if (binop->op() == Token::MUL) {
639 DCHECK(binop->right()->IsLiteral());
640 DCHECK_EQ(1.0, binop->right()->AsLiteral()->raw_value()->AsNumber());
641 DCHECK(binop->right()->AsLiteral()->raw_value()->ContainsDot());
642 VisitForeignVariable(true, prop);
643 } else if (binop->op() == Token::BIT_OR) {
644 DCHECK(binop->right()->IsLiteral());
645 DCHECK_EQ(0.0, binop->right()->AsLiteral()->raw_value()->AsNumber());
646 DCHECK(!binop->right()->AsLiteral()->raw_value()->ContainsDot());
647 VisitForeignVariable(false, prop);
648 } else {
649 UNREACHABLE();
650 }
651 UnLoadInitFunction();
652 return;
653 }
Ben Murdochda12d292016-06-02 14:46:10 +0100654 Property* prop = expr->value()->AsProperty();
655 if (prop != nullptr) {
656 VariableProxy* vp = prop->obj()->AsVariableProxy();
657 if (vp != nullptr && vp->var()->IsParameter() &&
658 vp->var()->index() == 1) {
659 VariableProxy* target = expr->target()->AsVariableProxy();
660 if (target->bounds().lower->Is(Type::Function())) {
661 const AstRawString* name =
662 prop->key()->AsLiteral()->AsRawPropertyName();
663 imported_function_table_.AddImport(target->var(), name->raw_data(),
664 name->length());
Ben Murdoch097c5b22016-05-18 11:27:45 +0100665 }
666 }
Ben Murdochda12d292016-06-02 14:46:10 +0100667 // Property values in module scope don't emit code, so return.
668 return;
669 }
670 ArrayLiteral* funcs = expr->value()->AsArrayLiteral();
671 if (funcs != nullptr &&
672 funcs->bounds().lower->AsArray()->Element()->IsFunction()) {
673 VariableProxy* target = expr->target()->AsVariableProxy();
674 DCHECK_NOT_NULL(target);
675 AddFunctionTable(target, funcs);
676 // Only add to the function table. No init needed.
677 return;
678 }
679 if (expr->value()->IsCallNew()) {
680 // No init code to emit for CallNew nodes.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000681 return;
682 }
683 in_init = true;
684 LoadInitFunction();
685 }
686 BinaryOperation* value_op = expr->value()->AsBinaryOperation();
687 if (value_op != nullptr && MatchBinaryOperation(value_op) == kAsIs) {
688 VariableProxy* target_var = expr->target()->AsVariableProxy();
689 VariableProxy* effective_value_var = GetLeft(value_op)->AsVariableProxy();
690 if (target_var != nullptr && effective_value_var != nullptr &&
691 target_var->var() == effective_value_var->var()) {
692 block_size_--;
693 return;
694 }
695 }
696 is_set_op_ = true;
697 RECURSE(Visit(expr->target()));
698 DCHECK(!is_set_op_);
Ben Murdochda12d292016-06-02 14:46:10 +0100699 // Assignment to heapf32 from float64 converts.
700 if (TypeOf(expr->value()) == kAstF64 && expr->target()->IsProperty() &&
701 expr->target()->AsProperty()->obj()->bounds().lower->Is(
702 cache_.kFloat32Array)) {
703 current_function_builder_->Emit(kExprF32ConvertF64);
704 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000705 RECURSE(Visit(expr->value()));
706 if (in_init) {
707 UnLoadInitFunction();
708 }
709 }
710
711 void VisitYield(Yield* expr) { UNREACHABLE(); }
712
713 void VisitThrow(Throw* expr) { UNREACHABLE(); }
714
Ben Murdoch097c5b22016-05-18 11:27:45 +0100715 void VisitForeignVariable(bool is_float, Property* expr) {
716 DCHECK(expr->obj()->AsVariableProxy());
717 DCHECK(VariableLocation::PARAMETER ==
718 expr->obj()->AsVariableProxy()->var()->location());
719 DCHECK_EQ(1, expr->obj()->AsVariableProxy()->var()->index());
720 Literal* key_literal = expr->key()->AsLiteral();
721 DCHECK_NOT_NULL(key_literal);
722 if (!key_literal->value().is_null() && !foreign_.is_null() &&
723 foreign_->IsObject()) {
724 Handle<Name> name =
725 i::Object::ToName(isolate_, key_literal->value()).ToHandleChecked();
726 MaybeHandle<Object> maybe_value = i::Object::GetProperty(foreign_, name);
727 if (!maybe_value.is_null()) {
728 Handle<Object> value = maybe_value.ToHandleChecked();
729 if (is_float) {
730 MaybeHandle<Object> maybe_nvalue = i::Object::ToNumber(value);
731 if (!maybe_nvalue.is_null()) {
732 Handle<Object> nvalue = maybe_nvalue.ToHandleChecked();
733 if (nvalue->IsNumber()) {
734 double val = nvalue->Number();
735 byte code[] = {WASM_F64(val)};
736 current_function_builder_->EmitCode(code, sizeof(code));
737 return;
738 }
739 }
740 } else {
741 MaybeHandle<Object> maybe_nvalue =
742 i::Object::ToInt32(isolate_, value);
743 if (!maybe_nvalue.is_null()) {
744 Handle<Object> nvalue = maybe_nvalue.ToHandleChecked();
745 if (nvalue->IsNumber()) {
746 int32_t val = static_cast<int32_t>(nvalue->Number());
Ben Murdochda12d292016-06-02 14:46:10 +0100747 // TODO(bradnelson): variable size
748 byte code[] = {WASM_I32V(val)};
Ben Murdoch097c5b22016-05-18 11:27:45 +0100749 current_function_builder_->EmitCode(code, sizeof(code));
750 return;
751 }
752 }
753 }
754 }
755 }
756 if (is_float) {
757 byte code[] = {WASM_F64(std::numeric_limits<double>::quiet_NaN())};
758 current_function_builder_->EmitCode(code, sizeof(code));
759 } else {
Ben Murdochda12d292016-06-02 14:46:10 +0100760 byte code[] = {WASM_I32V_1(0)};
Ben Murdoch097c5b22016-05-18 11:27:45 +0100761 current_function_builder_->EmitCode(code, sizeof(code));
762 }
763 }
764
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000765 void VisitProperty(Property* expr) {
766 Expression* obj = expr->obj();
Ben Murdoch097c5b22016-05-18 11:27:45 +0100767 DCHECK_EQ(obj->bounds().lower, obj->bounds().upper);
768 Type* type = obj->bounds().lower;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000769 MachineType mtype;
770 int size;
771 if (type->Is(cache_.kUint8Array)) {
772 mtype = MachineType::Uint8();
773 size = 1;
774 } else if (type->Is(cache_.kInt8Array)) {
775 mtype = MachineType::Int8();
776 size = 1;
777 } else if (type->Is(cache_.kUint16Array)) {
778 mtype = MachineType::Uint16();
779 size = 2;
780 } else if (type->Is(cache_.kInt16Array)) {
781 mtype = MachineType::Int16();
782 size = 2;
783 } else if (type->Is(cache_.kUint32Array)) {
784 mtype = MachineType::Uint32();
785 size = 4;
786 } else if (type->Is(cache_.kInt32Array)) {
787 mtype = MachineType::Int32();
788 size = 4;
789 } else if (type->Is(cache_.kUint32Array)) {
790 mtype = MachineType::Uint32();
791 size = 4;
792 } else if (type->Is(cache_.kFloat32Array)) {
793 mtype = MachineType::Float32();
794 size = 4;
795 } else if (type->Is(cache_.kFloat64Array)) {
796 mtype = MachineType::Float64();
797 size = 8;
798 } else {
799 UNREACHABLE();
800 }
Ben Murdochda12d292016-06-02 14:46:10 +0100801 // TODO(titzer): use special asm-compatibility opcodes?
802 current_function_builder_->EmitWithU8U8(
803 WasmOpcodes::LoadStoreOpcodeOf(mtype, is_set_op_), 0, 0);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000804 is_set_op_ = false;
Ben Murdoch097c5b22016-05-18 11:27:45 +0100805 if (size == 1) {
806 // Allow more general expression in byte arrays than the spec
807 // strictly permits.
808 // Early versions of Emscripten emit HEAP8[HEAP32[..]|0] in
809 // places that strictly should be HEAP8[HEAP32[..]>>0].
810 RECURSE(Visit(expr->key()));
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000811 return;
Ben Murdoch097c5b22016-05-18 11:27:45 +0100812 } else {
813 Literal* value = expr->key()->AsLiteral();
814 if (value) {
815 DCHECK(value->raw_value()->IsNumber());
816 DCHECK_EQ(kAstI32, TypeOf(value));
817 int val = static_cast<int>(value->raw_value()->AsNumber());
Ben Murdochda12d292016-06-02 14:46:10 +0100818 // TODO(bradnelson): variable size
819 byte code[] = {WASM_I32V(val * size)};
Ben Murdoch097c5b22016-05-18 11:27:45 +0100820 current_function_builder_->EmitCode(code, sizeof(code));
821 return;
822 }
823 BinaryOperation* binop = expr->key()->AsBinaryOperation();
824 if (binop) {
825 DCHECK_EQ(Token::SAR, binop->op());
826 DCHECK(binop->right()->AsLiteral()->raw_value()->IsNumber());
827 DCHECK(kAstI32 == TypeOf(binop->right()->AsLiteral()));
828 DCHECK_EQ(size,
829 1 << static_cast<int>(
830 binop->right()->AsLiteral()->raw_value()->AsNumber()));
831 // Mask bottom bits to match asm.js behavior.
832 current_function_builder_->Emit(kExprI32And);
833 byte code[] = {WASM_I8(~(size - 1))};
834 current_function_builder_->EmitCode(code, sizeof(code));
835 RECURSE(Visit(binop->left()));
836 return;
837 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000838 }
839 UNREACHABLE();
840 }
841
Ben Murdochda12d292016-06-02 14:46:10 +0100842 bool VisitStdlibFunction(Call* call, VariableProxy* expr) {
843 Variable* var = expr->var();
844 AsmTyper::StandardMember standard_object =
845 typer_->VariableAsStandardMember(var);
846 ZoneList<Expression*>* args = call->arguments();
847 LocalType call_type = TypeOf(call);
848 switch (standard_object) {
849 case AsmTyper::kNone: {
850 return false;
851 }
852 case AsmTyper::kMathAcos: {
853 DCHECK_EQ(kAstF64, call_type);
854 current_function_builder_->Emit(kExprF64Acos);
855 break;
856 }
857 case AsmTyper::kMathAsin: {
858 DCHECK_EQ(kAstF64, call_type);
859 current_function_builder_->Emit(kExprF64Asin);
860 break;
861 }
862 case AsmTyper::kMathAtan: {
863 DCHECK_EQ(kAstF64, call_type);
864 current_function_builder_->Emit(kExprF64Atan);
865 break;
866 }
867 case AsmTyper::kMathCos: {
868 DCHECK_EQ(kAstF64, call_type);
869 current_function_builder_->Emit(kExprF64Cos);
870 break;
871 }
872 case AsmTyper::kMathSin: {
873 DCHECK_EQ(kAstF64, call_type);
874 current_function_builder_->Emit(kExprF64Sin);
875 break;
876 }
877 case AsmTyper::kMathTan: {
878 DCHECK_EQ(kAstF64, call_type);
879 current_function_builder_->Emit(kExprF64Tan);
880 break;
881 }
882 case AsmTyper::kMathExp: {
883 DCHECK_EQ(kAstF64, call_type);
884 current_function_builder_->Emit(kExprF64Exp);
885 break;
886 }
887 case AsmTyper::kMathLog: {
888 DCHECK_EQ(kAstF64, call_type);
889 current_function_builder_->Emit(kExprF64Log);
890 break;
891 }
892 case AsmTyper::kMathCeil: {
893 if (call_type == kAstF32) {
894 current_function_builder_->Emit(kExprF32Ceil);
895 } else if (call_type == kAstF64) {
896 current_function_builder_->Emit(kExprF64Ceil);
897 } else {
898 UNREACHABLE();
899 }
900 break;
901 }
902 case AsmTyper::kMathFloor: {
903 if (call_type == kAstF32) {
904 current_function_builder_->Emit(kExprF32Floor);
905 } else if (call_type == kAstF64) {
906 current_function_builder_->Emit(kExprF64Floor);
907 } else {
908 UNREACHABLE();
909 }
910 break;
911 }
912 case AsmTyper::kMathSqrt: {
913 if (call_type == kAstF32) {
914 current_function_builder_->Emit(kExprF32Sqrt);
915 } else if (call_type == kAstF64) {
916 current_function_builder_->Emit(kExprF64Sqrt);
917 } else {
918 UNREACHABLE();
919 }
920 break;
921 }
922 case AsmTyper::kMathAbs: {
923 // TODO(bradnelson): Should this be cast to float?
924 if (call_type == kAstI32) {
925 current_function_builder_->Emit(kExprIfElse);
926 current_function_builder_->Emit(kExprI32LtS);
927 Visit(args->at(0));
928 byte code[] = {WASM_I8(0)};
929 current_function_builder_->EmitCode(code, sizeof(code));
930 current_function_builder_->Emit(kExprI32Sub);
931 current_function_builder_->EmitCode(code, sizeof(code));
932 Visit(args->at(0));
933 } else if (call_type == kAstF32) {
934 current_function_builder_->Emit(kExprF32Abs);
935 } else if (call_type == kAstF64) {
936 current_function_builder_->Emit(kExprF64Abs);
937 } else {
938 UNREACHABLE();
939 }
940 break;
941 }
942 case AsmTyper::kMathMin: {
943 // TODO(bradnelson): Change wasm to match Math.min in asm.js mode.
944 if (call_type == kAstI32) {
945 current_function_builder_->Emit(kExprIfElse);
946 current_function_builder_->Emit(kExprI32LeS);
947 Visit(args->at(0));
948 Visit(args->at(1));
949 } else if (call_type == kAstF32) {
950 current_function_builder_->Emit(kExprF32Min);
951 } else if (call_type == kAstF64) {
952 current_function_builder_->Emit(kExprF64Min);
953 } else {
954 UNREACHABLE();
955 }
956 break;
957 }
958 case AsmTyper::kMathMax: {
959 // TODO(bradnelson): Change wasm to match Math.max in asm.js mode.
960 if (call_type == kAstI32) {
961 current_function_builder_->Emit(kExprIfElse);
962 current_function_builder_->Emit(kExprI32GtS);
963 Visit(args->at(0));
964 Visit(args->at(1));
965 } else if (call_type == kAstF32) {
966 current_function_builder_->Emit(kExprF32Max);
967 } else if (call_type == kAstF64) {
968 current_function_builder_->Emit(kExprF64Max);
969 } else {
970 UNREACHABLE();
971 }
972 break;
973 }
974 case AsmTyper::kMathAtan2: {
975 DCHECK_EQ(kAstF64, call_type);
976 current_function_builder_->Emit(kExprF64Atan2);
977 break;
978 }
979 case AsmTyper::kMathPow: {
980 DCHECK_EQ(kAstF64, call_type);
981 current_function_builder_->Emit(kExprF64Pow);
982 break;
983 }
984 case AsmTyper::kMathImul: {
985 current_function_builder_->Emit(kExprI32Mul);
986 break;
987 }
988 case AsmTyper::kMathFround: {
989 DCHECK(args->length() == 1);
990 Literal* literal = args->at(0)->AsLiteral();
991 if (literal != nullptr) {
992 if (literal->raw_value()->IsNumber()) {
993 float val = static_cast<float>(literal->raw_value()->AsNumber());
994 byte code[] = {WASM_F32(val)};
995 current_function_builder_->EmitCode(code, sizeof(code));
996 return true;
997 }
998 }
999 switch (TypeIndexOf(args->at(0))) {
1000 case kInt32:
1001 case kFixnum:
1002 current_function_builder_->Emit(kExprF32SConvertI32);
1003 break;
1004 case kUint32:
1005 current_function_builder_->Emit(kExprF32UConvertI32);
1006 break;
1007 case kFloat32:
1008 break;
1009 case kFloat64:
1010 current_function_builder_->Emit(kExprF32ConvertF64);
1011 break;
1012 default:
1013 UNREACHABLE();
1014 }
1015 break;
1016 }
1017 default: {
1018 UNREACHABLE();
1019 break;
1020 }
1021 }
1022 VisitCallArgs(call);
1023 return true;
1024 }
1025
1026 void VisitCallArgs(Call* expr) {
1027 ZoneList<Expression*>* args = expr->arguments();
1028 for (int i = 0; i < args->length(); ++i) {
1029 Expression* arg = args->at(i);
1030 RECURSE(Visit(arg));
1031 }
1032 }
1033
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001034 void VisitCall(Call* expr) {
1035 Call::CallType call_type = expr->GetCallType(isolate_);
1036 switch (call_type) {
1037 case Call::OTHER_CALL: {
1038 DCHECK(in_function_);
Ben Murdochda12d292016-06-02 14:46:10 +01001039 VariableProxy* proxy = expr->expression()->AsVariableProxy();
1040 if (proxy != nullptr) {
1041 if (VisitStdlibFunction(expr, proxy)) {
1042 return;
1043 }
1044 }
Ben Murdoch097c5b22016-05-18 11:27:45 +01001045 uint16_t index;
1046 VariableProxy* vp = expr->expression()->AsVariableProxy();
1047 if (vp != nullptr &&
1048 Type::Any()->Is(vp->bounds().lower->AsFunction()->Result())) {
1049 LocalType return_type = TypeOf(expr);
1050 ZoneList<Expression*>* args = expr->arguments();
1051 FunctionSig::Builder sig(zone(), return_type == kAstStmt ? 0 : 1,
1052 args->length());
1053 if (return_type != kAstStmt) {
1054 sig.AddReturn(return_type);
1055 }
1056 for (int i = 0; i < args->length(); i++) {
1057 sig.AddParam(TypeOf(args->at(i)));
1058 }
1059 index =
1060 imported_function_table_.GetFunctionIndex(vp->var(), sig.Build());
1061 } else {
1062 index = LookupOrInsertFunction(vp->var());
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001063 }
Ben Murdoch097c5b22016-05-18 11:27:45 +01001064 current_function_builder_->Emit(kExprCallFunction);
1065 std::vector<uint8_t> index_arr = UnsignedLEB128From(index);
1066 current_function_builder_->EmitCode(
1067 &index_arr[0], static_cast<uint32_t>(index_arr.size()));
1068 break;
1069 }
1070 case Call::KEYED_PROPERTY_CALL: {
1071 DCHECK(in_function_);
1072 Property* p = expr->expression()->AsProperty();
1073 DCHECK_NOT_NULL(p);
1074 VariableProxy* var = p->obj()->AsVariableProxy();
1075 DCHECK_NOT_NULL(var);
1076 FunctionTableIndices* indices = LookupFunctionTable(var->var());
Ben Murdochda12d292016-06-02 14:46:10 +01001077 current_function_builder_->EmitWithVarInt(kExprCallIndirect,
1078 indices->signature_index);
Ben Murdoch097c5b22016-05-18 11:27:45 +01001079 current_function_builder_->Emit(kExprI32Add);
Ben Murdochda12d292016-06-02 14:46:10 +01001080 // TODO(bradnelson): variable size
1081 byte code[] = {WASM_I32V(indices->start_index)};
Ben Murdoch097c5b22016-05-18 11:27:45 +01001082 current_function_builder_->EmitCode(code, sizeof(code));
1083 RECURSE(Visit(p->key()));
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001084 break;
1085 }
1086 default:
1087 UNREACHABLE();
1088 }
Ben Murdochda12d292016-06-02 14:46:10 +01001089 VisitCallArgs(expr);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001090 }
1091
1092 void VisitCallNew(CallNew* expr) { UNREACHABLE(); }
1093
1094 void VisitCallRuntime(CallRuntime* expr) { UNREACHABLE(); }
1095
1096 void VisitUnaryOperation(UnaryOperation* expr) {
1097 switch (expr->op()) {
1098 case Token::NOT: {
Ben Murdoch097c5b22016-05-18 11:27:45 +01001099 DCHECK_EQ(kAstI32, TypeOf(expr->expression()));
Ben Murdochda12d292016-06-02 14:46:10 +01001100 current_function_builder_->Emit(kExprI32Eqz);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001101 break;
1102 }
1103 default:
1104 UNREACHABLE();
1105 }
1106 RECURSE(Visit(expr->expression()));
1107 }
1108
1109 void VisitCountOperation(CountOperation* expr) { UNREACHABLE(); }
1110
1111 bool MatchIntBinaryOperation(BinaryOperation* expr, Token::Value op,
1112 int32_t val) {
Ben Murdoch097c5b22016-05-18 11:27:45 +01001113 DCHECK_NOT_NULL(expr->right());
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001114 if (expr->op() == op && expr->right()->IsLiteral() &&
1115 TypeOf(expr) == kAstI32) {
1116 Literal* right = expr->right()->AsLiteral();
1117 DCHECK(right->raw_value()->IsNumber());
1118 if (static_cast<int32_t>(right->raw_value()->AsNumber()) == val) {
1119 return true;
1120 }
1121 }
1122 return false;
1123 }
1124
1125 bool MatchDoubleBinaryOperation(BinaryOperation* expr, Token::Value op,
1126 double val) {
Ben Murdoch097c5b22016-05-18 11:27:45 +01001127 DCHECK_NOT_NULL(expr->right());
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001128 if (expr->op() == op && expr->right()->IsLiteral() &&
1129 TypeOf(expr) == kAstF64) {
1130 Literal* right = expr->right()->AsLiteral();
1131 DCHECK(right->raw_value()->IsNumber());
1132 if (right->raw_value()->AsNumber() == val) {
1133 return true;
1134 }
1135 }
1136 return false;
1137 }
1138
1139 enum ConvertOperation { kNone, kAsIs, kToInt, kToDouble };
1140
1141 ConvertOperation MatchOr(BinaryOperation* expr) {
Ben Murdoch097c5b22016-05-18 11:27:45 +01001142 if (MatchIntBinaryOperation(expr, Token::BIT_OR, 0) &&
1143 (TypeOf(expr->left()) == kAstI32)) {
1144 return kAsIs;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001145 } else {
1146 return kNone;
1147 }
1148 }
1149
1150 ConvertOperation MatchShr(BinaryOperation* expr) {
1151 if (MatchIntBinaryOperation(expr, Token::SHR, 0)) {
1152 // TODO(titzer): this probably needs to be kToUint
1153 return (TypeOf(expr->left()) == kAstI32) ? kAsIs : kToInt;
1154 } else {
1155 return kNone;
1156 }
1157 }
1158
1159 ConvertOperation MatchXor(BinaryOperation* expr) {
1160 if (MatchIntBinaryOperation(expr, Token::BIT_XOR, 0xffffffff)) {
Ben Murdoch097c5b22016-05-18 11:27:45 +01001161 DCHECK_EQ(kAstI32, TypeOf(expr->left()));
1162 DCHECK_EQ(kAstI32, TypeOf(expr->right()));
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001163 BinaryOperation* op = expr->left()->AsBinaryOperation();
1164 if (op != nullptr) {
1165 if (MatchIntBinaryOperation(op, Token::BIT_XOR, 0xffffffff)) {
Ben Murdoch097c5b22016-05-18 11:27:45 +01001166 DCHECK_EQ(kAstI32, TypeOf(op->right()));
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001167 if (TypeOf(op->left()) != kAstI32) {
1168 return kToInt;
1169 } else {
1170 return kAsIs;
1171 }
1172 }
1173 }
1174 }
1175 return kNone;
1176 }
1177
1178 ConvertOperation MatchMul(BinaryOperation* expr) {
1179 if (MatchDoubleBinaryOperation(expr, Token::MUL, 1.0)) {
Ben Murdoch097c5b22016-05-18 11:27:45 +01001180 DCHECK_EQ(kAstF64, TypeOf(expr->right()));
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001181 if (TypeOf(expr->left()) != kAstF64) {
1182 return kToDouble;
1183 } else {
1184 return kAsIs;
1185 }
1186 } else {
1187 return kNone;
1188 }
1189 }
1190
1191 ConvertOperation MatchBinaryOperation(BinaryOperation* expr) {
1192 switch (expr->op()) {
1193 case Token::BIT_OR:
1194 return MatchOr(expr);
1195 case Token::SHR:
1196 return MatchShr(expr);
1197 case Token::BIT_XOR:
1198 return MatchXor(expr);
1199 case Token::MUL:
1200 return MatchMul(expr);
1201 default:
1202 return kNone;
1203 }
1204 }
1205
1206// Work around Mul + Div being defined in PPC assembler.
1207#ifdef Mul
1208#undef Mul
1209#endif
1210#ifdef Div
1211#undef Div
1212#endif
1213
1214#define NON_SIGNED_BINOP(op) \
1215 static WasmOpcode opcodes[] = { \
1216 kExprI32##op, \
1217 kExprI32##op, \
1218 kExprF32##op, \
1219 kExprF64##op \
1220 }
1221
1222#define SIGNED_BINOP(op) \
1223 static WasmOpcode opcodes[] = { \
1224 kExprI32##op##S, \
1225 kExprI32##op##U, \
1226 kExprF32##op, \
1227 kExprF64##op \
1228 }
1229
1230#define NON_SIGNED_INT_BINOP(op) \
1231 static WasmOpcode opcodes[] = { kExprI32##op, kExprI32##op }
1232
1233#define BINOP_CASE(token, op, V, ignore_sign) \
1234 case token: { \
1235 V(op); \
1236 int type = TypeIndexOf(expr->left(), expr->right(), ignore_sign); \
1237 current_function_builder_->Emit(opcodes[type]); \
1238 break; \
1239 }
1240
1241 Expression* GetLeft(BinaryOperation* expr) {
1242 if (expr->op() == Token::BIT_XOR) {
1243 return expr->left()->AsBinaryOperation()->left();
1244 } else {
1245 return expr->left();
1246 }
1247 }
1248
1249 void VisitBinaryOperation(BinaryOperation* expr) {
1250 ConvertOperation convertOperation = MatchBinaryOperation(expr);
1251 if (convertOperation == kToDouble) {
1252 TypeIndex type = TypeIndexOf(expr->left());
1253 if (type == kInt32 || type == kFixnum) {
1254 current_function_builder_->Emit(kExprF64SConvertI32);
1255 } else if (type == kUint32) {
1256 current_function_builder_->Emit(kExprF64UConvertI32);
1257 } else if (type == kFloat32) {
1258 current_function_builder_->Emit(kExprF64ConvertF32);
1259 } else {
1260 UNREACHABLE();
1261 }
1262 RECURSE(Visit(expr->left()));
1263 } else if (convertOperation == kToInt) {
1264 TypeIndex type = TypeIndexOf(GetLeft(expr));
1265 if (type == kFloat32) {
1266 current_function_builder_->Emit(kExprI32SConvertF32);
1267 } else if (type == kFloat64) {
1268 current_function_builder_->Emit(kExprI32SConvertF64);
1269 } else {
1270 UNREACHABLE();
1271 }
1272 RECURSE(Visit(GetLeft(expr)));
1273 } else if (convertOperation == kAsIs) {
1274 RECURSE(Visit(GetLeft(expr)));
1275 } else {
1276 switch (expr->op()) {
1277 BINOP_CASE(Token::ADD, Add, NON_SIGNED_BINOP, true);
1278 BINOP_CASE(Token::SUB, Sub, NON_SIGNED_BINOP, true);
1279 BINOP_CASE(Token::MUL, Mul, NON_SIGNED_BINOP, true);
1280 BINOP_CASE(Token::DIV, Div, SIGNED_BINOP, false);
1281 BINOP_CASE(Token::BIT_OR, Ior, NON_SIGNED_INT_BINOP, true);
Ben Murdoch097c5b22016-05-18 11:27:45 +01001282 BINOP_CASE(Token::BIT_AND, And, NON_SIGNED_INT_BINOP, true);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001283 BINOP_CASE(Token::BIT_XOR, Xor, NON_SIGNED_INT_BINOP, true);
1284 BINOP_CASE(Token::SHL, Shl, NON_SIGNED_INT_BINOP, true);
1285 BINOP_CASE(Token::SAR, ShrS, NON_SIGNED_INT_BINOP, true);
1286 BINOP_CASE(Token::SHR, ShrU, NON_SIGNED_INT_BINOP, true);
1287 case Token::MOD: {
1288 TypeIndex type = TypeIndexOf(expr->left(), expr->right(), false);
1289 if (type == kInt32) {
1290 current_function_builder_->Emit(kExprI32RemS);
1291 } else if (type == kUint32) {
1292 current_function_builder_->Emit(kExprI32RemU);
1293 } else if (type == kFloat64) {
Ben Murdochda12d292016-06-02 14:46:10 +01001294 current_function_builder_->Emit(kExprF64Mod);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001295 return;
1296 } else {
1297 UNREACHABLE();
1298 }
1299 break;
1300 }
Ben Murdoch097c5b22016-05-18 11:27:45 +01001301 case Token::COMMA: {
Ben Murdochda12d292016-06-02 14:46:10 +01001302 current_function_builder_->EmitWithVarInt(kExprBlock, 2);
Ben Murdoch097c5b22016-05-18 11:27:45 +01001303 break;
1304 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001305 default:
1306 UNREACHABLE();
1307 }
1308 RECURSE(Visit(expr->left()));
1309 RECURSE(Visit(expr->right()));
1310 }
1311 }
1312
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001313 void AddLeb128(uint32_t index, bool is_local) {
1314 std::vector<uint8_t> index_vec = UnsignedLEB128From(index);
1315 if (is_local) {
1316 uint32_t pos_of_index[1] = {0};
1317 current_function_builder_->EmitCode(
1318 &index_vec[0], static_cast<uint32_t>(index_vec.size()), pos_of_index,
1319 1);
1320 } else {
1321 current_function_builder_->EmitCode(
1322 &index_vec[0], static_cast<uint32_t>(index_vec.size()));
1323 }
1324 }
1325
1326 void VisitCompareOperation(CompareOperation* expr) {
1327 switch (expr->op()) {
1328 BINOP_CASE(Token::EQ, Eq, NON_SIGNED_BINOP, false);
1329 BINOP_CASE(Token::LT, Lt, SIGNED_BINOP, false);
1330 BINOP_CASE(Token::LTE, Le, SIGNED_BINOP, false);
1331 BINOP_CASE(Token::GT, Gt, SIGNED_BINOP, false);
1332 BINOP_CASE(Token::GTE, Ge, SIGNED_BINOP, false);
1333 default:
1334 UNREACHABLE();
1335 }
1336 RECURSE(Visit(expr->left()));
1337 RECURSE(Visit(expr->right()));
1338 }
1339
1340#undef BINOP_CASE
1341#undef NON_SIGNED_INT_BINOP
1342#undef SIGNED_BINOP
1343#undef NON_SIGNED_BINOP
1344
1345 enum TypeIndex {
1346 kInt32 = 0,
1347 kUint32 = 1,
1348 kFloat32 = 2,
1349 kFloat64 = 3,
1350 kFixnum = 4
1351 };
1352
1353 TypeIndex TypeIndexOf(Expression* left, Expression* right, bool ignore_sign) {
1354 TypeIndex left_index = TypeIndexOf(left);
1355 TypeIndex right_index = TypeIndexOf(right);
1356 if (left_index == kFixnum) {
1357 left_index = right_index;
1358 }
1359 if (right_index == kFixnum) {
1360 right_index = left_index;
1361 }
1362 if (left_index == kFixnum && right_index == kFixnum) {
1363 left_index = kInt32;
1364 right_index = kInt32;
1365 }
1366 DCHECK((left_index == right_index) ||
1367 (ignore_sign && (left_index <= 1) && (right_index <= 1)));
1368 return left_index;
1369 }
1370
1371 TypeIndex TypeIndexOf(Expression* expr) {
Ben Murdoch097c5b22016-05-18 11:27:45 +01001372 DCHECK_EQ(expr->bounds().lower, expr->bounds().upper);
1373 Type* type = expr->bounds().lower;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001374 if (type->Is(cache_.kAsmFixnum)) {
1375 return kFixnum;
1376 } else if (type->Is(cache_.kAsmSigned)) {
1377 return kInt32;
1378 } else if (type->Is(cache_.kAsmUnsigned)) {
1379 return kUint32;
1380 } else if (type->Is(cache_.kAsmInt)) {
1381 return kInt32;
1382 } else if (type->Is(cache_.kAsmFloat)) {
1383 return kFloat32;
1384 } else if (type->Is(cache_.kAsmDouble)) {
1385 return kFloat64;
1386 } else {
1387 UNREACHABLE();
1388 return kInt32;
1389 }
1390 }
1391
1392#undef CASE
1393#undef NON_SIGNED_INT
1394#undef SIGNED
1395#undef NON_SIGNED
1396
1397 void VisitThisFunction(ThisFunction* expr) { UNREACHABLE(); }
1398
1399 void VisitDeclarations(ZoneList<Declaration*>* decls) {
1400 for (int i = 0; i < decls->length(); ++i) {
1401 Declaration* decl = decls->at(i);
1402 RECURSE(Visit(decl));
1403 }
1404 }
1405
1406 void VisitClassLiteral(ClassLiteral* expr) { UNREACHABLE(); }
1407
1408 void VisitSpread(Spread* expr) { UNREACHABLE(); }
1409
1410 void VisitSuperPropertyReference(SuperPropertyReference* expr) {
1411 UNREACHABLE();
1412 }
1413
1414 void VisitSuperCallReference(SuperCallReference* expr) { UNREACHABLE(); }
1415
1416 void VisitSloppyBlockFunctionStatement(SloppyBlockFunctionStatement* expr) {
1417 UNREACHABLE();
1418 }
1419
1420 void VisitDoExpression(DoExpression* expr) { UNREACHABLE(); }
1421
Ben Murdoch097c5b22016-05-18 11:27:45 +01001422 void VisitRewritableExpression(RewritableExpression* expr) { UNREACHABLE(); }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001423
1424 struct IndexContainer : public ZoneObject {
1425 uint16_t index;
1426 };
1427
1428 uint16_t LookupOrInsertLocal(Variable* v, LocalType type) {
Ben Murdoch097c5b22016-05-18 11:27:45 +01001429 DCHECK_NOT_NULL(current_function_builder_);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001430 ZoneHashMap::Entry* entry =
1431 local_variables_.Lookup(v, ComputePointerHash(v));
1432 if (entry == nullptr) {
1433 uint16_t index;
1434 if (v->IsParameter()) {
1435 index = current_function_builder_->AddParam(type);
1436 } else {
1437 index = current_function_builder_->AddLocal(type);
1438 }
1439 IndexContainer* container = new (zone()) IndexContainer();
1440 container->index = index;
1441 entry = local_variables_.LookupOrInsert(v, ComputePointerHash(v),
1442 ZoneAllocationPolicy(zone()));
1443 entry->value = container;
1444 }
1445 return (reinterpret_cast<IndexContainer*>(entry->value))->index;
1446 }
1447
1448 uint16_t LookupOrInsertGlobal(Variable* v, LocalType type) {
1449 ZoneHashMap::Entry* entry =
1450 global_variables_.Lookup(v, ComputePointerHash(v));
1451 if (entry == nullptr) {
1452 uint16_t index =
1453 builder_->AddGlobal(WasmOpcodes::MachineTypeFor(type), 0);
1454 IndexContainer* container = new (zone()) IndexContainer();
1455 container->index = index;
1456 entry = global_variables_.LookupOrInsert(v, ComputePointerHash(v),
1457 ZoneAllocationPolicy(zone()));
1458 entry->value = container;
1459 }
1460 return (reinterpret_cast<IndexContainer*>(entry->value))->index;
1461 }
1462
1463 uint16_t LookupOrInsertFunction(Variable* v) {
Ben Murdoch097c5b22016-05-18 11:27:45 +01001464 DCHECK_NOT_NULL(builder_);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001465 ZoneHashMap::Entry* entry = functions_.Lookup(v, ComputePointerHash(v));
1466 if (entry == nullptr) {
1467 uint16_t index = builder_->AddFunction();
1468 IndexContainer* container = new (zone()) IndexContainer();
1469 container->index = index;
1470 entry = functions_.LookupOrInsert(v, ComputePointerHash(v),
1471 ZoneAllocationPolicy(zone()));
1472 entry->value = container;
1473 }
1474 return (reinterpret_cast<IndexContainer*>(entry->value))->index;
1475 }
1476
1477 LocalType TypeOf(Expression* expr) {
Ben Murdoch097c5b22016-05-18 11:27:45 +01001478 DCHECK_EQ(expr->bounds().lower, expr->bounds().upper);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001479 return TypeFrom(expr->bounds().lower);
1480 }
1481
Ben Murdoch097c5b22016-05-18 11:27:45 +01001482 LocalType TypeFrom(Type* type) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001483 if (type->Is(cache_.kAsmInt)) {
1484 return kAstI32;
1485 } else if (type->Is(cache_.kAsmFloat)) {
1486 return kAstF32;
1487 } else if (type->Is(cache_.kAsmDouble)) {
1488 return kAstF64;
1489 } else {
1490 return kAstStmt;
1491 }
1492 }
1493
1494 Zone* zone() { return zone_; }
1495
1496 ZoneHashMap local_variables_;
1497 ZoneHashMap functions_;
1498 ZoneHashMap global_variables_;
1499 bool in_function_;
1500 bool is_set_op_;
1501 bool marking_exported;
1502 WasmModuleBuilder* builder_;
1503 WasmFunctionBuilder* current_function_builder_;
1504 FunctionLiteral* literal_;
1505 Isolate* isolate_;
1506 Zone* zone_;
Ben Murdoch097c5b22016-05-18 11:27:45 +01001507 Handle<Object> foreign_;
Ben Murdochda12d292016-06-02 14:46:10 +01001508 AsmTyper* typer_;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001509 TypeCache const& cache_;
1510 ZoneVector<std::pair<BreakableStatement*, bool>> breakable_blocks_;
1511 int block_size_;
Ben Murdoch097c5b22016-05-18 11:27:45 +01001512 uint16_t init_function_index_;
1513 uint32_t next_table_index_;
1514 ZoneHashMap function_tables_;
1515 ImportedFunctionTable imported_function_table_;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001516
1517 DEFINE_AST_VISITOR_SUBCLASS_MEMBERS();
1518
1519 private:
1520 DISALLOW_COPY_AND_ASSIGN(AsmWasmBuilderImpl);
1521};
1522
1523AsmWasmBuilder::AsmWasmBuilder(Isolate* isolate, Zone* zone,
Ben Murdochda12d292016-06-02 14:46:10 +01001524 FunctionLiteral* literal, Handle<Object> foreign,
1525 AsmTyper* typer)
1526 : isolate_(isolate),
1527 zone_(zone),
1528 literal_(literal),
1529 foreign_(foreign),
1530 typer_(typer) {}
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001531
1532// TODO(aseemgarg): probably should take zone (to write wasm to) as input so
1533// that zone in constructor may be thrown away once wasm module is written.
1534WasmModuleIndex* AsmWasmBuilder::Run() {
Ben Murdochda12d292016-06-02 14:46:10 +01001535 AsmWasmBuilderImpl impl(isolate_, zone_, literal_, foreign_, typer_);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001536 impl.Compile();
1537 WasmModuleWriter* writer = impl.builder_->Build(zone_);
1538 return writer->WriteTo(zone_);
1539}
1540} // namespace wasm
1541} // namespace internal
1542} // namespace v8