OLD | NEW |
1 // Copyright 2016 the V8 project authors. All rights reserved. | 1 // Copyright 2016 the V8 project authors. All rights reserved. |
2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #include "src/asmjs/asm-typer.h" | 5 #include "src/asmjs/asm-typer.h" |
6 | 6 |
| 7 #include <algorithm> |
7 #include <limits> | 8 #include <limits> |
8 #include <string> | 9 #include <string> |
9 | 10 |
10 #include "src/v8.h" | 11 #include "src/v8.h" |
11 | 12 |
12 #include "src/asmjs/asm-types.h" | 13 #include "src/asmjs/asm-types.h" |
13 #include "src/ast/ast.h" | 14 #include "src/ast/ast.h" |
14 #include "src/ast/scopes.h" | 15 #include "src/ast/scopes.h" |
15 #include "src/base/bits.h" | 16 #include "src/base/bits.h" |
16 #include "src/codegen.h" | 17 #include "src/codegen.h" |
(...skipping 442 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
459 if (assign->op() != Token::INIT) { | 460 if (assign->op() != Token::INIT) { |
460 // Done with initializers. | 461 // Done with initializers. |
461 return nullptr; | 462 return nullptr; |
462 } | 463 } |
463 return assign; | 464 return assign; |
464 } | 465 } |
465 | 466 |
466 } // namespace | 467 } // namespace |
467 | 468 |
468 // 6.1 ValidateModule | 469 // 6.1 ValidateModule |
| 470 namespace { |
| 471 // SourceLayoutTracker keeps track of the start and end positions of each |
| 472 // section in the asm.js source. The sections should not overlap, otherwise the |
| 473 // asm.js source is invalid. |
| 474 class SourceLayoutTracker { |
| 475 public: |
| 476 SourceLayoutTracker() = default; |
| 477 |
| 478 bool IsValid() const { |
| 479 const Section* kAllSections[] = {&use_asm_, &globals_, &functions_, |
| 480 &tables_, &exports_}; |
| 481 for (size_t ii = 0; ii < arraysize(kAllSections); ++ii) { |
| 482 const auto& curr_section = *kAllSections[ii]; |
| 483 for (size_t jj = ii + 1; jj < arraysize(kAllSections); ++jj) { |
| 484 if (curr_section.OverlapsWith(*kAllSections[jj])) { |
| 485 return false; |
| 486 } |
| 487 } |
| 488 } |
| 489 return true; |
| 490 } |
| 491 |
| 492 void AddUseAsm(const AstNode& node) { use_asm_.AddNewElement(node); } |
| 493 |
| 494 void AddGlobal(const AstNode& node) { globals_.AddNewElement(node); } |
| 495 |
| 496 void AddFunction(const AstNode& node) { functions_.AddNewElement(node); } |
| 497 |
| 498 void AddTable(const AstNode& node) { tables_.AddNewElement(node); } |
| 499 |
| 500 void AddExport(const AstNode& node) { exports_.AddNewElement(node); } |
| 501 |
| 502 private: |
| 503 class Section { |
| 504 public: |
| 505 Section() = default; |
| 506 Section(const Section&) = default; |
| 507 Section& operator=(const Section&) = default; |
| 508 |
| 509 void AddNewElement(const AstNode& node) { |
| 510 const int node_pos = node.position(); |
| 511 if (start_ == kNoSourcePosition) { |
| 512 start_ = node_pos; |
| 513 } else { |
| 514 start_ = std::max(start_, node_pos); |
| 515 } |
| 516 if (end_ == kNoSourcePosition) { |
| 517 end_ = node_pos; |
| 518 } else { |
| 519 end_ = std::max(end_, node_pos); |
| 520 } |
| 521 } |
| 522 |
| 523 bool OverlapsWith(const Section& other) const { |
| 524 if (start_ == kNoSourcePosition) { |
| 525 DCHECK_EQ(end_, kNoSourcePosition); |
| 526 return false; |
| 527 } |
| 528 if (other.start_ == kNoSourcePosition) { |
| 529 DCHECK_EQ(other.end_, kNoSourcePosition); |
| 530 return false; |
| 531 } |
| 532 return other.start_ < end_ || other.end_ < start_; |
| 533 } |
| 534 |
| 535 private: |
| 536 int start_ = kNoSourcePosition; |
| 537 int end_ = kNoSourcePosition; |
| 538 }; |
| 539 |
| 540 Section use_asm_; |
| 541 Section globals_; |
| 542 Section functions_; |
| 543 Section tables_; |
| 544 Section exports_; |
| 545 |
| 546 DISALLOW_COPY_AND_ASSIGN(SourceLayoutTracker); |
| 547 }; |
| 548 } // namespace |
| 549 |
469 AsmType* AsmTyper::ValidateModule(FunctionLiteral* fun) { | 550 AsmType* AsmTyper::ValidateModule(FunctionLiteral* fun) { |
| 551 SourceLayoutTracker source_layout; |
| 552 |
470 Scope* scope = fun->scope(); | 553 Scope* scope = fun->scope(); |
471 if (!scope->is_function_scope()) FAIL(fun, "Not at function scope."); | 554 if (!scope->is_function_scope()) FAIL(fun, "Not at function scope."); |
472 if (!ValidAsmIdentifier(fun->name())) | 555 if (!ValidAsmIdentifier(fun->name())) |
473 FAIL(fun, "Invalid asm.js identifier in module name."); | 556 FAIL(fun, "Invalid asm.js identifier in module name."); |
474 module_name_ = fun->name(); | 557 module_name_ = fun->name(); |
475 | 558 |
476 // Allowed parameters: Stdlib, FFI, Mem | 559 // Allowed parameters: Stdlib, FFI, Mem |
477 static const uint32_t MaxModuleParameters = 3; | 560 static const uint32_t MaxModuleParameters = 3; |
478 if (scope->num_parameters() > MaxModuleParameters) { | 561 if (scope->num_parameters() > MaxModuleParameters) { |
479 FAIL(fun, "asm.js modules may not have more than three parameters."); | 562 FAIL(fun, "asm.js modules may not have more than three parameters."); |
(...skipping 20 matching lines...) Expand all Loading... |
500 FAIL(fun, "Redeclared identifier in module parameter."); | 583 FAIL(fun, "Redeclared identifier in module parameter."); |
501 } | 584 } |
502 } | 585 } |
503 | 586 |
504 ZoneVector<Assignment*> function_pointer_tables(zone_); | 587 ZoneVector<Assignment*> function_pointer_tables(zone_); |
505 FlattenedStatements iter(zone_, fun->body()); | 588 FlattenedStatements iter(zone_, fun->body()); |
506 auto* use_asm_directive = iter.Next(); | 589 auto* use_asm_directive = iter.Next(); |
507 if (use_asm_directive == nullptr || !IsUseAsmDirective(use_asm_directive)) { | 590 if (use_asm_directive == nullptr || !IsUseAsmDirective(use_asm_directive)) { |
508 FAIL(fun, "Missing \"use asm\"."); | 591 FAIL(fun, "Missing \"use asm\"."); |
509 } | 592 } |
| 593 source_layout.AddUseAsm(*use_asm_directive); |
510 ReturnStatement* module_return = nullptr; | 594 ReturnStatement* module_return = nullptr; |
511 | 595 |
512 // *VIOLATION* The spec states that globals should be followed by function | 596 // *VIOLATION* The spec states that globals should be followed by function |
513 // declarations, which should be followed by function pointer tables, followed | 597 // declarations, which should be followed by function pointer tables, followed |
514 // by the module export (return) statement. Our AST might be rearraged by the | 598 // by the module export (return) statement. Our AST might be rearraged by the |
515 // parser, so we can't rely on it being in source code order. | 599 // parser, so we can't rely on it being in source code order. |
516 while (Statement* current = iter.Next()) { | 600 while (Statement* current = iter.Next()) { |
517 if (auto* assign = ExtractInitializerExpression(current)) { | 601 if (auto* assign = ExtractInitializerExpression(current)) { |
518 if (assign->value()->IsArrayLiteral()) { | 602 if (assign->value()->IsArrayLiteral()) { |
519 // Save function tables for later validation. | 603 // Save function tables for later validation. |
520 function_pointer_tables.push_back(assign); | 604 function_pointer_tables.push_back(assign); |
521 } else { | 605 } else { |
522 RECURSE(ValidateGlobalDeclaration(assign)); | 606 RECURSE(ValidateGlobalDeclaration(assign)); |
| 607 source_layout.AddGlobal(*assign); |
523 } | 608 } |
524 continue; | 609 continue; |
525 } | 610 } |
526 | 611 |
527 if (auto* current_as_return = current->AsReturnStatement()) { | 612 if (auto* current_as_return = current->AsReturnStatement()) { |
528 if (module_return != nullptr) { | 613 if (module_return != nullptr) { |
529 FAIL(fun, "Multiple export statements."); | 614 FAIL(fun, "Multiple export statements."); |
530 } | 615 } |
531 module_return = current_as_return; | 616 module_return = current_as_return; |
| 617 source_layout.AddExport(*module_return); |
532 continue; | 618 continue; |
533 } | 619 } |
534 | 620 |
535 FAIL(current, "Invalid top-level statement in asm.js module."); | 621 FAIL(current, "Invalid top-level statement in asm.js module."); |
536 } | 622 } |
537 | 623 |
538 ZoneList<Declaration*>* decls = scope->declarations(); | 624 ZoneList<Declaration*>* decls = scope->declarations(); |
539 | 625 |
540 for (int ii = 0; ii < decls->length(); ++ii) { | 626 for (int ii = 0; ii < decls->length(); ++ii) { |
541 Declaration* decl = decls->at(ii); | 627 Declaration* decl = decls->at(ii); |
542 | 628 |
543 if (FunctionDeclaration* fun_decl = decl->AsFunctionDeclaration()) { | 629 if (FunctionDeclaration* fun_decl = decl->AsFunctionDeclaration()) { |
544 RECURSE(ValidateFunction(fun_decl)); | 630 RECURSE(ValidateFunction(fun_decl)); |
| 631 source_layout.AddFunction(*fun_decl); |
545 continue; | 632 continue; |
546 } | 633 } |
547 } | 634 } |
548 | 635 |
549 for (auto* function_table : function_pointer_tables) { | 636 for (auto* function_table : function_pointer_tables) { |
550 RECURSE(ValidateFunctionTable(function_table)); | 637 RECURSE(ValidateFunctionTable(function_table)); |
| 638 source_layout.AddTable(*function_table); |
551 } | 639 } |
552 | 640 |
553 for (int ii = 0; ii < decls->length(); ++ii) { | 641 for (int ii = 0; ii < decls->length(); ++ii) { |
554 Declaration* decl = decls->at(ii); | 642 Declaration* decl = decls->at(ii); |
555 | 643 |
556 if (decl->IsFunctionDeclaration()) { | 644 if (decl->IsFunctionDeclaration()) { |
557 continue; | 645 continue; |
558 } | 646 } |
559 | 647 |
560 VariableDeclaration* var_decl = decl->AsVariableDeclaration(); | 648 VariableDeclaration* var_decl = decl->AsVariableDeclaration(); |
(...skipping 18 matching lines...) Expand all Loading... |
579 | 667 |
580 for (auto* forward_def : forward_definitions_) { | 668 for (auto* forward_def : forward_definitions_) { |
581 if (forward_def->missing_definition()) { | 669 if (forward_def->missing_definition()) { |
582 FAIL(forward_def->first_forward_use(), | 670 FAIL(forward_def->first_forward_use(), |
583 "Missing definition for forward declared identifier."); | 671 "Missing definition for forward declared identifier."); |
584 } | 672 } |
585 } | 673 } |
586 | 674 |
587 RECURSE(ValidateExport(module_return)); | 675 RECURSE(ValidateExport(module_return)); |
588 | 676 |
| 677 if (!source_layout.IsValid()) { |
| 678 FAIL(fun, "Invalid asm.js source code layout."); |
| 679 } |
| 680 |
589 return AsmType::Int(); // Any type that is not AsmType::None(); | 681 return AsmType::Int(); // Any type that is not AsmType::None(); |
590 } | 682 } |
591 | 683 |
592 namespace { | 684 namespace { |
593 bool IsDoubleAnnotation(BinaryOperation* binop) { | 685 bool IsDoubleAnnotation(BinaryOperation* binop) { |
594 // *VIOLATION* The parser replaces uses of +x with x*1.0. | 686 // *VIOLATION* The parser replaces uses of +x with x*1.0. |
595 if (binop->op() != Token::MUL) { | 687 if (binop->op() != Token::MUL) { |
596 return false; | 688 return false; |
597 } | 689 } |
598 | 690 |
(...skipping 2036 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
2635 return true; | 2727 return true; |
2636 } | 2728 } |
2637 | 2729 |
2638 *error_message = typer.error_message(); | 2730 *error_message = typer.error_message(); |
2639 return false; | 2731 return false; |
2640 } | 2732 } |
2641 | 2733 |
2642 } // namespace wasm | 2734 } // namespace wasm |
2643 } // namespace internal | 2735 } // namespace internal |
2644 } // namespace v8 | 2736 } // namespace v8 |
OLD | NEW |