blob: ee5427b174d11e8736ca08af45e605e55f3ca8ab [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
7#include "src/wasm/asm-wasm-builder.h"
8#include "src/wasm/wasm-macro-gen.h"
9#include "src/wasm/wasm-opcodes.h"
10
11#include "src/ast/ast.h"
12#include "src/ast/scopes.h"
13#include "src/codegen.h"
14#include "src/type-cache.h"
15
16namespace v8 {
17namespace internal {
18namespace wasm {
19
20#define RECURSE(call) \
21 do { \
22 DCHECK(!HasStackOverflow()); \
23 call; \
24 if (HasStackOverflow()) return; \
25 } while (false)
26
27
28class AsmWasmBuilderImpl : public AstVisitor {
29 public:
Ben Murdoch097c5b22016-05-18 11:27:45 +010030 AsmWasmBuilderImpl(Isolate* isolate, Zone* zone, FunctionLiteral* literal,
31 Handle<Object> foreign)
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000032 : local_variables_(HashMap::PointersMatch,
33 ZoneHashMap::kDefaultHashMapCapacity,
34 ZoneAllocationPolicy(zone)),
35 functions_(HashMap::PointersMatch, ZoneHashMap::kDefaultHashMapCapacity,
36 ZoneAllocationPolicy(zone)),
37 global_variables_(HashMap::PointersMatch,
38 ZoneHashMap::kDefaultHashMapCapacity,
39 ZoneAllocationPolicy(zone)),
40 in_function_(false),
41 is_set_op_(false),
42 marking_exported(false),
43 builder_(new (zone) WasmModuleBuilder(zone)),
44 current_function_builder_(nullptr),
45 literal_(literal),
46 isolate_(isolate),
47 zone_(zone),
Ben Murdoch097c5b22016-05-18 11:27:45 +010048 foreign_(foreign),
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000049 cache_(TypeCache::Get()),
50 breakable_blocks_(zone),
51 block_size_(0),
Ben Murdoch097c5b22016-05-18 11:27:45 +010052 init_function_index_(0),
53 next_table_index_(0),
54 function_tables_(HashMap::PointersMatch,
55 ZoneHashMap::kDefaultHashMapCapacity,
56 ZoneAllocationPolicy(zone)),
57 imported_function_table_(this) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000058 InitializeAstVisitor(isolate);
59 }
60
61 void InitializeInitFunction() {
62 unsigned char init[] = "__init__";
Ben Murdoch097c5b22016-05-18 11:27:45 +010063 init_function_index_ = builder_->AddFunction();
64 current_function_builder_ = builder_->FunctionAt(init_function_index_);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000065 current_function_builder_->SetName(init, 8);
66 current_function_builder_->ReturnType(kAstStmt);
67 current_function_builder_->Exported(1);
68 current_function_builder_ = nullptr;
69 }
70
71 void Compile() {
72 InitializeInitFunction();
73 RECURSE(VisitFunctionLiteral(literal_));
74 }
75
76 void VisitVariableDeclaration(VariableDeclaration* decl) {}
77
78 void VisitFunctionDeclaration(FunctionDeclaration* decl) {
79 DCHECK(!in_function_);
Ben Murdoch097c5b22016-05-18 11:27:45 +010080 DCHECK_NULL(current_function_builder_);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000081 uint16_t index = LookupOrInsertFunction(decl->proxy()->var());
82 current_function_builder_ = builder_->FunctionAt(index);
83 in_function_ = true;
84 RECURSE(Visit(decl->fun()));
85 in_function_ = false;
86 current_function_builder_ = nullptr;
87 local_variables_.Clear();
88 }
89
90 void VisitImportDeclaration(ImportDeclaration* decl) {}
91
92 void VisitExportDeclaration(ExportDeclaration* decl) {}
93
94 void VisitStatements(ZoneList<Statement*>* stmts) {
95 for (int i = 0; i < stmts->length(); ++i) {
96 Statement* stmt = stmts->at(i);
97 RECURSE(Visit(stmt));
98 if (stmt->IsJump()) break;
99 }
100 }
101
102 void VisitBlock(Block* stmt) {
103 if (stmt->statements()->length() == 1) {
104 ExpressionStatement* expr =
105 stmt->statements()->at(0)->AsExpressionStatement();
106 if (expr != nullptr) {
107 if (expr->expression()->IsAssignment()) {
108 RECURSE(VisitExpressionStatement(expr));
109 return;
110 }
111 }
112 }
Ben Murdoch097c5b22016-05-18 11:27:45 +0100113 if (in_function_) {
114 BlockVisitor visitor(this, stmt->AsBreakableStatement(), kExprBlock,
115 false,
116 static_cast<byte>(stmt->statements()->length()));
117 RECURSE(VisitStatements(stmt->statements()));
118 DCHECK(block_size_ >= 0);
119 } else {
120 RECURSE(VisitStatements(stmt->statements()));
121 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000122 }
123
124 class BlockVisitor {
125 private:
126 int prev_block_size_;
127 uint32_t index_;
128 AsmWasmBuilderImpl* builder_;
129
130 public:
131 BlockVisitor(AsmWasmBuilderImpl* builder, BreakableStatement* stmt,
132 WasmOpcode opcode, bool is_loop, int initial_block_size)
133 : builder_(builder) {
134 builder_->breakable_blocks_.push_back(std::make_pair(stmt, is_loop));
135 builder_->current_function_builder_->Emit(opcode);
136 index_ = builder_->current_function_builder_->EmitEditableImmediate(0);
137 prev_block_size_ = builder_->block_size_;
138 builder_->block_size_ = initial_block_size;
139 }
140 ~BlockVisitor() {
141 builder_->current_function_builder_->EditImmediate(index_,
142 builder_->block_size_);
143 builder_->block_size_ = prev_block_size_;
144 builder_->breakable_blocks_.pop_back();
145 }
146 };
147
148 void VisitExpressionStatement(ExpressionStatement* stmt) {
149 RECURSE(Visit(stmt->expression()));
150 }
151
152 void VisitEmptyStatement(EmptyStatement* stmt) {}
153
154 void VisitEmptyParentheses(EmptyParentheses* paren) { UNREACHABLE(); }
155
156 void VisitIfStatement(IfStatement* stmt) {
157 DCHECK(in_function_);
158 if (stmt->HasElseStatement()) {
159 current_function_builder_->Emit(kExprIfElse);
160 } else {
161 current_function_builder_->Emit(kExprIf);
162 }
163 RECURSE(Visit(stmt->condition()));
164 if (stmt->HasThenStatement()) {
165 RECURSE(Visit(stmt->then_statement()));
166 } else {
167 current_function_builder_->Emit(kExprNop);
168 }
169 if (stmt->HasElseStatement()) {
170 RECURSE(Visit(stmt->else_statement()));
171 }
172 }
173
174 void VisitContinueStatement(ContinueStatement* stmt) {
175 DCHECK(in_function_);
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);
191 current_function_builder_->EmitWithU8(kExprBr, block_distance);
192 current_function_builder_->Emit(kExprNop);
193 }
194
195 void VisitBreakStatement(BreakStatement* stmt) {
196 DCHECK(in_function_);
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);
214 current_function_builder_->EmitWithU8(kExprBr, block_distance);
215 current_function_builder_->Emit(kExprNop);
216 }
217
218 void VisitReturnStatement(ReturnStatement* stmt) {
219 if (in_function_) {
220 current_function_builder_->Emit(kExprReturn);
221 } else {
222 marking_exported = true;
223 }
224 RECURSE(Visit(stmt->expression()));
225 if (!in_function_) {
226 marking_exported = false;
227 }
228 }
229
230 void VisitWithStatement(WithStatement* stmt) { UNREACHABLE(); }
231
232 void SetLocalTo(uint16_t index, int value) {
233 current_function_builder_->Emit(kExprSetLocal);
234 AddLeb128(index, true);
235 byte code[] = {WASM_I32(value)};
236 current_function_builder_->EmitCode(code, sizeof(code));
237 block_size_++;
238 }
239
240 void CompileCase(CaseClause* clause, uint16_t fall_through,
241 VariableProxy* tag) {
242 Literal* label = clause->label()->AsLiteral();
Ben Murdoch097c5b22016-05-18 11:27:45 +0100243 DCHECK_NOT_NULL(label);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000244 block_size_++;
245 current_function_builder_->Emit(kExprIf);
246 current_function_builder_->Emit(kExprI32Ior);
247 current_function_builder_->Emit(kExprI32Eq);
248 VisitVariableProxy(tag);
249 VisitLiteral(label);
250 current_function_builder_->Emit(kExprGetLocal);
251 AddLeb128(fall_through, true);
252 BlockVisitor visitor(this, nullptr, kExprBlock, false, 0);
253 SetLocalTo(fall_through, 1);
254 ZoneList<Statement*>* stmts = clause->statements();
255 block_size_ += stmts->length();
256 RECURSE(VisitStatements(stmts));
257 }
258
259 void VisitSwitchStatement(SwitchStatement* stmt) {
260 VariableProxy* tag = stmt->tag()->AsVariableProxy();
Ben Murdoch097c5b22016-05-18 11:27:45 +0100261 DCHECK_NOT_NULL(tag);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000262 BlockVisitor visitor(this, stmt->AsBreakableStatement(), kExprBlock, false,
263 0);
264 uint16_t fall_through = current_function_builder_->AddLocal(kAstI32);
265 SetLocalTo(fall_through, 0);
266
267 ZoneList<CaseClause*>* clauses = stmt->cases();
268 for (int i = 0; i < clauses->length(); ++i) {
269 CaseClause* clause = clauses->at(i);
270 if (!clause->is_default()) {
271 CompileCase(clause, fall_through, tag);
272 } else {
273 ZoneList<Statement*>* stmts = clause->statements();
274 block_size_ += stmts->length();
275 RECURSE(VisitStatements(stmts));
276 }
277 }
278 }
279
280 void VisitCaseClause(CaseClause* clause) { UNREACHABLE(); }
281
282 void VisitDoWhileStatement(DoWhileStatement* stmt) {
283 DCHECK(in_function_);
284 BlockVisitor visitor(this, stmt->AsBreakableStatement(), kExprLoop, true,
285 2);
286 RECURSE(Visit(stmt->body()));
287 current_function_builder_->Emit(kExprIf);
288 RECURSE(Visit(stmt->cond()));
289 current_function_builder_->EmitWithU8(kExprBr, 0);
290 current_function_builder_->Emit(kExprNop);
291 }
292
293 void VisitWhileStatement(WhileStatement* stmt) {
294 DCHECK(in_function_);
295 BlockVisitor visitor(this, stmt->AsBreakableStatement(), kExprLoop, true,
296 1);
297 current_function_builder_->Emit(kExprIf);
298 RECURSE(Visit(stmt->cond()));
299 current_function_builder_->EmitWithU8(kExprBr, 0);
300 RECURSE(Visit(stmt->body()));
301 }
302
303 void VisitForStatement(ForStatement* stmt) {
304 DCHECK(in_function_);
305 if (stmt->init() != nullptr) {
306 block_size_++;
307 RECURSE(Visit(stmt->init()));
308 }
309 BlockVisitor visitor(this, stmt->AsBreakableStatement(), kExprLoop, true,
310 0);
311 if (stmt->cond() != nullptr) {
312 block_size_++;
313 current_function_builder_->Emit(kExprIf);
314 current_function_builder_->Emit(kExprBoolNot);
315 RECURSE(Visit(stmt->cond()));
316 current_function_builder_->EmitWithU8(kExprBr, 1);
317 current_function_builder_->Emit(kExprNop);
318 }
319 if (stmt->body() != nullptr) {
320 block_size_++;
321 RECURSE(Visit(stmt->body()));
322 }
323 if (stmt->next() != nullptr) {
324 block_size_++;
325 RECURSE(Visit(stmt->next()));
326 }
327 block_size_++;
328 current_function_builder_->EmitWithU8(kExprBr, 0);
329 current_function_builder_->Emit(kExprNop);
330 }
331
332 void VisitForInStatement(ForInStatement* stmt) { UNREACHABLE(); }
333
334 void VisitForOfStatement(ForOfStatement* stmt) { UNREACHABLE(); }
335
336 void VisitTryCatchStatement(TryCatchStatement* stmt) { UNREACHABLE(); }
337
338 void VisitTryFinallyStatement(TryFinallyStatement* stmt) { UNREACHABLE(); }
339
340 void VisitDebuggerStatement(DebuggerStatement* stmt) { UNREACHABLE(); }
341
342 void VisitFunctionLiteral(FunctionLiteral* expr) {
343 Scope* scope = expr->scope();
344 if (in_function_) {
345 if (expr->bounds().lower->IsFunction()) {
Ben Murdoch097c5b22016-05-18 11:27:45 +0100346 FunctionType* func_type = expr->bounds().lower->AsFunction();
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000347 LocalType return_type = TypeFrom(func_type->Result());
348 current_function_builder_->ReturnType(return_type);
349 for (int i = 0; i < expr->parameter_count(); i++) {
350 LocalType type = TypeFrom(func_type->Parameter(i));
Ben Murdoch097c5b22016-05-18 11:27:45 +0100351 DCHECK_NE(kAstStmt, type);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000352 LookupOrInsertLocal(scope->parameter(i), type);
353 }
354 } else {
355 UNREACHABLE();
356 }
357 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000358 RECURSE(VisitStatements(expr->body()));
Ben Murdoch097c5b22016-05-18 11:27:45 +0100359 RECURSE(VisitDeclarations(scope->declarations()));
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000360 }
361
362 void VisitNativeFunctionLiteral(NativeFunctionLiteral* expr) {
363 UNREACHABLE();
364 }
365
366 void VisitConditional(Conditional* expr) {
367 DCHECK(in_function_);
368 current_function_builder_->Emit(kExprIfElse);
369 RECURSE(Visit(expr->condition()));
370 RECURSE(Visit(expr->then_expression()));
371 RECURSE(Visit(expr->else_expression()));
372 }
373
374 void VisitVariableProxy(VariableProxy* expr) {
375 if (in_function_) {
376 Variable* var = expr->var();
Ben Murdoch097c5b22016-05-18 11:27:45 +0100377 if (is_set_op_) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000378 if (var->IsContextSlot()) {
Ben Murdoch097c5b22016-05-18 11:27:45 +0100379 current_function_builder_->Emit(kExprStoreGlobal);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000380 } else {
Ben Murdoch097c5b22016-05-18 11:27:45 +0100381 current_function_builder_->Emit(kExprSetLocal);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000382 }
Ben Murdoch097c5b22016-05-18 11:27:45 +0100383 is_set_op_ = false;
384 } else {
385 if (var->IsContextSlot()) {
386 current_function_builder_->Emit(kExprLoadGlobal);
387 } else {
388 current_function_builder_->Emit(kExprGetLocal);
389 }
390 }
391 LocalType var_type = TypeOf(expr);
392 DCHECK_NE(kAstStmt, var_type);
393 if (var->IsContextSlot()) {
394 AddLeb128(LookupOrInsertGlobal(var, var_type), false);
395 } else {
396 AddLeb128(LookupOrInsertLocal(var, var_type), true);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000397 }
398 }
399 }
400
401 void VisitLiteral(Literal* expr) {
402 if (in_function_) {
403 if (expr->raw_value()->IsNumber()) {
404 LocalType type = TypeOf(expr);
405 switch (type) {
406 case kAstI32: {
407 int val = static_cast<int>(expr->raw_value()->AsNumber());
408 byte code[] = {WASM_I32(val)};
409 current_function_builder_->EmitCode(code, sizeof(code));
410 break;
411 }
412 case kAstF32: {
413 float val = static_cast<float>(expr->raw_value()->AsNumber());
414 byte code[] = {WASM_F32(val)};
415 current_function_builder_->EmitCode(code, sizeof(code));
416 break;
417 }
418 case kAstF64: {
419 double val = static_cast<double>(expr->raw_value()->AsNumber());
420 byte code[] = {WASM_F64(val)};
421 current_function_builder_->EmitCode(code, sizeof(code));
422 break;
423 }
424 default:
425 UNREACHABLE();
426 }
427 }
428 }
429 }
430
431 void VisitRegExpLiteral(RegExpLiteral* expr) { UNREACHABLE(); }
432
433 void VisitObjectLiteral(ObjectLiteral* expr) {
434 ZoneList<ObjectLiteralProperty*>* props = expr->properties();
435 for (int i = 0; i < props->length(); ++i) {
436 ObjectLiteralProperty* prop = props->at(i);
437 DCHECK(marking_exported);
438 VariableProxy* expr = prop->value()->AsVariableProxy();
Ben Murdoch097c5b22016-05-18 11:27:45 +0100439 DCHECK_NOT_NULL(expr);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000440 Variable* var = expr->var();
441 Literal* name = prop->key()->AsLiteral();
Ben Murdoch097c5b22016-05-18 11:27:45 +0100442 DCHECK_NOT_NULL(name);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000443 DCHECK(name->IsPropertyName());
444 const AstRawString* raw_name = name->AsRawPropertyName();
445 if (var->is_function()) {
446 uint16_t index = LookupOrInsertFunction(var);
447 builder_->FunctionAt(index)->Exported(1);
448 builder_->FunctionAt(index)
449 ->SetName(raw_name->raw_data(), raw_name->length());
450 }
451 }
452 }
453
454 void VisitArrayLiteral(ArrayLiteral* expr) { UNREACHABLE(); }
455
456 void LoadInitFunction() {
Ben Murdoch097c5b22016-05-18 11:27:45 +0100457 current_function_builder_ = builder_->FunctionAt(init_function_index_);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000458 in_function_ = true;
459 }
460
461 void UnLoadInitFunction() {
462 in_function_ = false;
463 current_function_builder_ = nullptr;
464 }
465
Ben Murdoch097c5b22016-05-18 11:27:45 +0100466 void AddFunctionTable(VariableProxy* table, ArrayLiteral* funcs) {
467 FunctionType* func_type =
468 funcs->bounds().lower->AsArray()->Element()->AsFunction();
469 LocalType return_type = TypeFrom(func_type->Result());
470 FunctionSig::Builder sig(zone(), return_type == kAstStmt ? 0 : 1,
471 func_type->Arity());
472 if (return_type != kAstStmt) {
473 sig.AddReturn(static_cast<LocalType>(return_type));
474 }
475 for (int i = 0; i < func_type->Arity(); i++) {
476 sig.AddParam(TypeFrom(func_type->Parameter(i)));
477 }
478 uint16_t signature_index = builder_->AddSignature(sig.Build());
479 InsertFunctionTable(table->var(), next_table_index_, signature_index);
480 next_table_index_ += funcs->values()->length();
481 for (int i = 0; i < funcs->values()->length(); i++) {
482 VariableProxy* func = funcs->values()->at(i)->AsVariableProxy();
483 DCHECK_NOT_NULL(func);
484 builder_->AddIndirectFunction(LookupOrInsertFunction(func->var()));
485 }
486 }
487
488 struct FunctionTableIndices : public ZoneObject {
489 uint32_t start_index;
490 uint16_t signature_index;
491 };
492
493 void InsertFunctionTable(Variable* v, uint32_t start_index,
494 uint16_t signature_index) {
495 FunctionTableIndices* container = new (zone()) FunctionTableIndices();
496 container->start_index = start_index;
497 container->signature_index = signature_index;
498 ZoneHashMap::Entry* entry = function_tables_.LookupOrInsert(
499 v, ComputePointerHash(v), ZoneAllocationPolicy(zone()));
500 entry->value = container;
501 }
502
503 FunctionTableIndices* LookupFunctionTable(Variable* v) {
504 ZoneHashMap::Entry* entry =
505 function_tables_.Lookup(v, ComputePointerHash(v));
506 DCHECK_NOT_NULL(entry);
507 return reinterpret_cast<FunctionTableIndices*>(entry->value);
508 }
509
510 class ImportedFunctionTable {
511 private:
512 class ImportedFunctionIndices : public ZoneObject {
513 public:
514 const unsigned char* name_;
515 int name_length_;
516 WasmModuleBuilder::SignatureMap signature_to_index_;
517
518 ImportedFunctionIndices(const unsigned char* name, int name_length,
519 Zone* zone)
520 : name_(name), name_length_(name_length), signature_to_index_(zone) {}
521 };
522 ZoneHashMap table_;
523 AsmWasmBuilderImpl* builder_;
524
525 public:
526 explicit ImportedFunctionTable(AsmWasmBuilderImpl* builder)
527 : table_(HashMap::PointersMatch, ZoneHashMap::kDefaultHashMapCapacity,
528 ZoneAllocationPolicy(builder->zone())),
529 builder_(builder) {}
530
531 void AddImport(Variable* v, const unsigned char* name, int name_length) {
532 ImportedFunctionIndices* indices = new (builder_->zone())
533 ImportedFunctionIndices(name, name_length, builder_->zone());
534 ZoneHashMap::Entry* entry = table_.LookupOrInsert(
535 v, ComputePointerHash(v), ZoneAllocationPolicy(builder_->zone()));
536 entry->value = indices;
537 }
538
539 uint16_t GetFunctionIndex(Variable* v, FunctionSig* sig) {
540 ZoneHashMap::Entry* entry = table_.Lookup(v, ComputePointerHash(v));
541 DCHECK_NOT_NULL(entry);
542 ImportedFunctionIndices* indices =
543 reinterpret_cast<ImportedFunctionIndices*>(entry->value);
544 WasmModuleBuilder::SignatureMap::iterator pos =
545 indices->signature_to_index_.find(sig);
546 if (pos != indices->signature_to_index_.end()) {
547 return pos->second;
548 } else {
549 uint16_t index = builder_->builder_->AddFunction();
550 indices->signature_to_index_[sig] = index;
551 WasmFunctionBuilder* function = builder_->builder_->FunctionAt(index);
552 function->External(1);
553 function->SetName(indices->name_, indices->name_length_);
554 if (sig->return_count() > 0) {
555 function->ReturnType(sig->GetReturn());
556 }
557 for (size_t i = 0; i < sig->parameter_count(); i++) {
558 function->AddParam(sig->GetParam(i));
559 }
560 return index;
561 }
562 }
563 };
564
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000565 void VisitAssignment(Assignment* expr) {
566 bool in_init = false;
567 if (!in_function_) {
Ben Murdoch097c5b22016-05-18 11:27:45 +0100568 BinaryOperation* binop = expr->value()->AsBinaryOperation();
569 if (binop != nullptr) {
570 Property* prop = binop->left()->AsProperty();
571 DCHECK_NOT_NULL(prop);
572 LoadInitFunction();
573 is_set_op_ = true;
574 RECURSE(Visit(expr->target()));
575 DCHECK(!is_set_op_);
576 if (binop->op() == Token::MUL) {
577 DCHECK(binop->right()->IsLiteral());
578 DCHECK_EQ(1.0, binop->right()->AsLiteral()->raw_value()->AsNumber());
579 DCHECK(binop->right()->AsLiteral()->raw_value()->ContainsDot());
580 VisitForeignVariable(true, prop);
581 } else if (binop->op() == Token::BIT_OR) {
582 DCHECK(binop->right()->IsLiteral());
583 DCHECK_EQ(0.0, binop->right()->AsLiteral()->raw_value()->AsNumber());
584 DCHECK(!binop->right()->AsLiteral()->raw_value()->ContainsDot());
585 VisitForeignVariable(false, prop);
586 } else {
587 UNREACHABLE();
588 }
589 UnLoadInitFunction();
590 return;
591 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000592 // TODO(bradnelson): Get rid of this.
593 if (TypeOf(expr->value()) == kAstStmt) {
Ben Murdoch097c5b22016-05-18 11:27:45 +0100594 Property* prop = expr->value()->AsProperty();
595 if (prop != nullptr) {
596 VariableProxy* vp = prop->obj()->AsVariableProxy();
597 if (vp != nullptr && vp->var()->IsParameter() &&
598 vp->var()->index() == 1) {
599 VariableProxy* target = expr->target()->AsVariableProxy();
600 if (target->bounds().lower->Is(Type::Function())) {
601 const AstRawString* name =
602 prop->key()->AsLiteral()->AsRawPropertyName();
603 imported_function_table_.AddImport(
604 target->var(), name->raw_data(), name->length());
605 }
606 }
607 }
608 ArrayLiteral* funcs = expr->value()->AsArrayLiteral();
609 if (funcs != nullptr &&
610 funcs->bounds().lower->AsArray()->Element()->IsFunction()) {
611 VariableProxy* target = expr->target()->AsVariableProxy();
612 DCHECK_NOT_NULL(target);
613 AddFunctionTable(target, funcs);
614 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000615 return;
616 }
617 in_init = true;
618 LoadInitFunction();
619 }
620 BinaryOperation* value_op = expr->value()->AsBinaryOperation();
621 if (value_op != nullptr && MatchBinaryOperation(value_op) == kAsIs) {
622 VariableProxy* target_var = expr->target()->AsVariableProxy();
623 VariableProxy* effective_value_var = GetLeft(value_op)->AsVariableProxy();
624 if (target_var != nullptr && effective_value_var != nullptr &&
625 target_var->var() == effective_value_var->var()) {
626 block_size_--;
627 return;
628 }
629 }
630 is_set_op_ = true;
631 RECURSE(Visit(expr->target()));
632 DCHECK(!is_set_op_);
633 RECURSE(Visit(expr->value()));
634 if (in_init) {
635 UnLoadInitFunction();
636 }
637 }
638
639 void VisitYield(Yield* expr) { UNREACHABLE(); }
640
641 void VisitThrow(Throw* expr) { UNREACHABLE(); }
642
Ben Murdoch097c5b22016-05-18 11:27:45 +0100643 void VisitForeignVariable(bool is_float, Property* expr) {
644 DCHECK(expr->obj()->AsVariableProxy());
645 DCHECK(VariableLocation::PARAMETER ==
646 expr->obj()->AsVariableProxy()->var()->location());
647 DCHECK_EQ(1, expr->obj()->AsVariableProxy()->var()->index());
648 Literal* key_literal = expr->key()->AsLiteral();
649 DCHECK_NOT_NULL(key_literal);
650 if (!key_literal->value().is_null() && !foreign_.is_null() &&
651 foreign_->IsObject()) {
652 Handle<Name> name =
653 i::Object::ToName(isolate_, key_literal->value()).ToHandleChecked();
654 MaybeHandle<Object> maybe_value = i::Object::GetProperty(foreign_, name);
655 if (!maybe_value.is_null()) {
656 Handle<Object> value = maybe_value.ToHandleChecked();
657 if (is_float) {
658 MaybeHandle<Object> maybe_nvalue = i::Object::ToNumber(value);
659 if (!maybe_nvalue.is_null()) {
660 Handle<Object> nvalue = maybe_nvalue.ToHandleChecked();
661 if (nvalue->IsNumber()) {
662 double val = nvalue->Number();
663 byte code[] = {WASM_F64(val)};
664 current_function_builder_->EmitCode(code, sizeof(code));
665 return;
666 }
667 }
668 } else {
669 MaybeHandle<Object> maybe_nvalue =
670 i::Object::ToInt32(isolate_, value);
671 if (!maybe_nvalue.is_null()) {
672 Handle<Object> nvalue = maybe_nvalue.ToHandleChecked();
673 if (nvalue->IsNumber()) {
674 int32_t val = static_cast<int32_t>(nvalue->Number());
675 byte code[] = {WASM_I32(val)};
676 current_function_builder_->EmitCode(code, sizeof(code));
677 return;
678 }
679 }
680 }
681 }
682 }
683 if (is_float) {
684 byte code[] = {WASM_F64(std::numeric_limits<double>::quiet_NaN())};
685 current_function_builder_->EmitCode(code, sizeof(code));
686 } else {
687 byte code[] = {WASM_I32(0)};
688 current_function_builder_->EmitCode(code, sizeof(code));
689 }
690 }
691
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000692 void VisitProperty(Property* expr) {
693 Expression* obj = expr->obj();
Ben Murdoch097c5b22016-05-18 11:27:45 +0100694 DCHECK_EQ(obj->bounds().lower, obj->bounds().upper);
695 Type* type = obj->bounds().lower;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000696 MachineType mtype;
697 int size;
698 if (type->Is(cache_.kUint8Array)) {
699 mtype = MachineType::Uint8();
700 size = 1;
701 } else if (type->Is(cache_.kInt8Array)) {
702 mtype = MachineType::Int8();
703 size = 1;
704 } else if (type->Is(cache_.kUint16Array)) {
705 mtype = MachineType::Uint16();
706 size = 2;
707 } else if (type->Is(cache_.kInt16Array)) {
708 mtype = MachineType::Int16();
709 size = 2;
710 } else if (type->Is(cache_.kUint32Array)) {
711 mtype = MachineType::Uint32();
712 size = 4;
713 } else if (type->Is(cache_.kInt32Array)) {
714 mtype = MachineType::Int32();
715 size = 4;
716 } else if (type->Is(cache_.kUint32Array)) {
717 mtype = MachineType::Uint32();
718 size = 4;
719 } else if (type->Is(cache_.kFloat32Array)) {
720 mtype = MachineType::Float32();
721 size = 4;
722 } else if (type->Is(cache_.kFloat64Array)) {
723 mtype = MachineType::Float64();
724 size = 8;
725 } else {
726 UNREACHABLE();
727 }
728 current_function_builder_->EmitWithU8(
729 WasmOpcodes::LoadStoreOpcodeOf(mtype, is_set_op_),
730 WasmOpcodes::LoadStoreAccessOf(false));
731 is_set_op_ = false;
Ben Murdoch097c5b22016-05-18 11:27:45 +0100732 if (size == 1) {
733 // Allow more general expression in byte arrays than the spec
734 // strictly permits.
735 // Early versions of Emscripten emit HEAP8[HEAP32[..]|0] in
736 // places that strictly should be HEAP8[HEAP32[..]>>0].
737 RECURSE(Visit(expr->key()));
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000738 return;
Ben Murdoch097c5b22016-05-18 11:27:45 +0100739 } else {
740 Literal* value = expr->key()->AsLiteral();
741 if (value) {
742 DCHECK(value->raw_value()->IsNumber());
743 DCHECK_EQ(kAstI32, TypeOf(value));
744 int val = static_cast<int>(value->raw_value()->AsNumber());
745 byte code[] = {WASM_I32(val * size)};
746 current_function_builder_->EmitCode(code, sizeof(code));
747 return;
748 }
749 BinaryOperation* binop = expr->key()->AsBinaryOperation();
750 if (binop) {
751 DCHECK_EQ(Token::SAR, binop->op());
752 DCHECK(binop->right()->AsLiteral()->raw_value()->IsNumber());
753 DCHECK(kAstI32 == TypeOf(binop->right()->AsLiteral()));
754 DCHECK_EQ(size,
755 1 << static_cast<int>(
756 binop->right()->AsLiteral()->raw_value()->AsNumber()));
757 // Mask bottom bits to match asm.js behavior.
758 current_function_builder_->Emit(kExprI32And);
759 byte code[] = {WASM_I8(~(size - 1))};
760 current_function_builder_->EmitCode(code, sizeof(code));
761 RECURSE(Visit(binop->left()));
762 return;
763 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000764 }
765 UNREACHABLE();
766 }
767
768 void VisitCall(Call* expr) {
769 Call::CallType call_type = expr->GetCallType(isolate_);
770 switch (call_type) {
771 case Call::OTHER_CALL: {
772 DCHECK(in_function_);
Ben Murdoch097c5b22016-05-18 11:27:45 +0100773 uint16_t index;
774 VariableProxy* vp = expr->expression()->AsVariableProxy();
775 if (vp != nullptr &&
776 Type::Any()->Is(vp->bounds().lower->AsFunction()->Result())) {
777 LocalType return_type = TypeOf(expr);
778 ZoneList<Expression*>* args = expr->arguments();
779 FunctionSig::Builder sig(zone(), return_type == kAstStmt ? 0 : 1,
780 args->length());
781 if (return_type != kAstStmt) {
782 sig.AddReturn(return_type);
783 }
784 for (int i = 0; i < args->length(); i++) {
785 sig.AddParam(TypeOf(args->at(i)));
786 }
787 index =
788 imported_function_table_.GetFunctionIndex(vp->var(), sig.Build());
789 } else {
790 index = LookupOrInsertFunction(vp->var());
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000791 }
Ben Murdoch097c5b22016-05-18 11:27:45 +0100792 current_function_builder_->Emit(kExprCallFunction);
793 std::vector<uint8_t> index_arr = UnsignedLEB128From(index);
794 current_function_builder_->EmitCode(
795 &index_arr[0], static_cast<uint32_t>(index_arr.size()));
796 break;
797 }
798 case Call::KEYED_PROPERTY_CALL: {
799 DCHECK(in_function_);
800 Property* p = expr->expression()->AsProperty();
801 DCHECK_NOT_NULL(p);
802 VariableProxy* var = p->obj()->AsVariableProxy();
803 DCHECK_NOT_NULL(var);
804 FunctionTableIndices* indices = LookupFunctionTable(var->var());
805 current_function_builder_->EmitWithU8(kExprCallIndirect,
806 indices->signature_index);
807 current_function_builder_->Emit(kExprI32Add);
808 byte code[] = {WASM_I32(indices->start_index)};
809 current_function_builder_->EmitCode(code, sizeof(code));
810 RECURSE(Visit(p->key()));
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000811 break;
812 }
813 default:
814 UNREACHABLE();
815 }
Ben Murdoch097c5b22016-05-18 11:27:45 +0100816 ZoneList<Expression*>* args = expr->arguments();
817 for (int i = 0; i < args->length(); ++i) {
818 Expression* arg = args->at(i);
819 RECURSE(Visit(arg));
820 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000821 }
822
823 void VisitCallNew(CallNew* expr) { UNREACHABLE(); }
824
825 void VisitCallRuntime(CallRuntime* expr) { UNREACHABLE(); }
826
827 void VisitUnaryOperation(UnaryOperation* expr) {
828 switch (expr->op()) {
829 case Token::NOT: {
Ben Murdoch097c5b22016-05-18 11:27:45 +0100830 DCHECK_EQ(kAstI32, TypeOf(expr->expression()));
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000831 current_function_builder_->Emit(kExprBoolNot);
832 break;
833 }
834 default:
835 UNREACHABLE();
836 }
837 RECURSE(Visit(expr->expression()));
838 }
839
840 void VisitCountOperation(CountOperation* expr) { UNREACHABLE(); }
841
842 bool MatchIntBinaryOperation(BinaryOperation* expr, Token::Value op,
843 int32_t val) {
Ben Murdoch097c5b22016-05-18 11:27:45 +0100844 DCHECK_NOT_NULL(expr->right());
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000845 if (expr->op() == op && expr->right()->IsLiteral() &&
846 TypeOf(expr) == kAstI32) {
847 Literal* right = expr->right()->AsLiteral();
848 DCHECK(right->raw_value()->IsNumber());
849 if (static_cast<int32_t>(right->raw_value()->AsNumber()) == val) {
850 return true;
851 }
852 }
853 return false;
854 }
855
856 bool MatchDoubleBinaryOperation(BinaryOperation* expr, Token::Value op,
857 double val) {
Ben Murdoch097c5b22016-05-18 11:27:45 +0100858 DCHECK_NOT_NULL(expr->right());
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000859 if (expr->op() == op && expr->right()->IsLiteral() &&
860 TypeOf(expr) == kAstF64) {
861 Literal* right = expr->right()->AsLiteral();
862 DCHECK(right->raw_value()->IsNumber());
863 if (right->raw_value()->AsNumber() == val) {
864 return true;
865 }
866 }
867 return false;
868 }
869
870 enum ConvertOperation { kNone, kAsIs, kToInt, kToDouble };
871
872 ConvertOperation MatchOr(BinaryOperation* expr) {
Ben Murdoch097c5b22016-05-18 11:27:45 +0100873 if (MatchIntBinaryOperation(expr, Token::BIT_OR, 0) &&
874 (TypeOf(expr->left()) == kAstI32)) {
875 return kAsIs;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000876 } else {
877 return kNone;
878 }
879 }
880
881 ConvertOperation MatchShr(BinaryOperation* expr) {
882 if (MatchIntBinaryOperation(expr, Token::SHR, 0)) {
883 // TODO(titzer): this probably needs to be kToUint
884 return (TypeOf(expr->left()) == kAstI32) ? kAsIs : kToInt;
885 } else {
886 return kNone;
887 }
888 }
889
890 ConvertOperation MatchXor(BinaryOperation* expr) {
891 if (MatchIntBinaryOperation(expr, Token::BIT_XOR, 0xffffffff)) {
Ben Murdoch097c5b22016-05-18 11:27:45 +0100892 DCHECK_EQ(kAstI32, TypeOf(expr->left()));
893 DCHECK_EQ(kAstI32, TypeOf(expr->right()));
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000894 BinaryOperation* op = expr->left()->AsBinaryOperation();
895 if (op != nullptr) {
896 if (MatchIntBinaryOperation(op, Token::BIT_XOR, 0xffffffff)) {
Ben Murdoch097c5b22016-05-18 11:27:45 +0100897 DCHECK_EQ(kAstI32, TypeOf(op->right()));
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000898 if (TypeOf(op->left()) != kAstI32) {
899 return kToInt;
900 } else {
901 return kAsIs;
902 }
903 }
904 }
905 }
906 return kNone;
907 }
908
909 ConvertOperation MatchMul(BinaryOperation* expr) {
910 if (MatchDoubleBinaryOperation(expr, Token::MUL, 1.0)) {
Ben Murdoch097c5b22016-05-18 11:27:45 +0100911 DCHECK_EQ(kAstF64, TypeOf(expr->right()));
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000912 if (TypeOf(expr->left()) != kAstF64) {
913 return kToDouble;
914 } else {
915 return kAsIs;
916 }
917 } else {
918 return kNone;
919 }
920 }
921
922 ConvertOperation MatchBinaryOperation(BinaryOperation* expr) {
923 switch (expr->op()) {
924 case Token::BIT_OR:
925 return MatchOr(expr);
926 case Token::SHR:
927 return MatchShr(expr);
928 case Token::BIT_XOR:
929 return MatchXor(expr);
930 case Token::MUL:
931 return MatchMul(expr);
932 default:
933 return kNone;
934 }
935 }
936
937// Work around Mul + Div being defined in PPC assembler.
938#ifdef Mul
939#undef Mul
940#endif
941#ifdef Div
942#undef Div
943#endif
944
945#define NON_SIGNED_BINOP(op) \
946 static WasmOpcode opcodes[] = { \
947 kExprI32##op, \
948 kExprI32##op, \
949 kExprF32##op, \
950 kExprF64##op \
951 }
952
953#define SIGNED_BINOP(op) \
954 static WasmOpcode opcodes[] = { \
955 kExprI32##op##S, \
956 kExprI32##op##U, \
957 kExprF32##op, \
958 kExprF64##op \
959 }
960
961#define NON_SIGNED_INT_BINOP(op) \
962 static WasmOpcode opcodes[] = { kExprI32##op, kExprI32##op }
963
964#define BINOP_CASE(token, op, V, ignore_sign) \
965 case token: { \
966 V(op); \
967 int type = TypeIndexOf(expr->left(), expr->right(), ignore_sign); \
968 current_function_builder_->Emit(opcodes[type]); \
969 break; \
970 }
971
972 Expression* GetLeft(BinaryOperation* expr) {
973 if (expr->op() == Token::BIT_XOR) {
974 return expr->left()->AsBinaryOperation()->left();
975 } else {
976 return expr->left();
977 }
978 }
979
980 void VisitBinaryOperation(BinaryOperation* expr) {
981 ConvertOperation convertOperation = MatchBinaryOperation(expr);
982 if (convertOperation == kToDouble) {
983 TypeIndex type = TypeIndexOf(expr->left());
984 if (type == kInt32 || type == kFixnum) {
985 current_function_builder_->Emit(kExprF64SConvertI32);
986 } else if (type == kUint32) {
987 current_function_builder_->Emit(kExprF64UConvertI32);
988 } else if (type == kFloat32) {
989 current_function_builder_->Emit(kExprF64ConvertF32);
990 } else {
991 UNREACHABLE();
992 }
993 RECURSE(Visit(expr->left()));
994 } else if (convertOperation == kToInt) {
995 TypeIndex type = TypeIndexOf(GetLeft(expr));
996 if (type == kFloat32) {
997 current_function_builder_->Emit(kExprI32SConvertF32);
998 } else if (type == kFloat64) {
999 current_function_builder_->Emit(kExprI32SConvertF64);
1000 } else {
1001 UNREACHABLE();
1002 }
1003 RECURSE(Visit(GetLeft(expr)));
1004 } else if (convertOperation == kAsIs) {
1005 RECURSE(Visit(GetLeft(expr)));
1006 } else {
1007 switch (expr->op()) {
1008 BINOP_CASE(Token::ADD, Add, NON_SIGNED_BINOP, true);
1009 BINOP_CASE(Token::SUB, Sub, NON_SIGNED_BINOP, true);
1010 BINOP_CASE(Token::MUL, Mul, NON_SIGNED_BINOP, true);
1011 BINOP_CASE(Token::DIV, Div, SIGNED_BINOP, false);
1012 BINOP_CASE(Token::BIT_OR, Ior, NON_SIGNED_INT_BINOP, true);
Ben Murdoch097c5b22016-05-18 11:27:45 +01001013 BINOP_CASE(Token::BIT_AND, And, NON_SIGNED_INT_BINOP, true);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001014 BINOP_CASE(Token::BIT_XOR, Xor, NON_SIGNED_INT_BINOP, true);
1015 BINOP_CASE(Token::SHL, Shl, NON_SIGNED_INT_BINOP, true);
1016 BINOP_CASE(Token::SAR, ShrS, NON_SIGNED_INT_BINOP, true);
1017 BINOP_CASE(Token::SHR, ShrU, NON_SIGNED_INT_BINOP, true);
1018 case Token::MOD: {
1019 TypeIndex type = TypeIndexOf(expr->left(), expr->right(), false);
1020 if (type == kInt32) {
1021 current_function_builder_->Emit(kExprI32RemS);
1022 } else if (type == kUint32) {
1023 current_function_builder_->Emit(kExprI32RemU);
1024 } else if (type == kFloat64) {
1025 ModF64(expr);
1026 return;
1027 } else {
1028 UNREACHABLE();
1029 }
1030 break;
1031 }
Ben Murdoch097c5b22016-05-18 11:27:45 +01001032 case Token::COMMA: {
1033 current_function_builder_->EmitWithU8(kExprBlock, 2);
1034 break;
1035 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001036 default:
1037 UNREACHABLE();
1038 }
1039 RECURSE(Visit(expr->left()));
1040 RECURSE(Visit(expr->right()));
1041 }
1042 }
1043
1044 void ModF64(BinaryOperation* expr) {
1045 current_function_builder_->EmitWithU8(kExprBlock, 3);
1046 uint16_t index_0 = current_function_builder_->AddLocal(kAstF64);
1047 uint16_t index_1 = current_function_builder_->AddLocal(kAstF64);
1048 current_function_builder_->Emit(kExprSetLocal);
1049 AddLeb128(index_0, true);
1050 RECURSE(Visit(expr->left()));
1051 current_function_builder_->Emit(kExprSetLocal);
1052 AddLeb128(index_1, true);
1053 RECURSE(Visit(expr->right()));
1054 current_function_builder_->Emit(kExprF64Sub);
1055 current_function_builder_->Emit(kExprGetLocal);
1056 AddLeb128(index_0, true);
1057 current_function_builder_->Emit(kExprF64Mul);
1058 current_function_builder_->Emit(kExprGetLocal);
1059 AddLeb128(index_1, true);
1060 // Use trunc instead of two casts
1061 current_function_builder_->Emit(kExprF64SConvertI32);
1062 current_function_builder_->Emit(kExprI32SConvertF64);
1063 current_function_builder_->Emit(kExprF64Div);
1064 current_function_builder_->Emit(kExprGetLocal);
1065 AddLeb128(index_0, true);
1066 current_function_builder_->Emit(kExprGetLocal);
1067 AddLeb128(index_1, true);
1068 }
1069
1070 void AddLeb128(uint32_t index, bool is_local) {
1071 std::vector<uint8_t> index_vec = UnsignedLEB128From(index);
1072 if (is_local) {
1073 uint32_t pos_of_index[1] = {0};
1074 current_function_builder_->EmitCode(
1075 &index_vec[0], static_cast<uint32_t>(index_vec.size()), pos_of_index,
1076 1);
1077 } else {
1078 current_function_builder_->EmitCode(
1079 &index_vec[0], static_cast<uint32_t>(index_vec.size()));
1080 }
1081 }
1082
1083 void VisitCompareOperation(CompareOperation* expr) {
1084 switch (expr->op()) {
1085 BINOP_CASE(Token::EQ, Eq, NON_SIGNED_BINOP, false);
1086 BINOP_CASE(Token::LT, Lt, SIGNED_BINOP, false);
1087 BINOP_CASE(Token::LTE, Le, SIGNED_BINOP, false);
1088 BINOP_CASE(Token::GT, Gt, SIGNED_BINOP, false);
1089 BINOP_CASE(Token::GTE, Ge, SIGNED_BINOP, false);
1090 default:
1091 UNREACHABLE();
1092 }
1093 RECURSE(Visit(expr->left()));
1094 RECURSE(Visit(expr->right()));
1095 }
1096
1097#undef BINOP_CASE
1098#undef NON_SIGNED_INT_BINOP
1099#undef SIGNED_BINOP
1100#undef NON_SIGNED_BINOP
1101
1102 enum TypeIndex {
1103 kInt32 = 0,
1104 kUint32 = 1,
1105 kFloat32 = 2,
1106 kFloat64 = 3,
1107 kFixnum = 4
1108 };
1109
1110 TypeIndex TypeIndexOf(Expression* left, Expression* right, bool ignore_sign) {
1111 TypeIndex left_index = TypeIndexOf(left);
1112 TypeIndex right_index = TypeIndexOf(right);
1113 if (left_index == kFixnum) {
1114 left_index = right_index;
1115 }
1116 if (right_index == kFixnum) {
1117 right_index = left_index;
1118 }
1119 if (left_index == kFixnum && right_index == kFixnum) {
1120 left_index = kInt32;
1121 right_index = kInt32;
1122 }
1123 DCHECK((left_index == right_index) ||
1124 (ignore_sign && (left_index <= 1) && (right_index <= 1)));
1125 return left_index;
1126 }
1127
1128 TypeIndex TypeIndexOf(Expression* expr) {
Ben Murdoch097c5b22016-05-18 11:27:45 +01001129 DCHECK_EQ(expr->bounds().lower, expr->bounds().upper);
1130 Type* type = expr->bounds().lower;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001131 if (type->Is(cache_.kAsmFixnum)) {
1132 return kFixnum;
1133 } else if (type->Is(cache_.kAsmSigned)) {
1134 return kInt32;
1135 } else if (type->Is(cache_.kAsmUnsigned)) {
1136 return kUint32;
1137 } else if (type->Is(cache_.kAsmInt)) {
1138 return kInt32;
1139 } else if (type->Is(cache_.kAsmFloat)) {
1140 return kFloat32;
1141 } else if (type->Is(cache_.kAsmDouble)) {
1142 return kFloat64;
1143 } else {
1144 UNREACHABLE();
1145 return kInt32;
1146 }
1147 }
1148
1149#undef CASE
1150#undef NON_SIGNED_INT
1151#undef SIGNED
1152#undef NON_SIGNED
1153
1154 void VisitThisFunction(ThisFunction* expr) { UNREACHABLE(); }
1155
1156 void VisitDeclarations(ZoneList<Declaration*>* decls) {
1157 for (int i = 0; i < decls->length(); ++i) {
1158 Declaration* decl = decls->at(i);
1159 RECURSE(Visit(decl));
1160 }
1161 }
1162
1163 void VisitClassLiteral(ClassLiteral* expr) { UNREACHABLE(); }
1164
1165 void VisitSpread(Spread* expr) { UNREACHABLE(); }
1166
1167 void VisitSuperPropertyReference(SuperPropertyReference* expr) {
1168 UNREACHABLE();
1169 }
1170
1171 void VisitSuperCallReference(SuperCallReference* expr) { UNREACHABLE(); }
1172
1173 void VisitSloppyBlockFunctionStatement(SloppyBlockFunctionStatement* expr) {
1174 UNREACHABLE();
1175 }
1176
1177 void VisitDoExpression(DoExpression* expr) { UNREACHABLE(); }
1178
Ben Murdoch097c5b22016-05-18 11:27:45 +01001179 void VisitRewritableExpression(RewritableExpression* expr) { UNREACHABLE(); }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001180
1181 struct IndexContainer : public ZoneObject {
1182 uint16_t index;
1183 };
1184
1185 uint16_t LookupOrInsertLocal(Variable* v, LocalType type) {
Ben Murdoch097c5b22016-05-18 11:27:45 +01001186 DCHECK_NOT_NULL(current_function_builder_);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001187 ZoneHashMap::Entry* entry =
1188 local_variables_.Lookup(v, ComputePointerHash(v));
1189 if (entry == nullptr) {
1190 uint16_t index;
1191 if (v->IsParameter()) {
1192 index = current_function_builder_->AddParam(type);
1193 } else {
1194 index = current_function_builder_->AddLocal(type);
1195 }
1196 IndexContainer* container = new (zone()) IndexContainer();
1197 container->index = index;
1198 entry = local_variables_.LookupOrInsert(v, ComputePointerHash(v),
1199 ZoneAllocationPolicy(zone()));
1200 entry->value = container;
1201 }
1202 return (reinterpret_cast<IndexContainer*>(entry->value))->index;
1203 }
1204
1205 uint16_t LookupOrInsertGlobal(Variable* v, LocalType type) {
1206 ZoneHashMap::Entry* entry =
1207 global_variables_.Lookup(v, ComputePointerHash(v));
1208 if (entry == nullptr) {
1209 uint16_t index =
1210 builder_->AddGlobal(WasmOpcodes::MachineTypeFor(type), 0);
1211 IndexContainer* container = new (zone()) IndexContainer();
1212 container->index = index;
1213 entry = global_variables_.LookupOrInsert(v, ComputePointerHash(v),
1214 ZoneAllocationPolicy(zone()));
1215 entry->value = container;
1216 }
1217 return (reinterpret_cast<IndexContainer*>(entry->value))->index;
1218 }
1219
1220 uint16_t LookupOrInsertFunction(Variable* v) {
Ben Murdoch097c5b22016-05-18 11:27:45 +01001221 DCHECK_NOT_NULL(builder_);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001222 ZoneHashMap::Entry* entry = functions_.Lookup(v, ComputePointerHash(v));
1223 if (entry == nullptr) {
1224 uint16_t index = builder_->AddFunction();
1225 IndexContainer* container = new (zone()) IndexContainer();
1226 container->index = index;
1227 entry = functions_.LookupOrInsert(v, ComputePointerHash(v),
1228 ZoneAllocationPolicy(zone()));
1229 entry->value = container;
1230 }
1231 return (reinterpret_cast<IndexContainer*>(entry->value))->index;
1232 }
1233
1234 LocalType TypeOf(Expression* expr) {
Ben Murdoch097c5b22016-05-18 11:27:45 +01001235 DCHECK_EQ(expr->bounds().lower, expr->bounds().upper);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001236 return TypeFrom(expr->bounds().lower);
1237 }
1238
Ben Murdoch097c5b22016-05-18 11:27:45 +01001239 LocalType TypeFrom(Type* type) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001240 if (type->Is(cache_.kAsmInt)) {
1241 return kAstI32;
1242 } else if (type->Is(cache_.kAsmFloat)) {
1243 return kAstF32;
1244 } else if (type->Is(cache_.kAsmDouble)) {
1245 return kAstF64;
1246 } else {
1247 return kAstStmt;
1248 }
1249 }
1250
1251 Zone* zone() { return zone_; }
1252
1253 ZoneHashMap local_variables_;
1254 ZoneHashMap functions_;
1255 ZoneHashMap global_variables_;
1256 bool in_function_;
1257 bool is_set_op_;
1258 bool marking_exported;
1259 WasmModuleBuilder* builder_;
1260 WasmFunctionBuilder* current_function_builder_;
1261 FunctionLiteral* literal_;
1262 Isolate* isolate_;
1263 Zone* zone_;
Ben Murdoch097c5b22016-05-18 11:27:45 +01001264 Handle<Object> foreign_;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001265 TypeCache const& cache_;
1266 ZoneVector<std::pair<BreakableStatement*, bool>> breakable_blocks_;
1267 int block_size_;
Ben Murdoch097c5b22016-05-18 11:27:45 +01001268 uint16_t init_function_index_;
1269 uint32_t next_table_index_;
1270 ZoneHashMap function_tables_;
1271 ImportedFunctionTable imported_function_table_;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001272
1273 DEFINE_AST_VISITOR_SUBCLASS_MEMBERS();
1274
1275 private:
1276 DISALLOW_COPY_AND_ASSIGN(AsmWasmBuilderImpl);
1277};
1278
1279AsmWasmBuilder::AsmWasmBuilder(Isolate* isolate, Zone* zone,
Ben Murdoch097c5b22016-05-18 11:27:45 +01001280 FunctionLiteral* literal, Handle<Object> foreign)
1281 : isolate_(isolate), zone_(zone), literal_(literal), foreign_(foreign) {}
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001282
1283// TODO(aseemgarg): probably should take zone (to write wasm to) as input so
1284// that zone in constructor may be thrown away once wasm module is written.
1285WasmModuleIndex* AsmWasmBuilder::Run() {
Ben Murdoch097c5b22016-05-18 11:27:45 +01001286 AsmWasmBuilderImpl impl(isolate_, zone_, literal_, foreign_);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001287 impl.Compile();
1288 WasmModuleWriter* writer = impl.builder_->Build(zone_);
1289 return writer->WriteTo(zone_);
1290}
1291} // namespace wasm
1292} // namespace internal
1293} // namespace v8