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