| Index: src/asmjs/asm-typer.cc
|
| diff --git a/src/asmjs/asm-typer.cc b/src/asmjs/asm-typer.cc
|
| index 91bec8c09012fa05b0d68b536e5df10b0cbaddb3..56247916693d914274ae9a0f90fd231444102a6b 100644
|
| --- a/src/asmjs/asm-typer.cc
|
| +++ b/src/asmjs/asm-typer.cc
|
| @@ -91,6 +91,51 @@ Statement* AsmTyper::FlattenedStatements::Next() {
|
| }
|
|
|
| // ----------------------------------------------------------------------------
|
| +// Implementation of AsmTyper::SourceLayoutTracker
|
| +
|
| +bool AsmTyper::SourceLayoutTracker::IsValid() const {
|
| + const Section* kAllSections[] = {&use_asm_, &globals_, &functions_, &tables_,
|
| + &exports_};
|
| + for (size_t ii = 0; ii < arraysize(kAllSections); ++ii) {
|
| + const auto& curr_section = *kAllSections[ii];
|
| + for (size_t jj = ii + 1; jj < arraysize(kAllSections); ++jj) {
|
| + if (curr_section.OverlapsWith(*kAllSections[jj])) {
|
| + return false;
|
| + }
|
| + }
|
| + }
|
| + return true;
|
| +}
|
| +
|
| +void AsmTyper::SourceLayoutTracker::Section::AddNewElement(
|
| + const AstNode& node) {
|
| + const int node_pos = node.position();
|
| + if (start_ == kNoSourcePosition) {
|
| + start_ = node_pos;
|
| + } else {
|
| + start_ = std::max(start_, node_pos);
|
| + }
|
| + if (end_ == kNoSourcePosition) {
|
| + end_ = node_pos;
|
| + } else {
|
| + end_ = std::max(end_, node_pos);
|
| + }
|
| +}
|
| +
|
| +bool AsmTyper::SourceLayoutTracker::Section::OverlapsWith(
|
| + const Section& other) const {
|
| + if (start_ == kNoSourcePosition) {
|
| + DCHECK_EQ(end_, kNoSourcePosition);
|
| + return false;
|
| + }
|
| + if (other.start_ == kNoSourcePosition) {
|
| + DCHECK_EQ(other.end_, kNoSourcePosition);
|
| + return false;
|
| + }
|
| + return other.start_ < end_ || other.end_ < start_;
|
| +}
|
| +
|
| +// ----------------------------------------------------------------------------
|
| // Implementation of AsmTyper::VariableInfo
|
|
|
| AsmTyper::VariableInfo* AsmTyper::VariableInfo::ForSpecialSymbol(
|
| @@ -139,7 +184,8 @@ AsmTyper::AsmTyper(Isolate* isolate, Zone* zone, Script* script,
|
| stack_limit_(isolate->stack_guard()->real_climit()),
|
| node_types_(zone_),
|
| fround_type_(AsmType::FroundType(zone_)),
|
| - ffi_type_(AsmType::FFIType(zone_)) {
|
| + ffi_type_(AsmType::FFIType(zone_)),
|
| + function_pointer_tables_(zone_) {
|
| InitializeStdlib();
|
| }
|
|
|
| @@ -434,7 +480,27 @@ AsmTyper::StandardMember AsmTyper::VariableAsStandardMember(Variable* var) {
|
| }
|
|
|
| bool AsmTyper::Validate() {
|
| - if (!AsmType::None()->IsExactly(ValidateModule(root_))) {
|
| + return ValidatePhase1of2() &&
|
| + !AsmType::None()->IsExactly(ValidateModuleFunctions(root_)) &&
|
| + ValidatePhase2of2();
|
| +}
|
| +
|
| +bool AsmTyper::ValidatePhase1of2() {
|
| + if (!AsmType::None()->IsExactly(ValidateModulePhase1of2(root_))) {
|
| + return true;
|
| + }
|
| + return false;
|
| +}
|
| +
|
| +bool AsmTyper::ValidateInnerFunction(FunctionDeclaration* fun_decl) {
|
| + if (!AsmType::None()->IsExactly(ValidateModuleFunction(fun_decl))) {
|
| + return true;
|
| + }
|
| + return false;
|
| +}
|
| +
|
| +bool AsmTyper::ValidatePhase2of2() {
|
| + if (!AsmType::None()->IsExactly(ValidateModulePhase2of2(root_))) {
|
| return true;
|
| }
|
| return false;
|
| @@ -477,89 +543,7 @@ Assignment* ExtractInitializerExpression(Statement* statement) {
|
| } // namespace
|
|
|
| // 6.1 ValidateModule
|
| -namespace {
|
| -// SourceLayoutTracker keeps track of the start and end positions of each
|
| -// section in the asm.js source. The sections should not overlap, otherwise the
|
| -// asm.js source is invalid.
|
| -class SourceLayoutTracker {
|
| - public:
|
| - SourceLayoutTracker() = default;
|
| -
|
| - bool IsValid() const {
|
| - const Section* kAllSections[] = {&use_asm_, &globals_, &functions_,
|
| - &tables_, &exports_};
|
| - for (size_t ii = 0; ii < arraysize(kAllSections); ++ii) {
|
| - const auto& curr_section = *kAllSections[ii];
|
| - for (size_t jj = ii + 1; jj < arraysize(kAllSections); ++jj) {
|
| - if (curr_section.OverlapsWith(*kAllSections[jj])) {
|
| - return false;
|
| - }
|
| - }
|
| - }
|
| - return true;
|
| - }
|
| -
|
| - void AddUseAsm(const AstNode& node) { use_asm_.AddNewElement(node); }
|
| -
|
| - void AddGlobal(const AstNode& node) { globals_.AddNewElement(node); }
|
| -
|
| - void AddFunction(const AstNode& node) { functions_.AddNewElement(node); }
|
| -
|
| - void AddTable(const AstNode& node) { tables_.AddNewElement(node); }
|
| -
|
| - void AddExport(const AstNode& node) { exports_.AddNewElement(node); }
|
| -
|
| - private:
|
| - class Section {
|
| - public:
|
| - Section() = default;
|
| - Section(const Section&) = default;
|
| - Section& operator=(const Section&) = default;
|
| -
|
| - void AddNewElement(const AstNode& node) {
|
| - const int node_pos = node.position();
|
| - if (start_ == kNoSourcePosition) {
|
| - start_ = node_pos;
|
| - } else {
|
| - start_ = std::max(start_, node_pos);
|
| - }
|
| - if (end_ == kNoSourcePosition) {
|
| - end_ = node_pos;
|
| - } else {
|
| - end_ = std::max(end_, node_pos);
|
| - }
|
| - }
|
| -
|
| - bool OverlapsWith(const Section& other) const {
|
| - if (start_ == kNoSourcePosition) {
|
| - DCHECK_EQ(end_, kNoSourcePosition);
|
| - return false;
|
| - }
|
| - if (other.start_ == kNoSourcePosition) {
|
| - DCHECK_EQ(other.end_, kNoSourcePosition);
|
| - return false;
|
| - }
|
| - return other.start_ < end_ || other.end_ < start_;
|
| - }
|
| -
|
| - private:
|
| - int start_ = kNoSourcePosition;
|
| - int end_ = kNoSourcePosition;
|
| - };
|
| -
|
| - Section use_asm_;
|
| - Section globals_;
|
| - Section functions_;
|
| - Section tables_;
|
| - Section exports_;
|
| -
|
| - DISALLOW_COPY_AND_ASSIGN(SourceLayoutTracker);
|
| -};
|
| -} // namespace
|
| -
|
| -AsmType* AsmTyper::ValidateModule(FunctionLiteral* fun) {
|
| - SourceLayoutTracker source_layout;
|
| -
|
| +AsmType* AsmTyper::ValidateModulePhase1of2(FunctionLiteral* fun) {
|
| DeclarationScope* scope = fun->scope();
|
| if (!scope->is_function_scope()) FAIL(fun, "Not at function scope.");
|
| if (!ValidAsmIdentifier(fun->name()))
|
| @@ -594,7 +578,6 @@ AsmType* AsmTyper::ValidateModule(FunctionLiteral* fun) {
|
| }
|
| }
|
|
|
| - ZoneVector<Assignment*> function_pointer_tables(zone_);
|
| FlattenedStatements iter(zone_, fun->body());
|
| auto* use_asm_directive = iter.Next();
|
| if (use_asm_directive == nullptr) {
|
| @@ -616,8 +599,8 @@ AsmType* AsmTyper::ValidateModule(FunctionLiteral* fun) {
|
| if (!IsUseAsmDirective(use_asm_directive)) {
|
| FAIL(fun, "Missing \"use asm\".");
|
| }
|
| - source_layout.AddUseAsm(*use_asm_directive);
|
| - ReturnStatement* module_return = nullptr;
|
| + source_layout_.AddUseAsm(*use_asm_directive);
|
| + module_return_ = nullptr;
|
|
|
| // *VIOLATION* The spec states that globals should be followed by function
|
| // declarations, which should be followed by function pointer tables, followed
|
| @@ -627,43 +610,60 @@ AsmType* AsmTyper::ValidateModule(FunctionLiteral* fun) {
|
| if (auto* assign = ExtractInitializerExpression(current)) {
|
| if (assign->value()->IsArrayLiteral()) {
|
| // Save function tables for later validation.
|
| - function_pointer_tables.push_back(assign);
|
| + function_pointer_tables_.push_back(assign);
|
| } else {
|
| RECURSE(ValidateGlobalDeclaration(assign));
|
| - source_layout.AddGlobal(*assign);
|
| + source_layout_.AddGlobal(*assign);
|
| }
|
| continue;
|
| }
|
|
|
| if (auto* current_as_return = current->AsReturnStatement()) {
|
| - if (module_return != nullptr) {
|
| + if (module_return_ != nullptr) {
|
| FAIL(fun, "Multiple export statements.");
|
| }
|
| - module_return = current_as_return;
|
| - source_layout.AddExport(*module_return);
|
| + module_return_ = current_as_return;
|
| + source_layout_.AddExport(*module_return_);
|
| continue;
|
| }
|
|
|
| FAIL(current, "Invalid top-level statement in asm.js module.");
|
| }
|
|
|
| + return AsmType::Int(); // Any type that is not AsmType::None();
|
| +}
|
| +
|
| +AsmType* AsmTyper::ValidateModuleFunction(FunctionDeclaration* fun_decl) {
|
| + RECURSE(ValidateFunction(fun_decl));
|
| + source_layout_.AddFunction(*fun_decl);
|
| +
|
| + return AsmType::Int(); // Any type that is not AsmType::None();
|
| +}
|
| +
|
| +AsmType* AsmTyper::ValidateModuleFunctions(FunctionLiteral* fun) {
|
| + DeclarationScope* scope = fun->scope();
|
| ZoneList<Declaration*>* decls = scope->declarations();
|
|
|
| for (int ii = 0; ii < decls->length(); ++ii) {
|
| Declaration* decl = decls->at(ii);
|
|
|
| if (FunctionDeclaration* fun_decl = decl->AsFunctionDeclaration()) {
|
| - RECURSE(ValidateFunction(fun_decl));
|
| - source_layout.AddFunction(*fun_decl);
|
| + RECURSE(ValidateModuleFunction(fun_decl));
|
| continue;
|
| }
|
| }
|
|
|
| - for (auto* function_table : function_pointer_tables) {
|
| + return AsmType::Int(); // Any type that is not AsmType::None();
|
| +}
|
| +
|
| +AsmType* AsmTyper::ValidateModulePhase2of2(FunctionLiteral* fun) {
|
| + for (auto* function_table : function_pointer_tables_) {
|
| RECURSE(ValidateFunctionTable(function_table));
|
| - source_layout.AddTable(*function_table);
|
| + source_layout_.AddTable(*function_table);
|
| }
|
|
|
| + DeclarationScope* scope = fun->scope();
|
| + ZoneList<Declaration*>* decls = scope->declarations();
|
| for (int ii = 0; ii < decls->length(); ++ii) {
|
| Declaration* decl = decls->at(ii);
|
|
|
| @@ -687,7 +687,7 @@ AsmType* AsmTyper::ValidateModule(FunctionLiteral* fun) {
|
| }
|
|
|
| // 6.2 ValidateExport
|
| - if (module_return == nullptr) {
|
| + if (module_return_ == nullptr) {
|
| FAIL(fun, "Missing asm.js module export.");
|
| }
|
|
|
| @@ -698,9 +698,9 @@ AsmType* AsmTyper::ValidateModule(FunctionLiteral* fun) {
|
| }
|
| }
|
|
|
| - RECURSE(ValidateExport(module_return));
|
| + RECURSE(ValidateExport(module_return_));
|
|
|
| - if (!source_layout.IsValid()) {
|
| + if (!source_layout_.IsValid()) {
|
| FAIL(fun, "Invalid asm.js source code layout.");
|
| }
|
|
|
| @@ -856,6 +856,7 @@ AsmType* AsmTyper::ValidateGlobalDeclaration(Assignment* assign) {
|
| AsmType* AsmTyper::ExportType(VariableProxy* fun_export) {
|
| auto* fun_info = Lookup(fun_export->var());
|
| if (fun_info == nullptr) {
|
| + UNREACHABLE();
|
| FAIL(fun_export, "Undefined identifier in asm.js module export.");
|
| }
|
|
|
|
|