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