Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(1117)

Side by Side Diff: src/wasm/asm-wasm-builder.cc

Issue 1504713014: Initial import of v8-native WASM. (Closed) Base URL: https://chromium.googlesource.com/v8/v8.git@master
Patch Set: Created 5 years ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « src/wasm/asm-wasm-builder.h ('k') | src/wasm/ast-decoder.h » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
(Empty)
1 // Copyright 2015 the V8 project authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 #include "src/v8.h"
6
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
16 namespace v8 {
17 namespace internal {
18 namespace wasm {
19
20 #define RECURSE(call) \
21 do { \
22 DCHECK(!HasStackOverflow()); \
23 call; \
24 if (HasStackOverflow()) return; \
25 } while (false)
26
27
28 class AsmWasmBuilderImpl : public AstVisitor {
29 public:
30 AsmWasmBuilderImpl(Isolate* isolate, Zone* zone, FunctionLiteral* literal)
31 : local_variables_(HashMap::PointersMatch,
32 ZoneHashMap::kDefaultHashMapCapacity,
33 ZoneAllocationPolicy(zone)),
34 functions_(HashMap::PointersMatch, ZoneHashMap::kDefaultHashMapCapacity,
35 ZoneAllocationPolicy(zone)),
36 global_variables_(HashMap::PointersMatch,
37 ZoneHashMap::kDefaultHashMapCapacity,
38 ZoneAllocationPolicy(zone)),
39 in_function_(false),
40 is_set_op_(false),
41 marking_exported(false),
42 builder_(new (zone) WasmModuleBuilder(zone)),
43 current_function_builder_(NULL),
44 literal_(literal),
45 isolate_(isolate),
46 zone_(zone),
47 cache_(TypeCache::Get()),
48 breakable_blocks_(zone),
49 block_size_(0) {
50 InitializeAstVisitor(isolate);
51 }
52
53 void Compile() { RECURSE(VisitFunctionLiteral(literal_)); }
54
55 void VisitVariableDeclaration(VariableDeclaration* decl) {}
56
57 void VisitFunctionDeclaration(FunctionDeclaration* decl) {
58 DCHECK(!in_function_);
59 DCHECK(current_function_builder_ == NULL);
60 uint16_t index = LookupOrInsertFunction(decl->proxy()->var());
61 current_function_builder_ = builder_->FunctionAt(index);
62 in_function_ = true;
63 RECURSE(Visit(decl->fun()));
64 in_function_ = false;
65 current_function_builder_ = NULL;
66 local_variables_.Clear();
67 }
68
69 void VisitImportDeclaration(ImportDeclaration* decl) {}
70
71 void VisitExportDeclaration(ExportDeclaration* decl) {}
72
73 void VisitStatements(ZoneList<Statement*>* stmts) {
74 for (int i = 0; i < stmts->length(); ++i) {
75 Statement* stmt = stmts->at(i);
76 RECURSE(Visit(stmt));
77 if (stmt->IsJump()) break;
78 }
79 }
80
81 void VisitBlock(Block* stmt) {
82 if (in_function_) {
83 breakable_blocks_.push_back(
84 std::make_pair(stmt->AsBreakableStatement(), false));
85 current_function_builder_->Emit(kExprBlock);
86 uint32_t index = current_function_builder_->EmitEditableImmediate(0);
87 int prev_block_size = block_size_;
88 block_size_ = static_cast<byte>(stmt->statements()->length());
89 RECURSE(VisitStatements(stmt->statements()));
90 DCHECK(block_size_ >= 0);
91 current_function_builder_->EditImmediate(index, block_size_);
92 block_size_ = prev_block_size;
93 breakable_blocks_.pop_back();
94 } else {
95 RECURSE(VisitStatements(stmt->statements()));
96 }
97 }
98
99 void VisitExpressionStatement(ExpressionStatement* stmt) {
100 RECURSE(Visit(stmt->expression()));
101 }
102
103 void VisitEmptyStatement(EmptyStatement* stmt) {}
104
105 void VisitEmptyParentheses(EmptyParentheses* paren) { UNREACHABLE(); }
106
107 void VisitIfStatement(IfStatement* stmt) {
108 DCHECK(in_function_);
109 if (stmt->HasElseStatement()) {
110 current_function_builder_->Emit(kExprIfElse);
111 } else {
112 current_function_builder_->Emit(kExprIf);
113 }
114 RECURSE(Visit(stmt->condition()));
115 if (stmt->HasThenStatement()) {
116 RECURSE(Visit(stmt->then_statement()));
117 } else {
118 current_function_builder_->Emit(kExprNop);
119 }
120 if (stmt->HasElseStatement()) {
121 RECURSE(Visit(stmt->else_statement()));
122 }
123 }
124
125 void VisitContinueStatement(ContinueStatement* stmt) {
126 DCHECK(in_function_);
127 int i = static_cast<int>(breakable_blocks_.size()) - 1;
128 int block_distance = 0;
129 for (; i >= 0; i--) {
130 auto elem = breakable_blocks_.at(i);
131 if (elem.first == stmt->target()) {
132 DCHECK(elem.second);
133 break;
134 } else if (elem.second) {
135 block_distance += 2;
136 } else {
137 block_distance += 1;
138 }
139 }
140 DCHECK(i >= 0);
141 current_function_builder_->EmitWithU8(kExprBr, block_distance);
142 current_function_builder_->Emit(kExprNop);
143 }
144
145 void VisitBreakStatement(BreakStatement* stmt) {
146 DCHECK(in_function_);
147 int i = static_cast<int>(breakable_blocks_.size()) - 1;
148 int block_distance = 0;
149 for (; i >= 0; i--) {
150 auto elem = breakable_blocks_.at(i);
151 if (elem.first == stmt->target()) {
152 if (elem.second) {
153 block_distance++;
154 }
155 break;
156 } else if (elem.second) {
157 block_distance += 2;
158 } else {
159 block_distance += 1;
160 }
161 }
162 DCHECK(i >= 0);
163 current_function_builder_->EmitWithU8(kExprBr, block_distance);
164 current_function_builder_->Emit(kExprNop);
165 }
166
167 void VisitReturnStatement(ReturnStatement* stmt) {
168 if (in_function_) {
169 current_function_builder_->Emit(kExprReturn);
170 } else {
171 marking_exported = true;
172 }
173 RECURSE(Visit(stmt->expression()));
174 if (!in_function_) {
175 marking_exported = false;
176 }
177 }
178
179 void VisitWithStatement(WithStatement* stmt) {
180 RECURSE(stmt->expression());
181 RECURSE(stmt->statement());
182 }
183
184 void VisitSwitchStatement(SwitchStatement* stmt) {
185 RECURSE(Visit(stmt->tag()));
186
187 ZoneList<CaseClause*>* clauses = stmt->cases();
188
189 for (int i = 0; i < clauses->length(); ++i) {
190 CaseClause* clause = clauses->at(i);
191 if (!clause->is_default()) {
192 Expression* label = clause->label();
193 RECURSE(Visit(label));
194 }
195 ZoneList<Statement*>* stmts = clause->statements();
196 RECURSE(VisitStatements(stmts));
197 }
198 }
199
200 void VisitCaseClause(CaseClause* clause) { UNREACHABLE(); }
201
202 void VisitDoWhileStatement(DoWhileStatement* stmt) {
203 RECURSE(Visit(stmt->body()));
204 RECURSE(Visit(stmt->cond()));
205 }
206
207 void VisitWhileStatement(WhileStatement* stmt) {
208 DCHECK(in_function_);
209 current_function_builder_->EmitWithU8(kExprLoop, 1);
210 breakable_blocks_.push_back(
211 std::make_pair(stmt->AsBreakableStatement(), true));
212 current_function_builder_->Emit(kExprIf);
213 RECURSE(Visit(stmt->cond()));
214 current_function_builder_->EmitWithU8(kExprBr, 0);
215 RECURSE(Visit(stmt->body()));
216 breakable_blocks_.pop_back();
217 }
218
219 void VisitForStatement(ForStatement* stmt) {
220 if (stmt->init() != NULL) {
221 RECURSE(Visit(stmt->init()));
222 }
223 if (stmt->cond() != NULL) {
224 RECURSE(Visit(stmt->cond()));
225 }
226 if (stmt->next() != NULL) {
227 RECURSE(Visit(stmt->next()));
228 }
229 RECURSE(Visit(stmt->body()));
230 }
231
232 void VisitForInStatement(ForInStatement* stmt) {
233 RECURSE(Visit(stmt->enumerable()));
234 RECURSE(Visit(stmt->body()));
235 }
236
237 void VisitForOfStatement(ForOfStatement* stmt) {
238 RECURSE(Visit(stmt->iterable()));
239 RECURSE(Visit(stmt->body()));
240 }
241
242 void VisitTryCatchStatement(TryCatchStatement* stmt) {
243 RECURSE(Visit(stmt->try_block()));
244 RECURSE(Visit(stmt->catch_block()));
245 }
246
247 void VisitTryFinallyStatement(TryFinallyStatement* stmt) {
248 RECURSE(Visit(stmt->try_block()));
249 RECURSE(Visit(stmt->finally_block()));
250 }
251
252 void VisitDebuggerStatement(DebuggerStatement* stmt) {}
253
254 void VisitFunctionLiteral(FunctionLiteral* expr) {
255 Scope* scope = expr->scope();
256 if (in_function_) {
257 if (expr->bounds().lower->IsFunction()) {
258 Type::FunctionType* func_type = expr->bounds().lower->AsFunction();
259 LocalType return_type = TypeFrom(func_type->Result());
260 current_function_builder_->ReturnType(return_type);
261 for (int i = 0; i < expr->parameter_count(); i++) {
262 LocalType type = TypeFrom(func_type->Parameter(i));
263 DCHECK(type != kAstStmt);
264 LookupOrInsertLocal(scope->parameter(i), type);
265 }
266 } else {
267 UNREACHABLE();
268 }
269 }
270 RECURSE(VisitDeclarations(scope->declarations()));
271 RECURSE(VisitStatements(expr->body()));
272 }
273
274 void VisitNativeFunctionLiteral(NativeFunctionLiteral* expr) {}
275
276 void VisitConditional(Conditional* expr) {
277 RECURSE(Visit(expr->condition()));
278 RECURSE(Visit(expr->then_expression()));
279 RECURSE(Visit(expr->else_expression()));
280 }
281
282 void VisitVariableProxy(VariableProxy* expr) {
283 if (in_function_) {
284 Variable* var = expr->var();
285 if (var->is_function()) {
286 DCHECK(!is_set_op_);
287 std::vector<uint8_t> index =
288 UnsignedLEB128From(LookupOrInsertFunction(var));
289 current_function_builder_->EmitCode(
290 index.data(), static_cast<uint32_t>(index.size()));
291 } else {
292 if (is_set_op_) {
293 if (var->IsContextSlot()) {
294 current_function_builder_->Emit(kExprStoreGlobal);
295 } else {
296 current_function_builder_->Emit(kExprSetLocal);
297 }
298 is_set_op_ = false;
299 } else {
300 if (var->IsContextSlot()) {
301 current_function_builder_->Emit(kExprLoadGlobal);
302 } else {
303 current_function_builder_->Emit(kExprGetLocal);
304 }
305 }
306 LocalType var_type = TypeOf(expr);
307 DCHECK(var_type != kAstStmt);
308 if (var->IsContextSlot()) {
309 AddLeb128(LookupOrInsertGlobal(var, var_type), false);
310 } else {
311 AddLeb128(LookupOrInsertLocal(var, var_type), true);
312 }
313 }
314 } else if (marking_exported) {
315 Variable* var = expr->var();
316 if (var->is_function()) {
317 uint16_t index = LookupOrInsertFunction(var);
318 builder_->FunctionAt(index)->Exported(1);
319 }
320 }
321 }
322
323 void VisitLiteral(Literal* expr) {
324 if (in_function_) {
325 if (expr->raw_value()->IsNumber()) {
326 LocalType type = TypeOf(expr);
327 switch (type) {
328 case kAstI32: {
329 int val = static_cast<int>(expr->raw_value()->AsNumber());
330 byte code[] = {WASM_I32(val)};
331 current_function_builder_->EmitCode(code, sizeof(code));
332 break;
333 }
334 case kAstF32: {
335 float val = static_cast<float>(expr->raw_value()->AsNumber());
336 byte code[] = {WASM_F32(val)};
337 current_function_builder_->EmitCode(code, sizeof(code));
338 break;
339 }
340 case kAstF64: {
341 double val = static_cast<double>(expr->raw_value()->AsNumber());
342 byte code[] = {WASM_F64(val)};
343 current_function_builder_->EmitCode(code, sizeof(code));
344 break;
345 }
346 default:
347 UNREACHABLE();
348 }
349 }
350 }
351 }
352
353 void VisitRegExpLiteral(RegExpLiteral* expr) {}
354
355 void VisitObjectLiteral(ObjectLiteral* expr) {
356 ZoneList<ObjectLiteralProperty*>* props = expr->properties();
357 for (int i = 0; i < props->length(); ++i) {
358 ObjectLiteralProperty* prop = props->at(i);
359 RECURSE(Visit(prop->value()));
360 }
361 }
362
363 void VisitArrayLiteral(ArrayLiteral* expr) {
364 ZoneList<Expression*>* values = expr->values();
365 for (int i = 0; i < values->length(); ++i) {
366 Expression* value = values->at(i);
367 RECURSE(Visit(value));
368 }
369 }
370
371 void VisitAssignment(Assignment* expr) {
372 if (in_function_) {
373 BinaryOperation* value_op = expr->value()->AsBinaryOperation();
374 if (value_op != NULL && MatchBinaryOperation(value_op) == kAsIs) {
375 VariableProxy* target_var = expr->target()->AsVariableProxy();
376 VariableProxy* effective_value_var =
377 GetLeft(value_op)->AsVariableProxy();
378 // TODO(aseemgarg): simplify block_size_ or replace with a kNop
379 if (target_var != NULL && effective_value_var != NULL &&
380 target_var->var() == effective_value_var->var()) {
381 block_size_--;
382 return;
383 }
384 }
385 is_set_op_ = true;
386 RECURSE(Visit(expr->target()));
387 DCHECK(!is_set_op_);
388 RECURSE(Visit(expr->value()));
389 }
390 }
391
392 void VisitYield(Yield* expr) {
393 RECURSE(Visit(expr->generator_object()));
394 RECURSE(Visit(expr->expression()));
395 }
396
397 void VisitThrow(Throw* expr) { RECURSE(Visit(expr->exception())); }
398
399 void VisitProperty(Property* expr) {
400 Expression* obj = expr->obj();
401 DCHECK(obj->bounds().lower == obj->bounds().upper);
402 TypeImpl<ZoneTypeConfig>* type = obj->bounds().lower;
403 MachineType mtype;
404 int size;
405 if (type->Is(cache_.kUint8Array)) {
406 mtype = MachineType::Uint8();
407 size = 1;
408 } else if (type->Is(cache_.kInt8Array)) {
409 mtype = MachineType::Int8();
410 size = 1;
411 } else if (type->Is(cache_.kUint16Array)) {
412 mtype = MachineType::Uint16();
413 size = 2;
414 } else if (type->Is(cache_.kInt16Array)) {
415 mtype = MachineType::Int16();
416 size = 2;
417 } else if (type->Is(cache_.kUint32Array)) {
418 mtype = MachineType::Uint32();
419 size = 4;
420 } else if (type->Is(cache_.kInt32Array)) {
421 mtype = MachineType::Int32();
422 size = 4;
423 } else if (type->Is(cache_.kUint32Array)) {
424 mtype = MachineType::Uint32();
425 size = 4;
426 } else if (type->Is(cache_.kFloat32Array)) {
427 mtype = MachineType::Float32();
428 size = 4;
429 } else if (type->Is(cache_.kFloat64Array)) {
430 mtype = MachineType::Float64();
431 size = 8;
432 } else {
433 UNREACHABLE();
434 }
435 current_function_builder_->EmitWithU8(
436 WasmOpcodes::LoadStoreOpcodeOf(mtype, is_set_op_),
437 WasmOpcodes::LoadStoreAccessOf(false));
438 is_set_op_ = false;
439 Literal* value = expr->key()->AsLiteral();
440 if (value) {
441 DCHECK(value->raw_value()->IsNumber());
442 DCHECK(kAstI32 == TypeOf(value));
443 int val = static_cast<int>(value->raw_value()->AsNumber());
444 byte code[] = {WASM_I32(val * size)};
445 current_function_builder_->EmitCode(code, sizeof(code));
446 return;
447 }
448 BinaryOperation* binop = expr->key()->AsBinaryOperation();
449 if (binop) {
450 DCHECK(Token::SAR == binop->op());
451 DCHECK(binop->right()->AsLiteral()->raw_value()->IsNumber());
452 DCHECK(kAstI32 == TypeOf(binop->right()->AsLiteral()));
453 DCHECK(size ==
454 1 << static_cast<int>(
455 binop->right()->AsLiteral()->raw_value()->AsNumber()));
456 // Mask bottom bits to match asm.js behavior.
457 current_function_builder_->Emit(kExprI32And);
458 byte code[] = {WASM_I8(~(size - 1))};
459 current_function_builder_->EmitCode(code, sizeof(code));
460 RECURSE(Visit(binop->left()));
461 return;
462 }
463 UNREACHABLE();
464 }
465
466 void VisitCall(Call* expr) {
467 Call::CallType call_type = expr->GetCallType(isolate_);
468 switch (call_type) {
469 case Call::OTHER_CALL: {
470 DCHECK(in_function_);
471 current_function_builder_->Emit(kExprCallFunction);
472 RECURSE(Visit(expr->expression()));
473 ZoneList<Expression*>* args = expr->arguments();
474 for (int i = 0; i < args->length(); ++i) {
475 Expression* arg = args->at(i);
476 RECURSE(Visit(arg));
477 }
478 break;
479 }
480 default:
481 UNREACHABLE();
482 }
483 }
484
485 void VisitCallNew(CallNew* expr) { UNREACHABLE(); }
486
487 void VisitCallRuntime(CallRuntime* expr) { UNREACHABLE(); }
488
489 void VisitUnaryOperation(UnaryOperation* expr) {
490 switch (expr->op()) {
491 case Token::NOT: {
492 DCHECK(TypeOf(expr->expression()) == kAstI32);
493 current_function_builder_->Emit(kExprBoolNot);
494 break;
495 }
496 default:
497 UNREACHABLE();
498 }
499 RECURSE(Visit(expr->expression()));
500 }
501
502 void VisitCountOperation(CountOperation* expr) {
503 RECURSE(Visit(expr->expression()));
504 }
505
506 bool MatchIntBinaryOperation(BinaryOperation* expr, Token::Value op,
507 int32_t val) {
508 DCHECK(expr->right() != NULL);
509 if (expr->op() == op && expr->right()->IsLiteral() &&
510 TypeOf(expr) == kAstI32) {
511 Literal* right = expr->right()->AsLiteral();
512 DCHECK(right->raw_value()->IsNumber());
513 if (static_cast<int32_t>(right->raw_value()->AsNumber()) == val) {
514 return true;
515 }
516 }
517 return false;
518 }
519
520 bool MatchDoubleBinaryOperation(BinaryOperation* expr, Token::Value op,
521 double val) {
522 DCHECK(expr->right() != NULL);
523 if (expr->op() == op && expr->right()->IsLiteral() &&
524 TypeOf(expr) == kAstF64) {
525 Literal* right = expr->right()->AsLiteral();
526 DCHECK(right->raw_value()->IsNumber());
527 if (right->raw_value()->AsNumber() == val) {
528 return true;
529 }
530 }
531 return false;
532 }
533
534 enum ConvertOperation { kNone, kAsIs, kToInt, kToDouble };
535
536 ConvertOperation MatchOr(BinaryOperation* expr) {
537 if (MatchIntBinaryOperation(expr, Token::BIT_OR, 0)) {
538 DCHECK(TypeOf(expr->left()) == kAstI32);
539 DCHECK(TypeOf(expr->right()) == kAstI32);
540 return kAsIs;
541 } else {
542 return kNone;
543 }
544 }
545
546 ConvertOperation MatchShr(BinaryOperation* expr) {
547 if (MatchIntBinaryOperation(expr, Token::SHR, 0)) {
548 DCHECK(TypeOf(expr->left()) == kAstI32);
549 DCHECK(TypeOf(expr->right()) == kAstI32);
550 return kAsIs;
551 } else {
552 return kNone;
553 }
554 }
555
556 ConvertOperation MatchXor(BinaryOperation* expr) {
557 if (MatchIntBinaryOperation(expr, Token::BIT_XOR, 0xffffffff)) {
558 DCHECK(TypeOf(expr->left()) == kAstI32);
559 DCHECK(TypeOf(expr->right()) == kAstI32);
560 BinaryOperation* op = expr->left()->AsBinaryOperation();
561 if (op != NULL) {
562 if (MatchIntBinaryOperation(op, Token::BIT_XOR, 0xffffffff)) {
563 DCHECK(TypeOf(op->right()) == kAstI32);
564 if (TypeOf(op->left()) != kAstI32) {
565 return kToInt;
566 } else {
567 return kAsIs;
568 }
569 }
570 }
571 }
572 return kNone;
573 }
574
575 ConvertOperation MatchMul(BinaryOperation* expr) {
576 if (MatchDoubleBinaryOperation(expr, Token::MUL, 1.0)) {
577 DCHECK(TypeOf(expr->right()) == kAstF64);
578 if (TypeOf(expr->left()) != kAstF64) {
579 return kToDouble;
580 } else {
581 return kAsIs;
582 }
583 } else {
584 return kNone;
585 }
586 }
587
588 ConvertOperation MatchBinaryOperation(BinaryOperation* expr) {
589 switch (expr->op()) {
590 case Token::BIT_OR:
591 return MatchOr(expr);
592 case Token::SHR:
593 return MatchShr(expr);
594 case Token::BIT_XOR:
595 return MatchXor(expr);
596 case Token::MUL:
597 return MatchMul(expr);
598 default:
599 return kNone;
600 }
601 }
602
603 #define NON_SIGNED_BINOP(op) \
604 static WasmOpcode opcodes[] = { \
605 kExprI32##op, \
606 kExprI32##op, \
607 kExprF32##op, \
608 kExprF64##op \
609 }
610
611 #define SIGNED_BINOP(op) \
612 static WasmOpcode opcodes[] = { \
613 kExprI32##op##S, \
614 kExprI32##op##U, \
615 kExprF32##op, \
616 kExprF64##op \
617 }
618
619 #define NON_SIGNED_INT_BINOP(op) \
620 static WasmOpcode opcodes[] = { kExprI32##op, kExprI32##op }
621
622 #define BINOP_CASE(token, op, V, ignore_sign) \
623 case token: { \
624 V(op); \
625 int type = TypeIndexOf(expr->left(), expr->right(), ignore_sign); \
626 current_function_builder_->Emit(opcodes[type]); \
627 break; \
628 }
629
630 Expression* GetLeft(BinaryOperation* expr) {
631 if (expr->op() == Token::BIT_XOR) {
632 return expr->left()->AsBinaryOperation()->left();
633 } else {
634 return expr->left();
635 }
636 }
637
638 void VisitBinaryOperation(BinaryOperation* expr) {
639 ConvertOperation convertOperation = MatchBinaryOperation(expr);
640 if (convertOperation == kToDouble) {
641 TypeIndex type = TypeIndexOf(expr->left());
642 if (type == kInt32 || type == kFixnum) {
643 current_function_builder_->Emit(kExprF64SConvertI32);
644 } else if (type == kUint32) {
645 current_function_builder_->Emit(kExprF64UConvertI32);
646 } else if (type == kFloat32) {
647 current_function_builder_->Emit(kExprF64ConvertF32);
648 } else {
649 UNREACHABLE();
650 }
651 RECURSE(Visit(expr->left()));
652 } else if (convertOperation == kToInt) {
653 TypeIndex type = TypeIndexOf(GetLeft(expr));
654 if (type == kFloat32) {
655 current_function_builder_->Emit(kExprI32SConvertF32);
656 } else if (type == kFloat64) {
657 current_function_builder_->Emit(kExprI32SConvertF64);
658 } else {
659 UNREACHABLE();
660 }
661 RECURSE(Visit(GetLeft(expr)));
662 } else if (convertOperation == kAsIs) {
663 RECURSE(Visit(GetLeft(expr)));
664 } else {
665 switch (expr->op()) {
666 BINOP_CASE(Token::ADD, Add, NON_SIGNED_BINOP, true);
667 BINOP_CASE(Token::SUB, Sub, NON_SIGNED_BINOP, true);
668 BINOP_CASE(Token::MUL, Mul, NON_SIGNED_BINOP, true);
669 BINOP_CASE(Token::DIV, Div, SIGNED_BINOP, false);
670 BINOP_CASE(Token::BIT_OR, Ior, NON_SIGNED_INT_BINOP, true);
671 BINOP_CASE(Token::BIT_XOR, Xor, NON_SIGNED_INT_BINOP, true);
672 BINOP_CASE(Token::SHL, Shl, NON_SIGNED_INT_BINOP, true);
673 BINOP_CASE(Token::SAR, ShrS, NON_SIGNED_INT_BINOP, true);
674 BINOP_CASE(Token::SHR, ShrU, NON_SIGNED_INT_BINOP, true);
675 case Token::MOD: {
676 TypeIndex type = TypeIndexOf(expr->left(), expr->right(), false);
677 if (type == kInt32) {
678 current_function_builder_->Emit(kExprI32RemS);
679 } else if (type == kUint32) {
680 current_function_builder_->Emit(kExprI32RemU);
681 } else if (type == kFloat64) {
682 ModF64(expr);
683 return;
684 } else {
685 UNREACHABLE();
686 }
687 break;
688 }
689 default:
690 UNREACHABLE();
691 }
692 RECURSE(Visit(expr->left()));
693 RECURSE(Visit(expr->right()));
694 }
695 }
696
697 void ModF64(BinaryOperation* expr) {
698 current_function_builder_->EmitWithU8(kExprBlock, 3);
699 uint16_t index_0 = current_function_builder_->AddLocal(kAstF64);
700 uint16_t index_1 = current_function_builder_->AddLocal(kAstF64);
701 current_function_builder_->Emit(kExprSetLocal);
702 AddLeb128(index_0, true);
703 RECURSE(Visit(expr->left()));
704 current_function_builder_->Emit(kExprSetLocal);
705 AddLeb128(index_1, true);
706 RECURSE(Visit(expr->right()));
707 current_function_builder_->Emit(kExprF64Sub);
708 current_function_builder_->Emit(kExprGetLocal);
709 AddLeb128(index_0, true);
710 current_function_builder_->Emit(kExprF64Mul);
711 current_function_builder_->Emit(kExprGetLocal);
712 AddLeb128(index_1, true);
713 // Use trunc instead of two casts
714 current_function_builder_->Emit(kExprF64SConvertI32);
715 current_function_builder_->Emit(kExprI32SConvertF64);
716 current_function_builder_->Emit(kExprF64Div);
717 current_function_builder_->Emit(kExprGetLocal);
718 AddLeb128(index_0, true);
719 current_function_builder_->Emit(kExprGetLocal);
720 AddLeb128(index_1, true);
721 }
722
723 void AddLeb128(uint32_t index, bool is_local) {
724 std::vector<uint8_t> index_vec = UnsignedLEB128From(index);
725 if (is_local) {
726 uint32_t pos_of_index[1] = {0};
727 current_function_builder_->EmitCode(
728 index_vec.data(), static_cast<uint32_t>(index_vec.size()),
729 pos_of_index, 1);
730 } else {
731 current_function_builder_->EmitCode(
732 index_vec.data(), static_cast<uint32_t>(index_vec.size()));
733 }
734 }
735
736 void VisitCompareOperation(CompareOperation* expr) {
737 switch (expr->op()) {
738 BINOP_CASE(Token::EQ, Eq, NON_SIGNED_BINOP, false);
739 BINOP_CASE(Token::LT, Lt, SIGNED_BINOP, false);
740 BINOP_CASE(Token::LTE, Le, SIGNED_BINOP, false);
741 BINOP_CASE(Token::GT, Gt, SIGNED_BINOP, false);
742 BINOP_CASE(Token::GTE, Ge, SIGNED_BINOP, false);
743 default:
744 UNREACHABLE();
745 }
746 RECURSE(Visit(expr->left()));
747 RECURSE(Visit(expr->right()));
748 }
749
750 #undef BINOP_CASE
751 #undef NON_SIGNED_INT_BINOP
752 #undef SIGNED_BINOP
753 #undef NON_SIGNED_BINOP
754
755 enum TypeIndex {
756 kInt32 = 0,
757 kUint32 = 1,
758 kFloat32 = 2,
759 kFloat64 = 3,
760 kFixnum = 4
761 };
762
763 TypeIndex TypeIndexOf(Expression* left, Expression* right, bool ignore_sign) {
764 TypeIndex left_index = TypeIndexOf(left);
765 TypeIndex right_index = TypeIndexOf(right);
766 if (left_index == kFixnum) {
767 left_index = right_index;
768 }
769 if (right_index == kFixnum) {
770 right_index = left_index;
771 }
772 if (left_index == kFixnum && right_index == kFixnum) {
773 left_index = kInt32;
774 right_index = kInt32;
775 }
776 DCHECK((left_index == right_index) ||
777 (ignore_sign && (left_index <= 1) && (right_index <= 1)));
778 return left_index;
779 }
780
781 TypeIndex TypeIndexOf(Expression* expr) {
782 DCHECK(expr->bounds().lower == expr->bounds().upper);
783 TypeImpl<ZoneTypeConfig>* type = expr->bounds().lower;
784 if (type->Is(cache_.kAsmFixnum)) {
785 return kFixnum;
786 } else if (type->Is(cache_.kAsmSigned)) {
787 return kInt32;
788 } else if (type->Is(cache_.kAsmUnsigned)) {
789 return kUint32;
790 } else if (type->Is(cache_.kAsmInt)) {
791 return kInt32;
792 } else if (type->Is(cache_.kAsmFloat)) {
793 return kFloat32;
794 } else if (type->Is(cache_.kAsmDouble)) {
795 return kFloat64;
796 } else {
797 UNREACHABLE();
798 }
799 }
800
801 #undef CASE
802 #undef NON_SIGNED_INT
803 #undef SIGNED
804 #undef NON_SIGNED
805
806 void VisitThisFunction(ThisFunction* expr) {}
807
808 void VisitDeclarations(ZoneList<Declaration*>* decls) {
809 for (int i = 0; i < decls->length(); ++i) {
810 Declaration* decl = decls->at(i);
811 RECURSE(Visit(decl));
812 }
813 }
814
815 void VisitClassLiteral(ClassLiteral* expr) {}
816
817 void VisitSpread(Spread* expr) {}
818
819 void VisitSuperPropertyReference(SuperPropertyReference* expr) {}
820
821 void VisitSuperCallReference(SuperCallReference* expr) {}
822
823 void VisitSloppyBlockFunctionStatement(SloppyBlockFunctionStatement* expr) {}
824
825 void VisitDoExpression(DoExpression* expr) {}
826
827 void VisitRewritableAssignmentExpression(
828 RewritableAssignmentExpression* expr) {}
829
830 struct IndexContainer : public ZoneObject {
831 uint16_t index;
832 };
833
834 uint16_t LookupOrInsertLocal(Variable* v, LocalType type) {
835 DCHECK(current_function_builder_ != NULL);
836 ZoneHashMap::Entry* entry =
837 local_variables_.Lookup(v, ComputePointerHash(v));
838 if (entry == NULL) {
839 uint16_t index;
840 if (v->IsParameter()) {
841 index = current_function_builder_->AddParam(type);
842 } else {
843 index = current_function_builder_->AddLocal(type);
844 }
845 IndexContainer* container = new (zone()) IndexContainer();
846 container->index = index;
847 entry = local_variables_.LookupOrInsert(v, ComputePointerHash(v),
848 ZoneAllocationPolicy(zone()));
849 entry->value = container;
850 }
851 return (reinterpret_cast<IndexContainer*>(entry->value))->index;
852 }
853
854 uint16_t LookupOrInsertGlobal(Variable* v, LocalType type) {
855 ZoneHashMap::Entry* entry =
856 global_variables_.Lookup(v, ComputePointerHash(v));
857 if (entry == NULL) {
858 uint16_t index =
859 builder_->AddGlobal(WasmOpcodes::MachineTypeFor(type), 0);
860 IndexContainer* container = new (zone()) IndexContainer();
861 container->index = index;
862 entry = global_variables_.LookupOrInsert(v, ComputePointerHash(v),
863 ZoneAllocationPolicy(zone()));
864 entry->value = container;
865 }
866 return (reinterpret_cast<IndexContainer*>(entry->value))->index;
867 }
868
869 uint16_t LookupOrInsertFunction(Variable* v) {
870 DCHECK(builder_ != NULL);
871 ZoneHashMap::Entry* entry = functions_.Lookup(v, ComputePointerHash(v));
872 if (entry == NULL) {
873 uint16_t index = builder_->AddFunction(v->raw_name()->raw_data(),
874 v->raw_name()->length());
875 IndexContainer* container = new (zone()) IndexContainer();
876 container->index = index;
877 entry = functions_.LookupOrInsert(v, ComputePointerHash(v),
878 ZoneAllocationPolicy(zone()));
879 entry->value = container;
880 }
881 return (reinterpret_cast<IndexContainer*>(entry->value))->index;
882 }
883
884 LocalType TypeOf(Expression* expr) {
885 DCHECK(expr->bounds().lower == expr->bounds().upper);
886 return TypeFrom(expr->bounds().lower);
887 }
888
889 LocalType TypeFrom(TypeImpl<ZoneTypeConfig>* type) {
890 if (type->Is(cache_.kAsmInt)) {
891 return kAstI32;
892 } else if (type->Is(cache_.kAsmFloat)) {
893 return kAstF32;
894 } else if (type->Is(cache_.kAsmDouble)) {
895 return kAstF64;
896 } else {
897 return kAstStmt;
898 }
899 }
900
901 Zone* zone() { return zone_; }
902
903 ZoneHashMap local_variables_;
904 ZoneHashMap functions_;
905 ZoneHashMap global_variables_;
906 bool in_function_;
907 bool is_set_op_;
908 bool marking_exported;
909 WasmModuleBuilder* builder_;
910 WasmFunctionBuilder* current_function_builder_;
911 FunctionLiteral* literal_;
912 Isolate* isolate_;
913 Zone* zone_;
914 TypeCache const& cache_;
915 ZoneVector<std::pair<BreakableStatement*, bool>> breakable_blocks_;
916 int block_size_;
917
918 DEFINE_AST_VISITOR_SUBCLASS_MEMBERS();
919
920 private:
921 DISALLOW_COPY_AND_ASSIGN(AsmWasmBuilderImpl);
922 };
923
924 AsmWasmBuilder::AsmWasmBuilder(Isolate* isolate, Zone* zone,
925 FunctionLiteral* literal)
926 : isolate_(isolate), zone_(zone), literal_(literal) {}
927
928 // TODO(aseemgarg): probably should take zone (to write wasm to) as input so
929 // that zone in constructor may be thrown away once wasm module is written.
930 WasmModuleIndex* AsmWasmBuilder::Run() {
931 AsmWasmBuilderImpl impl(isolate_, zone_, literal_);
932 impl.Compile();
933 WasmModuleWriter* writer = impl.builder_->Build(zone_);
934 return writer->WriteTo(zone_);
935 }
936 } // namespace wasm
937 } // namespace internal
938 } // namespace v8
OLDNEW
« no previous file with comments | « src/wasm/asm-wasm-builder.h ('k') | src/wasm/ast-decoder.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698