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