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

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

Issue 2057403003: Hooking up asm-wasm conversion. (Closed) Base URL: https://chromium.googlesource.com/v8/v8.git@master
Patch Set: fix Created 4 years, 5 months 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/wasm-js.cc » ('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 // Required to get M_E etc. in MSVC.
8 #if defined(_WIN32)
9 #define _USE_MATH_DEFINES
10 #endif
11 #include <math.h>
12
13 #include "src/wasm/asm-wasm-builder.h"
14 #include "src/wasm/switch-logic.h"
15 #include "src/wasm/wasm-macro-gen.h"
16 #include "src/wasm/wasm-opcodes.h"
17
18 #include "src/ast/ast.h"
19 #include "src/ast/scopes.h"
20 #include "src/codegen.h"
21 #include "src/type-cache.h"
22
23 namespace v8 {
24 namespace internal {
25 namespace wasm {
26
27 #define RECURSE(call) \
28 do { \
29 DCHECK(!HasStackOverflow()); \
30 call; \
31 if (HasStackOverflow()) return; \
32 } while (false)
33
34 enum AsmScope { kModuleScope, kInitScope, kFuncScope, kExportScope };
35
36 struct ForeignVariable {
37 Handle<Name> name;
38 Variable* var;
39 LocalType type;
40 };
41
42 class AsmWasmBuilderImpl : public AstVisitor {
43 public:
44 AsmWasmBuilderImpl(Isolate* isolate, Zone* zone, FunctionLiteral* literal,
45 AsmTyper* typer)
46 : local_variables_(base::HashMap::PointersMatch,
47 ZoneHashMap::kDefaultHashMapCapacity,
48 ZoneAllocationPolicy(zone)),
49 functions_(base::HashMap::PointersMatch,
50 ZoneHashMap::kDefaultHashMapCapacity,
51 ZoneAllocationPolicy(zone)),
52 global_variables_(base::HashMap::PointersMatch,
53 ZoneHashMap::kDefaultHashMapCapacity,
54 ZoneAllocationPolicy(zone)),
55 scope_(kModuleScope),
56 builder_(new (zone) WasmModuleBuilder(zone)),
57 current_function_builder_(nullptr),
58 literal_(literal),
59 isolate_(isolate),
60 zone_(zone),
61 typer_(typer),
62 cache_(TypeCache::Get()),
63 breakable_blocks_(zone),
64 foreign_variables_(zone),
65 init_function_index_(0),
66 foreign_init_function_index_(0),
67 next_table_index_(0),
68 function_tables_(base::HashMap::PointersMatch,
69 ZoneHashMap::kDefaultHashMapCapacity,
70 ZoneAllocationPolicy(zone)),
71 imported_function_table_(this),
72 bounds_(typer->bounds()) {
73 InitializeAstVisitor(isolate);
74 }
75
76 void InitializeInitFunction() {
77 init_function_index_ = builder_->AddFunction();
78 FunctionSig::Builder b(zone(), 0, 0);
79 current_function_builder_ = builder_->FunctionAt(init_function_index_);
80 current_function_builder_->SetSignature(b.Build());
81 builder_->MarkStartFunction(init_function_index_);
82 current_function_builder_ = nullptr;
83 }
84
85 void BuildForeignInitFunction() {
86 foreign_init_function_index_ = builder_->AddFunction();
87 FunctionSig::Builder b(zone(), 0, foreign_variables_.size());
88 for (auto i = foreign_variables_.begin(); i != foreign_variables_.end();
89 ++i) {
90 b.AddParam(i->type);
91 }
92 current_function_builder_ =
93 builder_->FunctionAt(foreign_init_function_index_);
94 current_function_builder_->SetExported();
95 std::string raw_name = "__foreign_init__";
96 current_function_builder_->SetName(raw_name.data(),
97 static_cast<int>(raw_name.size()));
98 current_function_builder_->SetSignature(b.Build());
99 for (size_t pos = 0; pos < foreign_variables_.size(); ++pos) {
100 current_function_builder_->EmitGetLocal(static_cast<uint32_t>(pos));
101 ForeignVariable* fv = &foreign_variables_[pos];
102 uint32_t index = LookupOrInsertGlobal(fv->var, fv->type);
103 current_function_builder_->EmitWithVarInt(kExprStoreGlobal, index);
104 }
105 current_function_builder_ = nullptr;
106 }
107
108 i::Handle<i::FixedArray> GetForeignArgs() {
109 i::Handle<FixedArray> ret = isolate_->factory()->NewFixedArray(
110 static_cast<int>(foreign_variables_.size()));
111 for (size_t i = 0; i < foreign_variables_.size(); ++i) {
112 ForeignVariable* fv = &foreign_variables_[i];
113 ret->set(static_cast<int>(i), *fv->name);
114 }
115 return ret;
116 }
117
118 void Build() {
119 InitializeInitFunction();
120 RECURSE(VisitFunctionLiteral(literal_));
121 BuildForeignInitFunction();
122 }
123
124 void VisitVariableDeclaration(VariableDeclaration* decl) override {}
125
126 void VisitFunctionDeclaration(FunctionDeclaration* decl) override {
127 DCHECK_EQ(kModuleScope, scope_);
128 DCHECK_NULL(current_function_builder_);
129 uint32_t index = LookupOrInsertFunction(decl->proxy()->var());
130 current_function_builder_ = builder_->FunctionAt(index);
131 scope_ = kFuncScope;
132 RECURSE(Visit(decl->fun()));
133 scope_ = kModuleScope;
134 current_function_builder_ = nullptr;
135 local_variables_.Clear();
136 }
137
138 void VisitImportDeclaration(ImportDeclaration* decl) override {}
139
140 void VisitStatements(ZoneList<Statement*>* stmts) override {
141 for (int i = 0; i < stmts->length(); ++i) {
142 Statement* stmt = stmts->at(i);
143 ExpressionStatement* e = stmt->AsExpressionStatement();
144 if (e != nullptr && e->expression()->IsUndefinedLiteral()) {
145 continue;
146 }
147 RECURSE(Visit(stmt));
148 if (stmt->IsJump()) break;
149 }
150 }
151
152 void VisitBlock(Block* stmt) override {
153 if (stmt->statements()->length() == 1) {
154 ExpressionStatement* expr =
155 stmt->statements()->at(0)->AsExpressionStatement();
156 if (expr != nullptr) {
157 if (expr->expression()->IsAssignment()) {
158 RECURSE(VisitExpressionStatement(expr));
159 return;
160 }
161 }
162 }
163 if (scope_ == kFuncScope) {
164 BlockVisitor visitor(this, stmt->AsBreakableStatement(), kExprBlock,
165 false);
166 RECURSE(VisitStatements(stmt->statements()));
167 } else {
168 RECURSE(VisitStatements(stmt->statements()));
169 }
170 }
171
172 class BlockVisitor {
173 private:
174 AsmWasmBuilderImpl* builder_;
175
176 public:
177 BlockVisitor(AsmWasmBuilderImpl* builder, BreakableStatement* stmt,
178 WasmOpcode opcode, bool is_loop)
179 : builder_(builder) {
180 builder_->breakable_blocks_.push_back(std::make_pair(stmt, is_loop));
181 builder_->current_function_builder_->Emit(opcode);
182 }
183 ~BlockVisitor() {
184 builder_->current_function_builder_->Emit(kExprEnd);
185 builder_->breakable_blocks_.pop_back();
186 }
187 };
188
189 void VisitExpressionStatement(ExpressionStatement* stmt) override {
190 RECURSE(Visit(stmt->expression()));
191 }
192
193 void VisitEmptyStatement(EmptyStatement* stmt) override {}
194
195 void VisitEmptyParentheses(EmptyParentheses* paren) override {
196 UNREACHABLE();
197 }
198
199 void VisitIfStatement(IfStatement* stmt) override {
200 DCHECK_EQ(kFuncScope, scope_);
201 RECURSE(Visit(stmt->condition()));
202 current_function_builder_->Emit(kExprIf);
203 // WASM ifs come with implement blocks for both arms.
204 breakable_blocks_.push_back(std::make_pair(nullptr, false));
205 if (stmt->HasThenStatement()) {
206 RECURSE(Visit(stmt->then_statement()));
207 }
208 if (stmt->HasElseStatement()) {
209 current_function_builder_->Emit(kExprElse);
210 RECURSE(Visit(stmt->else_statement()));
211 }
212 current_function_builder_->Emit(kExprEnd);
213 breakable_blocks_.pop_back();
214 }
215
216 void VisitContinueStatement(ContinueStatement* stmt) override {
217 DCHECK_EQ(kFuncScope, scope_);
218 DCHECK_NOT_NULL(stmt->target());
219 int i = static_cast<int>(breakable_blocks_.size()) - 1;
220 int block_distance = 0;
221 for (; i >= 0; i--) {
222 auto elem = breakable_blocks_.at(i);
223 if (elem.first == stmt->target()) {
224 DCHECK(elem.second);
225 break;
226 } else if (elem.second) {
227 block_distance += 2;
228 } else {
229 block_distance += 1;
230 }
231 }
232 DCHECK(i >= 0);
233 current_function_builder_->EmitWithU8(kExprBr, ARITY_0);
234 current_function_builder_->EmitVarInt(block_distance);
235 }
236
237 void VisitBreakStatement(BreakStatement* stmt) override {
238 DCHECK_EQ(kFuncScope, scope_);
239 DCHECK_NOT_NULL(stmt->target());
240 int i = static_cast<int>(breakable_blocks_.size()) - 1;
241 int block_distance = 0;
242 for (; i >= 0; i--) {
243 auto elem = breakable_blocks_.at(i);
244 if (elem.first == stmt->target()) {
245 if (elem.second) {
246 block_distance++;
247 }
248 break;
249 } else if (elem.second) {
250 block_distance += 2;
251 } else {
252 block_distance += 1;
253 }
254 }
255 DCHECK(i >= 0);
256 current_function_builder_->EmitWithU8(kExprBr, ARITY_0);
257 current_function_builder_->EmitVarInt(block_distance);
258 }
259
260 void VisitReturnStatement(ReturnStatement* stmt) override {
261 if (scope_ == kModuleScope) {
262 scope_ = kExportScope;
263 RECURSE(Visit(stmt->expression()));
264 scope_ = kModuleScope;
265 } else if (scope_ == kFuncScope) {
266 RECURSE(Visit(stmt->expression()));
267 uint8_t arity =
268 TypeOf(stmt->expression()) == kAstStmt ? ARITY_0 : ARITY_1;
269 current_function_builder_->EmitWithU8(kExprReturn, arity);
270 } else {
271 UNREACHABLE();
272 }
273 }
274
275 void VisitWithStatement(WithStatement* stmt) override { UNREACHABLE(); }
276
277 void HandleCase(CaseNode* node,
278 const ZoneMap<int, unsigned int>& case_to_block,
279 VariableProxy* tag, int default_block, int if_depth) {
280 int prev_if_depth = if_depth;
281 if (node->left != nullptr) {
282 VisitVariableProxy(tag);
283 current_function_builder_->EmitI32Const(node->begin);
284 current_function_builder_->Emit(kExprI32LtS);
285 current_function_builder_->Emit(kExprIf);
286 if_depth++;
287 breakable_blocks_.push_back(std::make_pair(nullptr, false));
288 HandleCase(node->left, case_to_block, tag, default_block, if_depth);
289 current_function_builder_->Emit(kExprElse);
290 }
291 if (node->right != nullptr) {
292 VisitVariableProxy(tag);
293 current_function_builder_->EmitI32Const(node->end);
294 current_function_builder_->Emit(kExprI32GtS);
295 current_function_builder_->Emit(kExprIf);
296 if_depth++;
297 breakable_blocks_.push_back(std::make_pair(nullptr, false));
298 HandleCase(node->right, case_to_block, tag, default_block, if_depth);
299 current_function_builder_->Emit(kExprElse);
300 }
301 if (node->begin == node->end) {
302 VisitVariableProxy(tag);
303 current_function_builder_->EmitI32Const(node->begin);
304 current_function_builder_->Emit(kExprI32Eq);
305 current_function_builder_->Emit(kExprIf);
306 DCHECK(case_to_block.find(node->begin) != case_to_block.end());
307 current_function_builder_->EmitWithU8(kExprBr, ARITY_0);
308 current_function_builder_->EmitVarInt(1 + if_depth +
309 case_to_block.at(node->begin));
310 current_function_builder_->Emit(kExprEnd);
311 } else {
312 if (node->begin != 0) {
313 VisitVariableProxy(tag);
314 current_function_builder_->EmitI32Const(node->begin);
315 current_function_builder_->Emit(kExprI32Sub);
316 } else {
317 VisitVariableProxy(tag);
318 }
319 current_function_builder_->EmitWithU8(kExprBrTable, ARITY_0);
320 current_function_builder_->EmitVarInt(node->end - node->begin + 1);
321 for (int v = node->begin; v <= node->end; v++) {
322 if (case_to_block.find(v) != case_to_block.end()) {
323 byte break_code[] = {BR_TARGET(if_depth + case_to_block.at(v))};
324 current_function_builder_->EmitCode(break_code, sizeof(break_code));
325 } else {
326 byte break_code[] = {BR_TARGET(if_depth + default_block)};
327 current_function_builder_->EmitCode(break_code, sizeof(break_code));
328 }
329 if (v == kMaxInt) {
330 break;
331 }
332 }
333 byte break_code[] = {BR_TARGET(if_depth + default_block)};
334 current_function_builder_->EmitCode(break_code, sizeof(break_code));
335 }
336
337 while (if_depth-- != prev_if_depth) {
338 breakable_blocks_.pop_back();
339 current_function_builder_->Emit(kExprEnd);
340 }
341 }
342
343 void VisitSwitchStatement(SwitchStatement* stmt) override {
344 VariableProxy* tag = stmt->tag()->AsVariableProxy();
345 DCHECK_NOT_NULL(tag);
346 ZoneList<CaseClause*>* clauses = stmt->cases();
347 int case_count = clauses->length();
348 if (case_count == 0) {
349 return;
350 }
351 BlockVisitor visitor(this, stmt->AsBreakableStatement(), kExprBlock, false);
352 ZoneVector<BlockVisitor*> blocks(zone_);
353 ZoneVector<int32_t> cases(zone_);
354 ZoneMap<int, unsigned int> case_to_block(zone_);
355 bool has_default = false;
356 for (int i = case_count - 1; i >= 0; i--) {
357 CaseClause* clause = clauses->at(i);
358 blocks.push_back(new BlockVisitor(this, nullptr, kExprBlock, false));
359 if (!clause->is_default()) {
360 Literal* label = clause->label()->AsLiteral();
361 Handle<Object> value = label->value();
362 DCHECK(value->IsNumber() &&
363 bounds_->get(label).upper->Is(cache_.kAsmSigned));
364 int32_t label_value;
365 if (!value->ToInt32(&label_value)) {
366 UNREACHABLE();
367 }
368 case_to_block[label_value] = i;
369 cases.push_back(label_value);
370 } else {
371 DCHECK_EQ(i, case_count - 1);
372 has_default = true;
373 }
374 }
375 if (!has_default || case_count > 1) {
376 int default_block = has_default ? case_count - 1 : case_count;
377 BlockVisitor switch_logic_block(this, nullptr, kExprBlock, false);
378 CaseNode* root = OrderCases(&cases, zone_);
379 HandleCase(root, case_to_block, tag, default_block, 0);
380 if (root->left != nullptr || root->right != nullptr ||
381 root->begin == root->end) {
382 current_function_builder_->EmitWithU8(kExprBr, ARITY_0);
383 current_function_builder_->EmitVarInt(default_block);
384 }
385 }
386 for (int i = 0; i < case_count; ++i) {
387 CaseClause* clause = clauses->at(i);
388 RECURSE(VisitStatements(clause->statements()));
389 BlockVisitor* v = blocks.at(case_count - i - 1);
390 blocks.pop_back();
391 delete v;
392 }
393 }
394
395 void VisitCaseClause(CaseClause* clause) override { UNREACHABLE(); }
396
397 void VisitDoWhileStatement(DoWhileStatement* stmt) override {
398 DCHECK_EQ(kFuncScope, scope_);
399 BlockVisitor visitor(this, stmt->AsBreakableStatement(), kExprLoop, true);
400 RECURSE(Visit(stmt->body()));
401 RECURSE(Visit(stmt->cond()));
402 current_function_builder_->Emit(kExprIf);
403 current_function_builder_->EmitWithU8U8(kExprBr, ARITY_0, 1);
404 current_function_builder_->Emit(kExprEnd);
405 }
406
407 void VisitWhileStatement(WhileStatement* stmt) override {
408 DCHECK_EQ(kFuncScope, scope_);
409 BlockVisitor visitor(this, stmt->AsBreakableStatement(), kExprLoop, true);
410 RECURSE(Visit(stmt->cond()));
411 breakable_blocks_.push_back(std::make_pair(nullptr, false));
412 current_function_builder_->Emit(kExprIf);
413 RECURSE(Visit(stmt->body()));
414 current_function_builder_->EmitWithU8U8(kExprBr, ARITY_0, 1);
415 current_function_builder_->Emit(kExprEnd);
416 breakable_blocks_.pop_back();
417 }
418
419 void VisitForStatement(ForStatement* stmt) override {
420 DCHECK_EQ(kFuncScope, scope_);
421 if (stmt->init() != nullptr) {
422 RECURSE(Visit(stmt->init()));
423 }
424 BlockVisitor visitor(this, stmt->AsBreakableStatement(), kExprLoop, true);
425 if (stmt->cond() != nullptr) {
426 RECURSE(Visit(stmt->cond()));
427 current_function_builder_->Emit(kExprI32Eqz);
428 current_function_builder_->Emit(kExprIf);
429 current_function_builder_->Emit(kExprNop);
430 current_function_builder_->EmitWithU8U8(kExprBr, ARITY_0, 2);
431 current_function_builder_->Emit(kExprEnd);
432 }
433 if (stmt->body() != nullptr) {
434 RECURSE(Visit(stmt->body()));
435 }
436 if (stmt->next() != nullptr) {
437 RECURSE(Visit(stmt->next()));
438 }
439 current_function_builder_->Emit(kExprNop);
440 current_function_builder_->EmitWithU8U8(kExprBr, ARITY_0, 0);
441 }
442
443 void VisitForInStatement(ForInStatement* stmt) override { UNREACHABLE(); }
444
445 void VisitForOfStatement(ForOfStatement* stmt) override { UNREACHABLE(); }
446
447 void VisitTryCatchStatement(TryCatchStatement* stmt) override {
448 UNREACHABLE();
449 }
450
451 void VisitTryFinallyStatement(TryFinallyStatement* stmt) override {
452 UNREACHABLE();
453 }
454
455 void VisitDebuggerStatement(DebuggerStatement* stmt) override {
456 UNREACHABLE();
457 }
458
459 void VisitFunctionLiteral(FunctionLiteral* expr) override {
460 Scope* scope = expr->scope();
461 if (scope_ == kFuncScope) {
462 if (bounds_->get(expr).lower->IsFunction()) {
463 // Build the signature for the function.
464 FunctionType* func_type = bounds_->get(expr).lower->AsFunction();
465 LocalType return_type = TypeFrom(func_type->Result());
466 FunctionSig::Builder b(zone(), return_type == kAstStmt ? 0 : 1,
467 func_type->Arity());
468 if (return_type != kAstStmt) b.AddReturn(return_type);
469 for (int i = 0; i < expr->parameter_count(); ++i) {
470 LocalType type = TypeFrom(func_type->Parameter(i));
471 DCHECK_NE(kAstStmt, type);
472 b.AddParam(type);
473 InsertParameter(scope->parameter(i), type, i);
474 }
475 current_function_builder_->SetSignature(b.Build());
476 } else {
477 UNREACHABLE();
478 }
479 }
480 RECURSE(VisitStatements(expr->body()));
481 RECURSE(VisitDeclarations(scope->declarations()));
482 }
483
484 void VisitNativeFunctionLiteral(NativeFunctionLiteral* expr) override {
485 UNREACHABLE();
486 }
487
488 void VisitConditional(Conditional* expr) override {
489 DCHECK_EQ(kFuncScope, scope_);
490 RECURSE(Visit(expr->condition()));
491 // WASM ifs come with implicit blocks for both arms.
492 breakable_blocks_.push_back(std::make_pair(nullptr, false));
493 current_function_builder_->Emit(kExprIf);
494 RECURSE(Visit(expr->then_expression()));
495 current_function_builder_->Emit(kExprElse);
496 RECURSE(Visit(expr->else_expression()));
497 current_function_builder_->Emit(kExprEnd);
498 breakable_blocks_.pop_back();
499 }
500
501 bool VisitStdlibConstant(Variable* var) {
502 AsmTyper::StandardMember standard_object =
503 typer_->VariableAsStandardMember(var);
504 double value;
505 switch (standard_object) {
506 case AsmTyper::kInfinity: {
507 value = std::numeric_limits<double>::infinity();
508 break;
509 }
510 case AsmTyper::kNaN: {
511 value = std::numeric_limits<double>::quiet_NaN();
512 break;
513 }
514 case AsmTyper::kMathE: {
515 value = M_E;
516 break;
517 }
518 case AsmTyper::kMathLN10: {
519 value = M_LN10;
520 break;
521 }
522 case AsmTyper::kMathLN2: {
523 value = M_LN2;
524 break;
525 }
526 case AsmTyper::kMathLOG10E: {
527 value = M_LOG10E;
528 break;
529 }
530 case AsmTyper::kMathLOG2E: {
531 value = M_LOG2E;
532 break;
533 }
534 case AsmTyper::kMathPI: {
535 value = M_PI;
536 break;
537 }
538 case AsmTyper::kMathSQRT1_2: {
539 value = M_SQRT1_2;
540 break;
541 }
542 case AsmTyper::kMathSQRT2: {
543 value = M_SQRT2;
544 break;
545 }
546 default: { return false; }
547 }
548 byte code[] = {WASM_F64(value)};
549 current_function_builder_->EmitCode(code, sizeof(code));
550 return true;
551 }
552
553 void VisitVariableProxy(VariableProxy* expr) override {
554 if (scope_ == kFuncScope || scope_ == kInitScope) {
555 Variable* var = expr->var();
556 if (VisitStdlibConstant(var)) {
557 return;
558 }
559 LocalType var_type = TypeOf(expr);
560 DCHECK_NE(kAstStmt, var_type);
561 if (var->IsContextSlot()) {
562 current_function_builder_->EmitWithVarInt(
563 kExprLoadGlobal, LookupOrInsertGlobal(var, var_type));
564 } else {
565 current_function_builder_->EmitGetLocal(
566 LookupOrInsertLocal(var, var_type));
567 }
568 }
569 }
570
571 void VisitLiteral(Literal* expr) override {
572 Handle<Object> value = expr->value();
573 if (!value->IsNumber() || (scope_ != kFuncScope && scope_ != kInitScope)) {
574 return;
575 }
576 Type* type = bounds_->get(expr).upper;
577 if (type->Is(cache_.kAsmSigned)) {
578 int32_t i = 0;
579 if (!value->ToInt32(&i)) {
580 UNREACHABLE();
581 }
582 byte code[] = {WASM_I32V(i)};
583 current_function_builder_->EmitCode(code, sizeof(code));
584 } else if (type->Is(cache_.kAsmUnsigned) || type->Is(cache_.kAsmFixnum)) {
585 uint32_t u = 0;
586 if (!value->ToUint32(&u)) {
587 UNREACHABLE();
588 }
589 int32_t i = static_cast<int32_t>(u);
590 byte code[] = {WASM_I32V(i)};
591 current_function_builder_->EmitCode(code, sizeof(code));
592 } else if (type->Is(cache_.kAsmDouble)) {
593 double val = expr->raw_value()->AsNumber();
594 byte code[] = {WASM_F64(val)};
595 current_function_builder_->EmitCode(code, sizeof(code));
596 } else {
597 UNREACHABLE();
598 }
599 }
600
601 void VisitRegExpLiteral(RegExpLiteral* expr) override { UNREACHABLE(); }
602
603 void VisitObjectLiteral(ObjectLiteral* expr) override {
604 ZoneList<ObjectLiteralProperty*>* props = expr->properties();
605 for (int i = 0; i < props->length(); ++i) {
606 ObjectLiteralProperty* prop = props->at(i);
607 DCHECK_EQ(kExportScope, scope_);
608 VariableProxy* expr = prop->value()->AsVariableProxy();
609 DCHECK_NOT_NULL(expr);
610 Variable* var = expr->var();
611 Literal* name = prop->key()->AsLiteral();
612 DCHECK_NOT_NULL(name);
613 DCHECK(name->IsPropertyName());
614 const AstRawString* raw_name = name->AsRawPropertyName();
615 if (var->is_function()) {
616 uint32_t index = LookupOrInsertFunction(var);
617 builder_->FunctionAt(index)->SetExported();
618 builder_->FunctionAt(index)->SetName(
619 reinterpret_cast<const char*>(raw_name->raw_data()),
620 raw_name->length());
621 }
622 }
623 }
624
625 void VisitArrayLiteral(ArrayLiteral* expr) override { UNREACHABLE(); }
626
627 void LoadInitFunction() {
628 current_function_builder_ = builder_->FunctionAt(init_function_index_);
629 scope_ = kInitScope;
630 }
631
632 void UnLoadInitFunction() {
633 scope_ = kModuleScope;
634 current_function_builder_ = nullptr;
635 }
636
637 void AddFunctionTable(VariableProxy* table, ArrayLiteral* funcs) {
638 FunctionType* func_type =
639 bounds_->get(funcs).lower->AsArray()->Element()->AsFunction();
640 LocalType return_type = TypeFrom(func_type->Result());
641 FunctionSig::Builder sig(zone(), return_type == kAstStmt ? 0 : 1,
642 func_type->Arity());
643 if (return_type != kAstStmt) {
644 sig.AddReturn(static_cast<LocalType>(return_type));
645 }
646 for (int i = 0; i < func_type->Arity(); ++i) {
647 sig.AddParam(TypeFrom(func_type->Parameter(i)));
648 }
649 uint32_t signature_index = builder_->AddSignature(sig.Build());
650 InsertFunctionTable(table->var(), next_table_index_, signature_index);
651 next_table_index_ += funcs->values()->length();
652 for (int i = 0; i < funcs->values()->length(); ++i) {
653 VariableProxy* func = funcs->values()->at(i)->AsVariableProxy();
654 DCHECK_NOT_NULL(func);
655 builder_->AddIndirectFunction(LookupOrInsertFunction(func->var()));
656 }
657 }
658
659 struct FunctionTableIndices : public ZoneObject {
660 uint32_t start_index;
661 uint32_t signature_index;
662 };
663
664 void InsertFunctionTable(Variable* v, uint32_t start_index,
665 uint32_t signature_index) {
666 FunctionTableIndices* container = new (zone()) FunctionTableIndices();
667 container->start_index = start_index;
668 container->signature_index = signature_index;
669 ZoneHashMap::Entry* entry = function_tables_.LookupOrInsert(
670 v, ComputePointerHash(v), ZoneAllocationPolicy(zone()));
671 entry->value = container;
672 }
673
674 FunctionTableIndices* LookupFunctionTable(Variable* v) {
675 ZoneHashMap::Entry* entry =
676 function_tables_.Lookup(v, ComputePointerHash(v));
677 DCHECK_NOT_NULL(entry);
678 return reinterpret_cast<FunctionTableIndices*>(entry->value);
679 }
680
681 class ImportedFunctionTable {
682 private:
683 class ImportedFunctionIndices : public ZoneObject {
684 public:
685 const char* name_;
686 int name_length_;
687 WasmModuleBuilder::SignatureMap signature_to_index_;
688
689 ImportedFunctionIndices(const char* name, int name_length, Zone* zone)
690 : name_(name), name_length_(name_length), signature_to_index_(zone) {}
691 };
692 ZoneHashMap table_;
693 AsmWasmBuilderImpl* builder_;
694
695 public:
696 explicit ImportedFunctionTable(AsmWasmBuilderImpl* builder)
697 : table_(base::HashMap::PointersMatch,
698 ZoneHashMap::kDefaultHashMapCapacity,
699 ZoneAllocationPolicy(builder->zone())),
700 builder_(builder) {}
701
702 void AddImport(Variable* v, const char* name, int name_length) {
703 ImportedFunctionIndices* indices = new (builder_->zone())
704 ImportedFunctionIndices(name, name_length, builder_->zone());
705 ZoneHashMap::Entry* entry = table_.LookupOrInsert(
706 v, ComputePointerHash(v), ZoneAllocationPolicy(builder_->zone()));
707 entry->value = indices;
708 }
709
710 uint32_t GetFunctionIndex(Variable* v, FunctionSig* sig) {
711 ZoneHashMap::Entry* entry = table_.Lookup(v, ComputePointerHash(v));
712 DCHECK_NOT_NULL(entry);
713 ImportedFunctionIndices* indices =
714 reinterpret_cast<ImportedFunctionIndices*>(entry->value);
715 WasmModuleBuilder::SignatureMap::iterator pos =
716 indices->signature_to_index_.find(sig);
717 if (pos != indices->signature_to_index_.end()) {
718 return pos->second;
719 } else {
720 uint32_t index = builder_->builder_->AddImport(
721 indices->name_, indices->name_length_, sig);
722 indices->signature_to_index_[sig] = index;
723 return index;
724 }
725 }
726 };
727
728 void EmitAssignmentLhs(Expression* target, MachineType* mtype) {
729 // Match the left hand side of the assignment.
730 VariableProxy* target_var = target->AsVariableProxy();
731 if (target_var != nullptr) {
732 // Left hand side is a local or a global variable, no code on LHS.
733 return;
734 }
735
736 Property* target_prop = target->AsProperty();
737 if (target_prop != nullptr) {
738 // Left hand side is a property access, i.e. the asm.js heap.
739 VisitPropertyAndEmitIndex(target_prop, mtype);
740 return;
741 }
742
743 if (target_var == nullptr && target_prop == nullptr) {
744 UNREACHABLE(); // invalid assignment.
745 }
746 }
747
748 void EmitAssignmentRhs(Expression* target, Expression* value, bool* is_nop) {
749 BinaryOperation* binop = value->AsBinaryOperation();
750 if (binop != nullptr) {
751 if (scope_ == kInitScope) {
752 // Handle foreign variables in the initialization scope.
753 Property* prop = binop->left()->AsProperty();
754 if (binop->op() == Token::MUL) {
755 DCHECK(binop->right()->IsLiteral());
756 DCHECK_EQ(1.0, binop->right()->AsLiteral()->raw_value()->AsNumber());
757 DCHECK(binop->right()->AsLiteral()->raw_value()->ContainsDot());
758 DCHECK(target->IsVariableProxy());
759 VisitForeignVariable(true, target->AsVariableProxy()->var(), prop);
760 *is_nop = true;
761 return;
762 } else if (binop->op() == Token::BIT_OR) {
763 DCHECK(binop->right()->IsLiteral());
764 DCHECK_EQ(0.0, binop->right()->AsLiteral()->raw_value()->AsNumber());
765 DCHECK(!binop->right()->AsLiteral()->raw_value()->ContainsDot());
766 DCHECK(target->IsVariableProxy());
767 VisitForeignVariable(false, target->AsVariableProxy()->var(), prop);
768 *is_nop = true;
769 return;
770 } else {
771 UNREACHABLE();
772 }
773 }
774 if (MatchBinaryOperation(binop) == kAsIs) {
775 VariableProxy* target_var = target->AsVariableProxy();
776 VariableProxy* effective_value_var = GetLeft(binop)->AsVariableProxy();
777 if (target_var != nullptr && effective_value_var != nullptr &&
778 target_var->var() == effective_value_var->var()) {
779 *is_nop = true;
780 return;
781 }
782 }
783 }
784 RECURSE(Visit(value));
785 }
786
787 void EmitAssignment(Assignment* expr, MachineType type) {
788 // Match the left hand side of the assignment.
789 VariableProxy* target_var = expr->target()->AsVariableProxy();
790 if (target_var != nullptr) {
791 // Left hand side is a local or a global variable.
792 Variable* var = target_var->var();
793 LocalType var_type = TypeOf(expr);
794 DCHECK_NE(kAstStmt, var_type);
795 if (var->IsContextSlot()) {
796 current_function_builder_->EmitWithVarInt(
797 kExprStoreGlobal, LookupOrInsertGlobal(var, var_type));
798 } else {
799 current_function_builder_->EmitSetLocal(
800 LookupOrInsertLocal(var, var_type));
801 }
802 }
803
804 Property* target_prop = expr->target()->AsProperty();
805 if (target_prop != nullptr) {
806 // Left hand side is a property access, i.e. the asm.js heap.
807 if (TypeOf(expr->value()) == kAstF64 && expr->target()->IsProperty() &&
808 bounds_->get(expr->target()->AsProperty()->obj())
809 .lower->Is(cache_.kFloat32Array)) {
810 current_function_builder_->Emit(kExprF32ConvertF64);
811 }
812 WasmOpcode opcode;
813 if (type == MachineType::Int8()) {
814 opcode = kExprI32AsmjsStoreMem8;
815 } else if (type == MachineType::Uint8()) {
816 opcode = kExprI32AsmjsStoreMem8;
817 } else if (type == MachineType::Int16()) {
818 opcode = kExprI32AsmjsStoreMem16;
819 } else if (type == MachineType::Uint16()) {
820 opcode = kExprI32AsmjsStoreMem16;
821 } else if (type == MachineType::Int32()) {
822 opcode = kExprI32AsmjsStoreMem;
823 } else if (type == MachineType::Uint32()) {
824 opcode = kExprI32AsmjsStoreMem;
825 } else if (type == MachineType::Float32()) {
826 opcode = kExprF32AsmjsStoreMem;
827 } else if (type == MachineType::Float64()) {
828 opcode = kExprF64AsmjsStoreMem;
829 } else {
830 UNREACHABLE();
831 }
832 current_function_builder_->Emit(opcode);
833 }
834
835 if (target_var == nullptr && target_prop == nullptr) {
836 UNREACHABLE(); // invalid assignment.
837 }
838 }
839
840 void VisitAssignment(Assignment* expr) override {
841 bool as_init = false;
842 if (scope_ == kModuleScope) {
843 Property* prop = expr->value()->AsProperty();
844 if (prop != nullptr) {
845 VariableProxy* vp = prop->obj()->AsVariableProxy();
846 if (vp != nullptr && vp->var()->IsParameter() &&
847 vp->var()->index() == 1) {
848 VariableProxy* target = expr->target()->AsVariableProxy();
849 if (bounds_->get(target).lower->Is(Type::Function())) {
850 const AstRawString* name =
851 prop->key()->AsLiteral()->AsRawPropertyName();
852 imported_function_table_.AddImport(
853 target->var(), reinterpret_cast<const char*>(name->raw_data()),
854 name->length());
855 }
856 }
857 // Property values in module scope don't emit code, so return.
858 return;
859 }
860 ArrayLiteral* funcs = expr->value()->AsArrayLiteral();
861 if (funcs != nullptr &&
862 bounds_->get(funcs).lower->AsArray()->Element()->IsFunction()) {
863 VariableProxy* target = expr->target()->AsVariableProxy();
864 DCHECK_NOT_NULL(target);
865 AddFunctionTable(target, funcs);
866 // Only add to the function table. No init needed.
867 return;
868 }
869 if (expr->value()->IsCallNew()) {
870 // No init code to emit for CallNew nodes.
871 return;
872 }
873 as_init = true;
874 }
875
876 if (as_init) LoadInitFunction();
877 MachineType mtype;
878 bool is_nop = false;
879 EmitAssignmentLhs(expr->target(), &mtype);
880 EmitAssignmentRhs(expr->target(), expr->value(), &is_nop);
881 if (!is_nop) {
882 EmitAssignment(expr, mtype);
883 }
884 if (as_init) UnLoadInitFunction();
885 }
886
887 void VisitYield(Yield* expr) override { UNREACHABLE(); }
888
889 void VisitThrow(Throw* expr) override { UNREACHABLE(); }
890
891 void VisitForeignVariable(bool is_float, Variable* var, Property* expr) {
892 DCHECK(expr->obj()->AsVariableProxy());
893 DCHECK(VariableLocation::PARAMETER ==
894 expr->obj()->AsVariableProxy()->var()->location());
895 DCHECK_EQ(1, expr->obj()->AsVariableProxy()->var()->index());
896 Literal* key_literal = expr->key()->AsLiteral();
897 DCHECK_NOT_NULL(key_literal);
898 if (!key_literal->value().is_null()) {
899 Handle<Name> name =
900 i::Object::ToName(isolate_, key_literal->value()).ToHandleChecked();
901 LocalType type = is_float ? kAstF64 : kAstI32;
902 foreign_variables_.push_back({name, var, type});
903 }
904 }
905
906 void VisitPropertyAndEmitIndex(Property* expr, MachineType* mtype) {
907 Expression* obj = expr->obj();
908 DCHECK_EQ(bounds_->get(obj).lower, bounds_->get(obj).upper);
909 Type* type = bounds_->get(obj).lower;
910 int size;
911 if (type->Is(cache_.kUint8Array)) {
912 *mtype = MachineType::Uint8();
913 size = 1;
914 } else if (type->Is(cache_.kInt8Array)) {
915 *mtype = MachineType::Int8();
916 size = 1;
917 } else if (type->Is(cache_.kUint16Array)) {
918 *mtype = MachineType::Uint16();
919 size = 2;
920 } else if (type->Is(cache_.kInt16Array)) {
921 *mtype = MachineType::Int16();
922 size = 2;
923 } else if (type->Is(cache_.kUint32Array)) {
924 *mtype = MachineType::Uint32();
925 size = 4;
926 } else if (type->Is(cache_.kInt32Array)) {
927 *mtype = MachineType::Int32();
928 size = 4;
929 } else if (type->Is(cache_.kUint32Array)) {
930 *mtype = MachineType::Uint32();
931 size = 4;
932 } else if (type->Is(cache_.kFloat32Array)) {
933 *mtype = MachineType::Float32();
934 size = 4;
935 } else if (type->Is(cache_.kFloat64Array)) {
936 *mtype = MachineType::Float64();
937 size = 8;
938 } else {
939 UNREACHABLE();
940 }
941 if (size == 1) {
942 // Allow more general expression in byte arrays than the spec
943 // strictly permits.
944 // Early versions of Emscripten emit HEAP8[HEAP32[..]|0] in
945 // places that strictly should be HEAP8[HEAP32[..]>>0].
946 RECURSE(Visit(expr->key()));
947 return;
948 }
949
950 Literal* value = expr->key()->AsLiteral();
951 if (value) {
952 DCHECK(value->raw_value()->IsNumber());
953 DCHECK_EQ(kAstI32, TypeOf(value));
954 int32_t val = static_cast<int32_t>(value->raw_value()->AsNumber());
955 // TODO(titzer): handle overflow here.
956 current_function_builder_->EmitI32Const(val * size);
957 return;
958 }
959 BinaryOperation* binop = expr->key()->AsBinaryOperation();
960 if (binop) {
961 DCHECK_EQ(Token::SAR, binop->op());
962 DCHECK(binop->right()->AsLiteral()->raw_value()->IsNumber());
963 DCHECK(kAstI32 == TypeOf(binop->right()->AsLiteral()));
964 DCHECK_EQ(size,
965 1 << static_cast<int>(
966 binop->right()->AsLiteral()->raw_value()->AsNumber()));
967 // Mask bottom bits to match asm.js behavior.
968 byte mask = static_cast<byte>(~(size - 1));
969 RECURSE(Visit(binop->left()));
970 current_function_builder_->EmitWithU8(kExprI8Const, mask);
971 current_function_builder_->Emit(kExprI32And);
972 return;
973 }
974 UNREACHABLE();
975 }
976
977 void VisitProperty(Property* expr) override {
978 MachineType type;
979 VisitPropertyAndEmitIndex(expr, &type);
980 WasmOpcode opcode;
981 if (type == MachineType::Int8()) {
982 opcode = kExprI32AsmjsLoadMem8S;
983 } else if (type == MachineType::Uint8()) {
984 opcode = kExprI32AsmjsLoadMem8U;
985 } else if (type == MachineType::Int16()) {
986 opcode = kExprI32AsmjsLoadMem16S;
987 } else if (type == MachineType::Uint16()) {
988 opcode = kExprI32AsmjsLoadMem16U;
989 } else if (type == MachineType::Int32()) {
990 opcode = kExprI32AsmjsLoadMem;
991 } else if (type == MachineType::Uint32()) {
992 opcode = kExprI32AsmjsLoadMem;
993 } else if (type == MachineType::Float32()) {
994 opcode = kExprF32AsmjsLoadMem;
995 } else if (type == MachineType::Float64()) {
996 opcode = kExprF64AsmjsLoadMem;
997 } else {
998 UNREACHABLE();
999 }
1000
1001 current_function_builder_->Emit(opcode);
1002 }
1003
1004 bool VisitStdlibFunction(Call* call, VariableProxy* expr) {
1005 Variable* var = expr->var();
1006 AsmTyper::StandardMember standard_object =
1007 typer_->VariableAsStandardMember(var);
1008 ZoneList<Expression*>* args = call->arguments();
1009 LocalType call_type = TypeOf(call);
1010
1011 switch (standard_object) {
1012 case AsmTyper::kNone: {
1013 return false;
1014 }
1015 case AsmTyper::kMathAcos: {
1016 VisitCallArgs(call);
1017 DCHECK_EQ(kAstF64, call_type);
1018 current_function_builder_->Emit(kExprF64Acos);
1019 break;
1020 }
1021 case AsmTyper::kMathAsin: {
1022 VisitCallArgs(call);
1023 DCHECK_EQ(kAstF64, call_type);
1024 current_function_builder_->Emit(kExprF64Asin);
1025 break;
1026 }
1027 case AsmTyper::kMathAtan: {
1028 VisitCallArgs(call);
1029 DCHECK_EQ(kAstF64, call_type);
1030 current_function_builder_->Emit(kExprF64Atan);
1031 break;
1032 }
1033 case AsmTyper::kMathCos: {
1034 VisitCallArgs(call);
1035 DCHECK_EQ(kAstF64, call_type);
1036 current_function_builder_->Emit(kExprF64Cos);
1037 break;
1038 }
1039 case AsmTyper::kMathSin: {
1040 VisitCallArgs(call);
1041 DCHECK_EQ(kAstF64, call_type);
1042 current_function_builder_->Emit(kExprF64Sin);
1043 break;
1044 }
1045 case AsmTyper::kMathTan: {
1046 VisitCallArgs(call);
1047 DCHECK_EQ(kAstF64, call_type);
1048 current_function_builder_->Emit(kExprF64Tan);
1049 break;
1050 }
1051 case AsmTyper::kMathExp: {
1052 VisitCallArgs(call);
1053 DCHECK_EQ(kAstF64, call_type);
1054 current_function_builder_->Emit(kExprF64Exp);
1055 break;
1056 }
1057 case AsmTyper::kMathLog: {
1058 VisitCallArgs(call);
1059 DCHECK_EQ(kAstF64, call_type);
1060 current_function_builder_->Emit(kExprF64Log);
1061 break;
1062 }
1063 case AsmTyper::kMathCeil: {
1064 VisitCallArgs(call);
1065 if (call_type == kAstF32) {
1066 current_function_builder_->Emit(kExprF32Ceil);
1067 } else if (call_type == kAstF64) {
1068 current_function_builder_->Emit(kExprF64Ceil);
1069 } else {
1070 UNREACHABLE();
1071 }
1072 break;
1073 }
1074 case AsmTyper::kMathFloor: {
1075 VisitCallArgs(call);
1076 if (call_type == kAstF32) {
1077 current_function_builder_->Emit(kExprF32Floor);
1078 } else if (call_type == kAstF64) {
1079 current_function_builder_->Emit(kExprF64Floor);
1080 } else {
1081 UNREACHABLE();
1082 }
1083 break;
1084 }
1085 case AsmTyper::kMathSqrt: {
1086 VisitCallArgs(call);
1087 if (call_type == kAstF32) {
1088 current_function_builder_->Emit(kExprF32Sqrt);
1089 } else if (call_type == kAstF64) {
1090 current_function_builder_->Emit(kExprF64Sqrt);
1091 } else {
1092 UNREACHABLE();
1093 }
1094 break;
1095 }
1096 case AsmTyper::kMathAbs: {
1097 if (call_type == kAstI32) {
1098 uint32_t tmp = current_function_builder_->AddLocal(kAstI32);
1099
1100 // if set_local(tmp, x) < 0
1101 Visit(call->arguments()->at(0));
1102 current_function_builder_->EmitSetLocal(tmp);
1103 byte code[] = {WASM_I8(0)};
1104 current_function_builder_->EmitCode(code, sizeof(code));
1105 current_function_builder_->Emit(kExprI32LtS);
1106 current_function_builder_->Emit(kExprIf);
1107
1108 // then (0 - tmp)
1109 current_function_builder_->EmitCode(code, sizeof(code));
1110 current_function_builder_->EmitGetLocal(tmp);
1111 current_function_builder_->Emit(kExprI32Sub);
1112
1113 // else tmp
1114 current_function_builder_->Emit(kExprElse);
1115 current_function_builder_->EmitGetLocal(tmp);
1116 // end
1117 current_function_builder_->Emit(kExprEnd);
1118
1119 } else if (call_type == kAstF32) {
1120 VisitCallArgs(call);
1121 current_function_builder_->Emit(kExprF32Abs);
1122 } else if (call_type == kAstF64) {
1123 VisitCallArgs(call);
1124 current_function_builder_->Emit(kExprF64Abs);
1125 } else {
1126 UNREACHABLE();
1127 }
1128 break;
1129 }
1130 case AsmTyper::kMathMin: {
1131 // TODO(bradnelson): Change wasm to match Math.min in asm.js mode.
1132 if (call_type == kAstI32) {
1133 uint32_t tmp_x = current_function_builder_->AddLocal(kAstI32);
1134 uint32_t tmp_y = current_function_builder_->AddLocal(kAstI32);
1135
1136 // if set_local(tmp_x, x) < set_local(tmp_y, y)
1137 Visit(call->arguments()->at(0));
1138 current_function_builder_->EmitSetLocal(tmp_x);
1139
1140 Visit(call->arguments()->at(1));
1141 current_function_builder_->EmitSetLocal(tmp_y);
1142
1143 current_function_builder_->Emit(kExprI32LeS);
1144 current_function_builder_->Emit(kExprIf);
1145
1146 // then tmp_x
1147 current_function_builder_->EmitGetLocal(tmp_x);
1148
1149 // else tmp_y
1150 current_function_builder_->Emit(kExprElse);
1151 current_function_builder_->EmitGetLocal(tmp_y);
1152 current_function_builder_->Emit(kExprEnd);
1153
1154 } else if (call_type == kAstF32) {
1155 VisitCallArgs(call);
1156 current_function_builder_->Emit(kExprF32Min);
1157 } else if (call_type == kAstF64) {
1158 VisitCallArgs(call);
1159 current_function_builder_->Emit(kExprF64Min);
1160 } else {
1161 UNREACHABLE();
1162 }
1163 break;
1164 }
1165 case AsmTyper::kMathMax: {
1166 // TODO(bradnelson): Change wasm to match Math.max in asm.js mode.
1167 if (call_type == kAstI32) {
1168 uint32_t tmp_x = current_function_builder_->AddLocal(kAstI32);
1169 uint32_t tmp_y = current_function_builder_->AddLocal(kAstI32);
1170
1171 // if set_local(tmp_x, x) < set_local(tmp_y, y)
1172 Visit(call->arguments()->at(0));
1173
1174 current_function_builder_->EmitSetLocal(tmp_x);
1175
1176 Visit(call->arguments()->at(1));
1177 current_function_builder_->EmitSetLocal(tmp_y);
1178
1179 current_function_builder_->Emit(kExprI32LeS);
1180 current_function_builder_->Emit(kExprIf);
1181
1182 // then tmp_y
1183 current_function_builder_->EmitGetLocal(tmp_y);
1184
1185 // else tmp_x
1186 current_function_builder_->Emit(kExprElse);
1187 current_function_builder_->EmitGetLocal(tmp_x);
1188 current_function_builder_->Emit(kExprEnd);
1189
1190 } else if (call_type == kAstF32) {
1191 VisitCallArgs(call);
1192 current_function_builder_->Emit(kExprF32Max);
1193 } else if (call_type == kAstF64) {
1194 VisitCallArgs(call);
1195 current_function_builder_->Emit(kExprF64Max);
1196 } else {
1197 UNREACHABLE();
1198 }
1199 break;
1200 }
1201 case AsmTyper::kMathAtan2: {
1202 VisitCallArgs(call);
1203 DCHECK_EQ(kAstF64, call_type);
1204 current_function_builder_->Emit(kExprF64Atan2);
1205 break;
1206 }
1207 case AsmTyper::kMathPow: {
1208 VisitCallArgs(call);
1209 DCHECK_EQ(kAstF64, call_type);
1210 current_function_builder_->Emit(kExprF64Pow);
1211 break;
1212 }
1213 case AsmTyper::kMathImul: {
1214 VisitCallArgs(call);
1215 current_function_builder_->Emit(kExprI32Mul);
1216 break;
1217 }
1218 case AsmTyper::kMathFround: {
1219 DCHECK(args->length() == 1);
1220 Literal* literal = args->at(0)->AsLiteral();
1221 if (literal != nullptr) {
1222 // constant fold Math.fround(#const);
1223 if (literal->raw_value()->IsNumber()) {
1224 float val = static_cast<float>(literal->raw_value()->AsNumber());
1225 byte code[] = {WASM_F32(val)};
1226 current_function_builder_->EmitCode(code, sizeof(code));
1227 return true;
1228 }
1229 }
1230 VisitCallArgs(call);
1231 switch (TypeIndexOf(args->at(0))) {
1232 case kInt32:
1233 case kFixnum:
1234 current_function_builder_->Emit(kExprF32SConvertI32);
1235 break;
1236 case kUint32:
1237 current_function_builder_->Emit(kExprF32UConvertI32);
1238 break;
1239 case kFloat32:
1240 break;
1241 case kFloat64:
1242 current_function_builder_->Emit(kExprF32ConvertF64);
1243 break;
1244 default:
1245 UNREACHABLE();
1246 }
1247 break;
1248 }
1249 default: {
1250 UNREACHABLE();
1251 break;
1252 }
1253 }
1254 return true;
1255 }
1256
1257 void VisitCallArgs(Call* expr) {
1258 ZoneList<Expression*>* args = expr->arguments();
1259 for (int i = 0; i < args->length(); ++i) {
1260 Expression* arg = args->at(i);
1261 RECURSE(Visit(arg));
1262 }
1263 }
1264
1265 void VisitCall(Call* expr) override {
1266 Call::CallType call_type = expr->GetCallType(isolate_);
1267 switch (call_type) {
1268 case Call::OTHER_CALL: {
1269 DCHECK_EQ(kFuncScope, scope_);
1270 VariableProxy* proxy = expr->expression()->AsVariableProxy();
1271 if (proxy != nullptr) {
1272 if (VisitStdlibFunction(expr, proxy)) {
1273 return;
1274 }
1275 }
1276 uint32_t index;
1277 VariableProxy* vp = expr->expression()->AsVariableProxy();
1278 if (vp != nullptr &&
1279 Type::Any()->Is(bounds_->get(vp).lower->AsFunction()->Result())) {
1280 LocalType return_type = TypeOf(expr);
1281 ZoneList<Expression*>* args = expr->arguments();
1282 FunctionSig::Builder sig(zone(), return_type == kAstStmt ? 0 : 1,
1283 args->length());
1284 if (return_type != kAstStmt) {
1285 sig.AddReturn(return_type);
1286 }
1287 for (int i = 0; i < args->length(); ++i) {
1288 sig.AddParam(TypeOf(args->at(i)));
1289 }
1290 index =
1291 imported_function_table_.GetFunctionIndex(vp->var(), sig.Build());
1292 VisitCallArgs(expr);
1293 current_function_builder_->Emit(kExprCallImport);
1294 current_function_builder_->EmitVarInt(expr->arguments()->length());
1295 current_function_builder_->EmitVarInt(index);
1296 } else {
1297 index = LookupOrInsertFunction(vp->var());
1298 VisitCallArgs(expr);
1299 current_function_builder_->Emit(kExprCallFunction);
1300 current_function_builder_->EmitVarInt(expr->arguments()->length());
1301 current_function_builder_->EmitVarInt(index);
1302 }
1303 break;
1304 }
1305 case Call::KEYED_PROPERTY_CALL: {
1306 DCHECK_EQ(kFuncScope, scope_);
1307 Property* p = expr->expression()->AsProperty();
1308 DCHECK_NOT_NULL(p);
1309 VariableProxy* var = p->obj()->AsVariableProxy();
1310 DCHECK_NOT_NULL(var);
1311 FunctionTableIndices* indices = LookupFunctionTable(var->var());
1312 RECURSE(Visit(p->key()));
1313 current_function_builder_->EmitI32Const(indices->start_index);
1314 current_function_builder_->Emit(kExprI32Add);
1315 VisitCallArgs(expr);
1316 current_function_builder_->Emit(kExprCallIndirect);
1317 current_function_builder_->EmitVarInt(expr->arguments()->length());
1318 current_function_builder_->EmitVarInt(indices->signature_index);
1319 break;
1320 }
1321 default:
1322 UNREACHABLE();
1323 }
1324 }
1325
1326 void VisitCallNew(CallNew* expr) override { UNREACHABLE(); }
1327
1328 void VisitCallRuntime(CallRuntime* expr) override { UNREACHABLE(); }
1329
1330 void VisitUnaryOperation(UnaryOperation* expr) override {
1331 RECURSE(Visit(expr->expression()));
1332 switch (expr->op()) {
1333 case Token::NOT: {
1334 DCHECK_EQ(kAstI32, TypeOf(expr->expression()));
1335 current_function_builder_->Emit(kExprI32Eqz);
1336 break;
1337 }
1338 default:
1339 UNREACHABLE();
1340 }
1341 }
1342
1343 void VisitCountOperation(CountOperation* expr) override { UNREACHABLE(); }
1344
1345 bool MatchIntBinaryOperation(BinaryOperation* expr, Token::Value op,
1346 int32_t val) {
1347 DCHECK_NOT_NULL(expr->right());
1348 if (expr->op() == op && expr->right()->IsLiteral() &&
1349 TypeOf(expr) == kAstI32) {
1350 Literal* right = expr->right()->AsLiteral();
1351 DCHECK(right->raw_value()->IsNumber());
1352 if (static_cast<int32_t>(right->raw_value()->AsNumber()) == val) {
1353 return true;
1354 }
1355 }
1356 return false;
1357 }
1358
1359 bool MatchDoubleBinaryOperation(BinaryOperation* expr, Token::Value op,
1360 double val) {
1361 DCHECK_NOT_NULL(expr->right());
1362 if (expr->op() == op && expr->right()->IsLiteral() &&
1363 TypeOf(expr) == kAstF64) {
1364 Literal* right = expr->right()->AsLiteral();
1365 DCHECK(right->raw_value()->IsNumber());
1366 if (right->raw_value()->AsNumber() == val) {
1367 return true;
1368 }
1369 }
1370 return false;
1371 }
1372
1373 enum ConvertOperation { kNone, kAsIs, kToInt, kToDouble };
1374
1375 ConvertOperation MatchOr(BinaryOperation* expr) {
1376 if (MatchIntBinaryOperation(expr, Token::BIT_OR, 0) &&
1377 (TypeOf(expr->left()) == kAstI32)) {
1378 return kAsIs;
1379 } else {
1380 return kNone;
1381 }
1382 }
1383
1384 ConvertOperation MatchShr(BinaryOperation* expr) {
1385 if (MatchIntBinaryOperation(expr, Token::SHR, 0)) {
1386 // TODO(titzer): this probably needs to be kToUint
1387 return (TypeOf(expr->left()) == kAstI32) ? kAsIs : kToInt;
1388 } else {
1389 return kNone;
1390 }
1391 }
1392
1393 ConvertOperation MatchXor(BinaryOperation* expr) {
1394 if (MatchIntBinaryOperation(expr, Token::BIT_XOR, 0xffffffff)) {
1395 DCHECK_EQ(kAstI32, TypeOf(expr->left()));
1396 DCHECK_EQ(kAstI32, TypeOf(expr->right()));
1397 BinaryOperation* op = expr->left()->AsBinaryOperation();
1398 if (op != nullptr) {
1399 if (MatchIntBinaryOperation(op, Token::BIT_XOR, 0xffffffff)) {
1400 DCHECK_EQ(kAstI32, TypeOf(op->right()));
1401 if (TypeOf(op->left()) != kAstI32) {
1402 return kToInt;
1403 } else {
1404 return kAsIs;
1405 }
1406 }
1407 }
1408 }
1409 return kNone;
1410 }
1411
1412 ConvertOperation MatchMul(BinaryOperation* expr) {
1413 if (MatchDoubleBinaryOperation(expr, Token::MUL, 1.0)) {
1414 DCHECK_EQ(kAstF64, TypeOf(expr->right()));
1415 if (TypeOf(expr->left()) != kAstF64) {
1416 return kToDouble;
1417 } else {
1418 return kAsIs;
1419 }
1420 } else {
1421 return kNone;
1422 }
1423 }
1424
1425 ConvertOperation MatchBinaryOperation(BinaryOperation* expr) {
1426 switch (expr->op()) {
1427 case Token::BIT_OR:
1428 return MatchOr(expr);
1429 case Token::SHR:
1430 return MatchShr(expr);
1431 case Token::BIT_XOR:
1432 return MatchXor(expr);
1433 case Token::MUL:
1434 return MatchMul(expr);
1435 default:
1436 return kNone;
1437 }
1438 }
1439
1440 // Work around Mul + Div being defined in PPC assembler.
1441 #ifdef Mul
1442 #undef Mul
1443 #endif
1444
1445 #define NON_SIGNED_BINOP(op) \
1446 static WasmOpcode opcodes[] = { \
1447 kExprI32##op, \
1448 kExprI32##op, \
1449 kExprF32##op, \
1450 kExprF64##op \
1451 }
1452
1453 #define SIGNED_BINOP(op) \
1454 static WasmOpcode opcodes[] = { \
1455 kExprI32##op##S, \
1456 kExprI32##op##U, \
1457 kExprF32##op, \
1458 kExprF64##op \
1459 }
1460
1461 #define NON_SIGNED_INT_BINOP(op) \
1462 static WasmOpcode opcodes[] = { kExprI32##op, kExprI32##op }
1463
1464 #define BINOP_CASE(token, op, V, ignore_sign) \
1465 case token: { \
1466 V(op); \
1467 int type = TypeIndexOf(expr->left(), expr->right(), ignore_sign); \
1468 current_function_builder_->Emit(opcodes[type]); \
1469 break; \
1470 }
1471
1472 Expression* GetLeft(BinaryOperation* expr) {
1473 if (expr->op() == Token::BIT_XOR) {
1474 return expr->left()->AsBinaryOperation()->left();
1475 } else {
1476 return expr->left();
1477 }
1478 }
1479
1480 void VisitBinaryOperation(BinaryOperation* expr) override {
1481 ConvertOperation convertOperation = MatchBinaryOperation(expr);
1482 if (convertOperation == kToDouble) {
1483 RECURSE(Visit(expr->left()));
1484 TypeIndex type = TypeIndexOf(expr->left());
1485 if (type == kInt32 || type == kFixnum) {
1486 current_function_builder_->Emit(kExprF64SConvertI32);
1487 } else if (type == kUint32) {
1488 current_function_builder_->Emit(kExprF64UConvertI32);
1489 } else if (type == kFloat32) {
1490 current_function_builder_->Emit(kExprF64ConvertF32);
1491 } else {
1492 UNREACHABLE();
1493 }
1494 } else if (convertOperation == kToInt) {
1495 RECURSE(Visit(GetLeft(expr)));
1496 TypeIndex type = TypeIndexOf(GetLeft(expr));
1497 if (type == kFloat32) {
1498 current_function_builder_->Emit(kExprI32AsmjsSConvertF32);
1499 } else if (type == kFloat64) {
1500 current_function_builder_->Emit(kExprI32AsmjsSConvertF64);
1501 } else {
1502 UNREACHABLE();
1503 }
1504 } else if (convertOperation == kAsIs) {
1505 RECURSE(Visit(GetLeft(expr)));
1506 } else {
1507 if (expr->op() == Token::COMMA) {
1508 current_function_builder_->Emit(kExprBlock);
1509 }
1510
1511 RECURSE(Visit(expr->left()));
1512 RECURSE(Visit(expr->right()));
1513
1514 if (expr->op() == Token::COMMA) {
1515 current_function_builder_->Emit(kExprEnd);
1516 }
1517
1518 switch (expr->op()) {
1519 BINOP_CASE(Token::ADD, Add, NON_SIGNED_BINOP, true);
1520 BINOP_CASE(Token::SUB, Sub, NON_SIGNED_BINOP, true);
1521 BINOP_CASE(Token::MUL, Mul, NON_SIGNED_BINOP, true);
1522 BINOP_CASE(Token::BIT_OR, Ior, NON_SIGNED_INT_BINOP, true);
1523 BINOP_CASE(Token::BIT_AND, And, NON_SIGNED_INT_BINOP, true);
1524 BINOP_CASE(Token::BIT_XOR, Xor, NON_SIGNED_INT_BINOP, true);
1525 BINOP_CASE(Token::SHL, Shl, NON_SIGNED_INT_BINOP, true);
1526 BINOP_CASE(Token::SAR, ShrS, NON_SIGNED_INT_BINOP, true);
1527 BINOP_CASE(Token::SHR, ShrU, NON_SIGNED_INT_BINOP, true);
1528 case Token::DIV: {
1529 static WasmOpcode opcodes[] = {kExprI32AsmjsDivS, kExprI32AsmjsDivU,
1530 kExprF32Div, kExprF64Div};
1531 int type = TypeIndexOf(expr->left(), expr->right(), false);
1532 current_function_builder_->Emit(opcodes[type]);
1533 break;
1534 }
1535 case Token::MOD: {
1536 TypeIndex type = TypeIndexOf(expr->left(), expr->right(), false);
1537 if (type == kInt32) {
1538 current_function_builder_->Emit(kExprI32AsmjsRemS);
1539 } else if (type == kUint32) {
1540 current_function_builder_->Emit(kExprI32AsmjsRemU);
1541 } else if (type == kFloat64) {
1542 current_function_builder_->Emit(kExprF64Mod);
1543 return;
1544 } else {
1545 UNREACHABLE();
1546 }
1547 break;
1548 }
1549 case Token::COMMA: {
1550 break;
1551 }
1552 default:
1553 UNREACHABLE();
1554 }
1555 }
1556 }
1557
1558 void VisitCompareOperation(CompareOperation* expr) override {
1559 RECURSE(Visit(expr->left()));
1560 RECURSE(Visit(expr->right()));
1561 switch (expr->op()) {
1562 BINOP_CASE(Token::EQ, Eq, NON_SIGNED_BINOP, false);
1563 BINOP_CASE(Token::LT, Lt, SIGNED_BINOP, false);
1564 BINOP_CASE(Token::LTE, Le, SIGNED_BINOP, false);
1565 BINOP_CASE(Token::GT, Gt, SIGNED_BINOP, false);
1566 BINOP_CASE(Token::GTE, Ge, SIGNED_BINOP, false);
1567 default:
1568 UNREACHABLE();
1569 }
1570 }
1571
1572 #undef BINOP_CASE
1573 #undef NON_SIGNED_INT_BINOP
1574 #undef SIGNED_BINOP
1575 #undef NON_SIGNED_BINOP
1576
1577 enum TypeIndex {
1578 kInt32 = 0,
1579 kUint32 = 1,
1580 kFloat32 = 2,
1581 kFloat64 = 3,
1582 kFixnum = 4
1583 };
1584
1585 TypeIndex TypeIndexOf(Expression* left, Expression* right, bool ignore_sign) {
1586 TypeIndex left_index = TypeIndexOf(left);
1587 TypeIndex right_index = TypeIndexOf(right);
1588 if (left_index == kFixnum) {
1589 left_index = right_index;
1590 }
1591 if (right_index == kFixnum) {
1592 right_index = left_index;
1593 }
1594 if (left_index == kFixnum && right_index == kFixnum) {
1595 left_index = kInt32;
1596 right_index = kInt32;
1597 }
1598 DCHECK((left_index == right_index) ||
1599 (ignore_sign && (left_index <= 1) && (right_index <= 1)));
1600 return left_index;
1601 }
1602
1603 TypeIndex TypeIndexOf(Expression* expr) {
1604 DCHECK_EQ(bounds_->get(expr).lower, bounds_->get(expr).upper);
1605 Type* type = bounds_->get(expr).lower;
1606 if (type->Is(cache_.kAsmFixnum)) {
1607 return kFixnum;
1608 } else if (type->Is(cache_.kAsmSigned)) {
1609 return kInt32;
1610 } else if (type->Is(cache_.kAsmUnsigned)) {
1611 return kUint32;
1612 } else if (type->Is(cache_.kAsmInt)) {
1613 return kInt32;
1614 } else if (type->Is(cache_.kAsmFloat)) {
1615 return kFloat32;
1616 } else if (type->Is(cache_.kAsmDouble)) {
1617 return kFloat64;
1618 } else {
1619 UNREACHABLE();
1620 return kInt32;
1621 }
1622 }
1623
1624 #undef CASE
1625 #undef NON_SIGNED_INT
1626 #undef SIGNED
1627 #undef NON_SIGNED
1628
1629 void VisitThisFunction(ThisFunction* expr) override { UNREACHABLE(); }
1630
1631 void VisitDeclarations(ZoneList<Declaration*>* decls) override {
1632 for (int i = 0; i < decls->length(); ++i) {
1633 Declaration* decl = decls->at(i);
1634 RECURSE(Visit(decl));
1635 }
1636 }
1637
1638 void VisitClassLiteral(ClassLiteral* expr) override { UNREACHABLE(); }
1639
1640 void VisitSpread(Spread* expr) override { UNREACHABLE(); }
1641
1642 void VisitSuperPropertyReference(SuperPropertyReference* expr) override {
1643 UNREACHABLE();
1644 }
1645
1646 void VisitSuperCallReference(SuperCallReference* expr) override {
1647 UNREACHABLE();
1648 }
1649
1650 void VisitSloppyBlockFunctionStatement(
1651 SloppyBlockFunctionStatement* expr) override {
1652 UNREACHABLE();
1653 }
1654
1655 void VisitDoExpression(DoExpression* expr) override { UNREACHABLE(); }
1656
1657 void VisitRewritableExpression(RewritableExpression* expr) override {
1658 UNREACHABLE();
1659 }
1660
1661 struct IndexContainer : public ZoneObject {
1662 uint32_t index;
1663 };
1664
1665 uint32_t LookupOrInsertLocal(Variable* v, LocalType type) {
1666 DCHECK_NOT_NULL(current_function_builder_);
1667 ZoneHashMap::Entry* entry =
1668 local_variables_.Lookup(v, ComputePointerHash(v));
1669 if (entry == nullptr) {
1670 uint32_t index;
1671 DCHECK(!v->IsParameter());
1672 index = current_function_builder_->AddLocal(type);
1673 IndexContainer* container = new (zone()) IndexContainer();
1674 container->index = index;
1675 entry = local_variables_.LookupOrInsert(v, ComputePointerHash(v),
1676 ZoneAllocationPolicy(zone()));
1677 entry->value = container;
1678 }
1679 return (reinterpret_cast<IndexContainer*>(entry->value))->index;
1680 }
1681
1682 void InsertParameter(Variable* v, LocalType type, uint32_t index) {
1683 DCHECK(v->IsParameter());
1684 DCHECK_NOT_NULL(current_function_builder_);
1685 ZoneHashMap::Entry* entry =
1686 local_variables_.Lookup(v, ComputePointerHash(v));
1687 DCHECK_NULL(entry);
1688 IndexContainer* container = new (zone()) IndexContainer();
1689 container->index = index;
1690 entry = local_variables_.LookupOrInsert(v, ComputePointerHash(v),
1691 ZoneAllocationPolicy(zone()));
1692 entry->value = container;
1693 }
1694
1695 uint32_t LookupOrInsertGlobal(Variable* v, LocalType type) {
1696 ZoneHashMap::Entry* entry =
1697 global_variables_.Lookup(v, ComputePointerHash(v));
1698 if (entry == nullptr) {
1699 uint32_t index =
1700 builder_->AddGlobal(WasmOpcodes::MachineTypeFor(type), 0);
1701 IndexContainer* container = new (zone()) IndexContainer();
1702 container->index = index;
1703 entry = global_variables_.LookupOrInsert(v, ComputePointerHash(v),
1704 ZoneAllocationPolicy(zone()));
1705 entry->value = container;
1706 }
1707 return (reinterpret_cast<IndexContainer*>(entry->value))->index;
1708 }
1709
1710 uint32_t LookupOrInsertFunction(Variable* v) {
1711 DCHECK_NOT_NULL(builder_);
1712 ZoneHashMap::Entry* entry = functions_.Lookup(v, ComputePointerHash(v));
1713 if (entry == nullptr) {
1714 uint32_t index = builder_->AddFunction();
1715 IndexContainer* container = new (zone()) IndexContainer();
1716 container->index = index;
1717 entry = functions_.LookupOrInsert(v, ComputePointerHash(v),
1718 ZoneAllocationPolicy(zone()));
1719 entry->value = container;
1720 }
1721 return (reinterpret_cast<IndexContainer*>(entry->value))->index;
1722 }
1723
1724 LocalType TypeOf(Expression* expr) {
1725 DCHECK_EQ(bounds_->get(expr).lower, bounds_->get(expr).upper);
1726 return TypeFrom(bounds_->get(expr).lower);
1727 }
1728
1729 LocalType TypeFrom(Type* type) {
1730 if (type->Is(cache_.kAsmInt)) {
1731 return kAstI32;
1732 } else if (type->Is(cache_.kAsmFloat)) {
1733 return kAstF32;
1734 } else if (type->Is(cache_.kAsmDouble)) {
1735 return kAstF64;
1736 } else {
1737 return kAstStmt;
1738 }
1739 }
1740
1741 Zone* zone() { return zone_; }
1742
1743 ZoneHashMap local_variables_;
1744 ZoneHashMap functions_;
1745 ZoneHashMap global_variables_;
1746 AsmScope scope_;
1747 WasmModuleBuilder* builder_;
1748 WasmFunctionBuilder* current_function_builder_;
1749 FunctionLiteral* literal_;
1750 Isolate* isolate_;
1751 Zone* zone_;
1752 AsmTyper* typer_;
1753 TypeCache const& cache_;
1754 ZoneVector<std::pair<BreakableStatement*, bool>> breakable_blocks_;
1755 ZoneVector<ForeignVariable> foreign_variables_;
1756 uint32_t init_function_index_;
1757 uint32_t foreign_init_function_index_;
1758 uint32_t next_table_index_;
1759 ZoneHashMap function_tables_;
1760 ImportedFunctionTable imported_function_table_;
1761 const AstTypeBounds* bounds_;
1762
1763 DEFINE_AST_VISITOR_SUBCLASS_MEMBERS();
1764
1765 private:
1766 DISALLOW_COPY_AND_ASSIGN(AsmWasmBuilderImpl);
1767 };
1768
1769 AsmWasmBuilder::AsmWasmBuilder(Isolate* isolate, Zone* zone,
1770 FunctionLiteral* literal, AsmTyper* typer)
1771 : isolate_(isolate), zone_(zone), literal_(literal), typer_(typer) {}
1772
1773 // TODO(aseemgarg): probably should take zone (to write wasm to) as input so
1774 // that zone in constructor may be thrown away once wasm module is written.
1775 ZoneBuffer* AsmWasmBuilder::Run(i::Handle<i::FixedArray>* foreign_args) {
1776 AsmWasmBuilderImpl impl(isolate_, zone_, literal_, typer_);
1777 impl.Build();
1778 *foreign_args = impl.GetForeignArgs();
1779 ZoneBuffer* buffer = new (zone_) ZoneBuffer(zone_);
1780 impl.builder_->WriteTo(*buffer);
1781 return buffer;
1782 }
1783 } // namespace wasm
1784 } // namespace internal
1785 } // namespace v8
OLDNEW
« no previous file with comments | « src/wasm/asm-wasm-builder.h ('k') | src/wasm/wasm-js.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698