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."); |
} |