| Index: src/asmjs/asm-typer.cc
|
| diff --git a/src/asmjs/asm-typer.cc b/src/asmjs/asm-typer.cc
|
| index 2b0b91a5568ff8b9081cbbb7db21b03309815d94..ef09006015302a623b105cb651a9a389bb3507c3 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(
|
| @@ -137,9 +182,11 @@ AsmTyper::AsmTyper(Isolate* isolate, Zone* zone, Script* script,
|
| local_scope_(ZoneHashMap::kDefaultHashMapCapacity,
|
| ZoneAllocationPolicy(zone)),
|
| stack_limit_(isolate->stack_guard()->real_climit()),
|
| - node_types_(zone_),
|
| + module_node_types_(zone_),
|
| + function_node_types_(zone_),
|
| fround_type_(AsmType::FroundType(zone_)),
|
| - ffi_type_(AsmType::FFIType(zone_)) {
|
| + ffi_type_(AsmType::FFIType(zone_)),
|
| + function_pointer_tables_(zone_) {
|
| InitializeStdlib();
|
| }
|
|
|
| @@ -390,13 +437,22 @@ bool AsmTyper::AddLocal(Variable* variable, VariableInfo* info) {
|
|
|
| void AsmTyper::SetTypeOf(AstNode* node, AsmType* type) {
|
| DCHECK_NE(type, AsmType::None());
|
| - DCHECK(node_types_.find(node) == node_types_.end());
|
| - node_types_.insert(std::make_pair(node, type));
|
| + if (in_function_) {
|
| + DCHECK(function_node_types_.find(node) == function_node_types_.end());
|
| + function_node_types_.insert(std::make_pair(node, type));
|
| + } else {
|
| + DCHECK(module_node_types_.find(node) == module_node_types_.end());
|
| + module_node_types_.insert(std::make_pair(node, type));
|
| + }
|
| }
|
|
|
| AsmType* AsmTyper::TypeOf(AstNode* node) const {
|
| - auto node_type_iter = node_types_.find(node);
|
| - if (node_type_iter != node_types_.end()) {
|
| + auto node_type_iter = function_node_types_.find(node);
|
| + if (node_type_iter != function_node_types_.end()) {
|
| + return node_type_iter->second;
|
| + }
|
| + node_type_iter = module_node_types_.find(node);
|
| + if (node_type_iter != module_node_types_.end()) {
|
| return node_type_iter->second;
|
| }
|
|
|
| @@ -434,12 +490,34 @@ AsmTyper::StandardMember AsmTyper::VariableAsStandardMember(Variable* var) {
|
| }
|
|
|
| bool AsmTyper::Validate() {
|
| - if (!AsmType::None()->IsExactly(ValidateModule(root_))) {
|
| + return ValidateBeforeFunctionsPhase() &&
|
| + !AsmType::None()->IsExactly(ValidateModuleFunctions(root_)) &&
|
| + ValidateAfterFunctionsPhase();
|
| +}
|
| +
|
| +bool AsmTyper::ValidateBeforeFunctionsPhase() {
|
| + if (!AsmType::None()->IsExactly(ValidateModuleBeforeFunctionsPhase(root_))) {
|
| + return true;
|
| + }
|
| + return false;
|
| +}
|
| +
|
| +bool AsmTyper::ValidateInnerFunction(FunctionDeclaration* fun_decl) {
|
| + if (!AsmType::None()->IsExactly(ValidateModuleFunction(fun_decl))) {
|
| return true;
|
| }
|
| return false;
|
| }
|
|
|
| +bool AsmTyper::ValidateAfterFunctionsPhase() {
|
| + if (!AsmType::None()->IsExactly(ValidateModuleAfterFunctionsPhase(root_))) {
|
| + return true;
|
| + }
|
| + return false;
|
| +}
|
| +
|
| +void AsmTyper::ClearFunctionNodeTypes() { function_node_types_.clear(); }
|
| +
|
| namespace {
|
| bool IsUseAsmDirective(Statement* first_statement) {
|
| ExpressionStatement* use_asm = first_statement->AsExpressionStatement();
|
| @@ -477,89 +555,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::ValidateModuleBeforeFunctionsPhase(FunctionLiteral* fun) {
|
| DeclarationScope* scope = fun->scope();
|
| if (!scope->is_function_scope()) FAIL(fun, "Not at function scope.");
|
| if (!ValidAsmIdentifier(fun->name()))
|
| @@ -594,7 +590,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 +611,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,40 +622,57 @@ 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();
|
| Declaration::List* decls = scope->declarations();
|
| for (Declaration* decl : *decls) {
|
| 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::ValidateModuleAfterFunctionsPhase(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();
|
| + Declaration::List* decls = scope->declarations();
|
| for (Declaration* decl : *decls) {
|
| if (decl->IsFunctionDeclaration()) {
|
| continue;
|
| @@ -682,7 +694,7 @@ AsmType* AsmTyper::ValidateModule(FunctionLiteral* fun) {
|
| }
|
|
|
| // 6.2 ValidateExport
|
| - if (module_return == nullptr) {
|
| + if (module_return_ == nullptr) {
|
| FAIL(fun, "Missing asm.js module export.");
|
| }
|
|
|
| @@ -693,9 +705,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.");
|
| }
|
|
|
|
|