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: 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 71 void InitializeInitFunction() { 72 FunctionSig::Builder b(zone(), 0, 0); 73 init_function_ = builder_->AddFunction(b.Build()); 74 builder_->MarkStartFunction(init_function_); 75 } 76 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 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 105 void Build() { 106 InitializeInitFunction(); 107 RECURSE(VisitFunctionLiteral(literal_)); 108 BuildForeignInitFunction(); 109 } 110 111 void VisitVariableDeclaration(VariableDeclaration* decl) {} 112 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 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 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: 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 } 168 ~BlockVisitor() { 169 builder_->current_function_builder_->Emit(kExprEnd); 170 builder_->breakable_blocks_.pop_back(); 171 } 172 }; 173 174 void VisitExpressionStatement(ExpressionStatement* stmt) { 175 VisitForEffect(stmt->expression()); 176 } 177 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 203 void VisitEmptyStatement(EmptyStatement* stmt) {} 204 205 void VisitEmptyParentheses(EmptyParentheses* paren) { UNREACHABLE(); } 206 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 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 238 void VisitContinueStatement(ContinueStatement* stmt) { 239 DoBreakOrContinue(stmt->target(), true); 240 } 241 242 void VisitBreakStatement(BreakStatement* stmt) { 243 DoBreakOrContinue(stmt->target(), false); 244 } 245 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 259 void VisitWithStatement(WithStatement* stmt) { UNREACHABLE(); } 260 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 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 377 void VisitCaseClause(CaseClause* clause) { UNREACHABLE(); } 378 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 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 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 426 void VisitForInStatement(ForInStatement* stmt) { UNREACHABLE(); } 427 428 void VisitForOfStatement(ForOfStatement* stmt) { UNREACHABLE(); } 429 430 void VisitTryCatchStatement(TryCatchStatement* stmt) { UNREACHABLE(); } 431 432 void VisitTryFinallyStatement(TryFinallyStatement* stmt) { UNREACHABLE(); } 433 434 void VisitDebuggerStatement(DebuggerStatement* stmt) { UNREACHABLE(); } 435 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 455 void VisitNativeFunctionLiteral(NativeFunctionLiteral* expr) { 456 UNREACHABLE(); 457 } 458 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 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 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 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 628 void VisitRegExpLiteral(RegExpLiteral* expr) { UNREACHABLE(); } 629 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 651 void VisitArrayLiteral(ArrayLiteral* expr) { UNREACHABLE(); } 652 653 void LoadInitFunction() { 654 current_function_builder_ = init_function_; 655 scope_ = kInitScope; 656 } 657 658 void UnLoadInitFunction() { 659 scope_ = kModuleScope; 660 current_function_builder_ = nullptr; 661 } 662 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 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 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 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: 725 explicit ImportedFunctionTable(AsmWasmBuilderImpl* builder) 726 : table_(ZoneHashMap::kDefaultHashMapCapacity, 727 ZoneAllocationPolicy(builder->zone())), 728 builder_(builder) {} 729 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). 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 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 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 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 882 void VisitAssignment(Assignment* expr) { 883 VisitAssignment(expr, kLeaveOnStack); 884 } 885 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 942 void VisitYield(Yield* expr) { UNREACHABLE(); } 943 944 void VisitThrow(Throw* expr) { UNREACHABLE(); } 945 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 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 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 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 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 1296 void VisitCall(Call* expr) { VisitCallExpression(expr); } 1297 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 1378 void VisitCallNew(CallNew* expr) { UNREACHABLE(); } 1379 1380 void VisitCallRuntime(CallRuntime* expr) { UNREACHABLE(); } 1381 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 1395 void VisitCountOperation(CountOperation* expr) { UNREACHABLE(); } 1396 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 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 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 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 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 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 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 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 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 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 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 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 1692 void VisitThisFunction(ThisFunction* expr) { UNREACHABLE(); } 1693 1694 void VisitDeclarations(Declaration::List* decls) { 1695 for (Declaration* decl : *decls) { 1696 RECURSE(Visit(decl)); 1697 } 1698 } 1699 1700 void VisitClassLiteral(ClassLiteral* expr) { UNREACHABLE(); } 1701 1702 void VisitSpread(Spread* expr) { UNREACHABLE(); } 1703 1704 void VisitSuperPropertyReference(SuperPropertyReference* expr) { 1705 UNREACHABLE(); 1706 } 1707 1708 void VisitSuperCallReference(SuperCallReference* expr) { UNREACHABLE(); } 1709 1710 void VisitSloppyBlockFunctionStatement(SloppyBlockFunctionStatement* expr) { 1711 UNREACHABLE(); 1712 } 1713 1714 void VisitDoExpression(DoExpression* expr) { UNREACHABLE(); } 1715 1716 void VisitRewritableExpression(RewritableExpression* expr) { UNREACHABLE(); } 1717 1718 struct IndexContainer : public ZoneObject { 1719 uint32_t index; 1720 }; 1721 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 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 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 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 1795 LocalType TypeOf(Expression* expr) { return TypeFrom(typer_->TypeOf(expr)); } 1796 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 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 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. 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