Chromium Code Reviews| 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 <algorithm> |
| 8 #include <limits> | 8 #include <limits> |
| 9 #include <memory> | 9 #include <memory> |
| 10 #include <string> | 10 #include <string> |
| 11 | 11 |
| 12 #include "src/v8.h" | 12 #include "src/v8.h" |
| 13 | 13 |
| 14 #include "src/asmjs/asm-types.h" | 14 #include "src/asmjs/asm-types.h" |
| 15 #include "src/ast/ast.h" | 15 #include "src/ast/ast.h" |
| 16 #include "src/ast/scopes.h" | 16 #include "src/ast/scopes.h" |
| 17 #include "src/base/bits.h" | 17 #include "src/base/bits.h" |
| 18 #include "src/codegen.h" | 18 #include "src/codegen.h" |
| 19 #include "src/globals.h" | 19 #include "src/globals.h" |
| 20 #include "src/utils.h" | 20 #include "src/utils.h" |
| 21 | 21 |
| 22 #define FAIL_LINE(line, msg) \ | |
| 23 do { \ | |
| 24 base::OS::SNPrintF(error_message_, sizeof(error_message_), \ | |
| 25 "asm: line %d: %s", (line) + 1, msg); \ | |
| 26 return AsmType::None(); \ | |
| 27 } while (false) | |
| 28 | |
| 22 #define FAIL(node, msg) \ | 29 #define FAIL(node, msg) \ |
| 23 do { \ | 30 do { \ |
| 24 int line = node->position() == kNoSourcePosition \ | 31 int line = node->position() == kNoSourcePosition \ |
| 25 ? -1 \ | 32 ? -1 \ |
| 26 : script_->GetLineNumber(node->position()); \ | 33 : script_->GetLineNumber(node->position()); \ |
| 27 base::OS::SNPrintF(error_message_, sizeof(error_message_), \ | 34 FAIL_LINE(line, msg); \ |
| 28 "asm: line %d: %s", line + 1, msg); \ | |
| 29 return AsmType::None(); \ | |
| 30 } while (false) | 35 } while (false) |
| 31 | 36 |
| 32 #define RECURSE(call) \ | 37 #define RECURSE(call) \ |
| 33 do { \ | 38 do { \ |
| 34 if (GetCurrentStackPosition() < stack_limit_) { \ | 39 if (GetCurrentStackPosition() < stack_limit_) { \ |
| 35 stack_overflow_ = true; \ | 40 stack_overflow_ = true; \ |
| 36 FAIL(root_, "Stack overflow while parsing asm.js module."); \ | 41 FAIL(root_, "Stack overflow while parsing asm.js module."); \ |
| 37 } \ | 42 } \ |
| 38 \ | 43 \ |
| 39 AsmType* result = (call); \ | 44 AsmType* result = (call); \ |
| (...skipping 44 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 84 context_stack_.emplace_back( | 89 context_stack_.emplace_back( |
| 85 Context(current_statement->AsBlock()->statements())); | 90 Context(current_statement->AsBlock()->statements())); |
| 86 continue; | 91 continue; |
| 87 } | 92 } |
| 88 | 93 |
| 89 return current_statement; | 94 return current_statement; |
| 90 } | 95 } |
| 91 } | 96 } |
| 92 | 97 |
| 93 // ---------------------------------------------------------------------------- | 98 // ---------------------------------------------------------------------------- |
| 99 // Implementation of AsmTyper::SourceLayoutTracker | |
| 100 | |
| 101 bool AsmTyper::SourceLayoutTracker::IsValid() const { | |
| 102 const Section* kAllSections[] = {&use_asm_, &globals_, &functions_, &tables_, | |
| 103 &exports_}; | |
| 104 for (size_t ii = 0; ii < arraysize(kAllSections); ++ii) { | |
| 105 const auto& curr_section = *kAllSections[ii]; | |
| 106 for (size_t jj = ii + 1; jj < arraysize(kAllSections); ++jj) { | |
| 107 if (curr_section.OverlapsWith(*kAllSections[jj])) { | |
| 108 return false; | |
| 109 } | |
| 110 } | |
| 111 } | |
| 112 return true; | |
| 113 } | |
| 114 | |
| 115 void AsmTyper::SourceLayoutTracker::Section::AddNewElement( | |
| 116 const AstNode& node) { | |
| 117 const int node_pos = node.position(); | |
| 118 if (start_ == kNoSourcePosition) { | |
| 119 start_ = node_pos; | |
| 120 } else { | |
| 121 start_ = std::max(start_, node_pos); | |
| 122 } | |
| 123 if (end_ == kNoSourcePosition) { | |
| 124 end_ = node_pos; | |
| 125 } else { | |
| 126 end_ = std::max(end_, node_pos); | |
| 127 } | |
| 128 } | |
| 129 | |
| 130 bool AsmTyper::SourceLayoutTracker::Section::OverlapsWith( | |
|
titzer
2016/11/29 14:57:37
This check is actually stricter than OverlapsWith;
bradn
2016/11/29 22:09:06
Actually this is too strict.
It happens to work be
bradn
2016/11/29 23:30:02
Actually this is not overlap, renaming.
| |
| 131 const Section& other) const { | |
| 132 if (start_ == kNoSourcePosition) { | |
| 133 DCHECK_EQ(end_, kNoSourcePosition); | |
| 134 return false; | |
| 135 } | |
| 136 if (other.start_ == kNoSourcePosition) { | |
| 137 DCHECK_EQ(other.end_, kNoSourcePosition); | |
| 138 return false; | |
| 139 } | |
| 140 return other.start_ < end_ || other.end_ < start_; | |
| 141 } | |
| 142 | |
| 143 // ---------------------------------------------------------------------------- | |
| 94 // Implementation of AsmTyper::VariableInfo | 144 // Implementation of AsmTyper::VariableInfo |
| 95 | 145 |
| 96 AsmTyper::VariableInfo* AsmTyper::VariableInfo::ForSpecialSymbol( | 146 AsmTyper::VariableInfo* AsmTyper::VariableInfo::ForSpecialSymbol( |
| 97 Zone* zone, StandardMember standard_member) { | 147 Zone* zone, StandardMember standard_member) { |
| 98 DCHECK(standard_member == kStdlib || standard_member == kFFI || | 148 DCHECK(standard_member == kStdlib || standard_member == kFFI || |
| 99 standard_member == kHeap || standard_member == kModule); | 149 standard_member == kHeap || standard_member == kModule); |
| 100 auto* new_var_info = new (zone) VariableInfo(AsmType::None()); | 150 auto* new_var_info = new (zone) VariableInfo(AsmType::None()); |
| 101 new_var_info->standard_member_ = standard_member; | 151 new_var_info->standard_member_ = standard_member; |
| 102 new_var_info->mutability_ = kImmutableGlobal; | 152 new_var_info->mutability_ = kImmutableGlobal; |
| 103 return new_var_info; | 153 return new_var_info; |
| 104 } | 154 } |
| 105 | 155 |
| 106 AsmTyper::VariableInfo* AsmTyper::VariableInfo::Clone(Zone* zone) const { | 156 AsmTyper::VariableInfo* AsmTyper::VariableInfo::Clone(Zone* zone) const { |
| 107 CHECK(standard_member_ != kNone); | 157 CHECK(standard_member_ != kNone); |
| 108 CHECK(!type_->IsA(AsmType::None())); | 158 CHECK(!type_->IsA(AsmType::None())); |
| 109 auto* new_var_info = new (zone) VariableInfo(type_); | 159 auto* new_var_info = new (zone) VariableInfo(type_); |
| 110 new_var_info->standard_member_ = standard_member_; | 160 new_var_info->standard_member_ = standard_member_; |
| 111 new_var_info->mutability_ = mutability_; | 161 new_var_info->mutability_ = mutability_; |
| 112 return new_var_info; | 162 return new_var_info; |
| 113 } | 163 } |
| 114 | 164 |
| 115 void AsmTyper::VariableInfo::FirstForwardUseIs(VariableProxy* var) { | 165 void AsmTyper::VariableInfo::FirstForwardUseIs(int source_location) { |
| 116 DCHECK(first_forward_use_ == nullptr); | 166 DCHECK(source_location_ == -1); |
| 117 missing_definition_ = true; | 167 missing_definition_ = true; |
| 118 first_forward_use_ = var; | 168 source_location_ = source_location; |
| 119 } | 169 } |
| 120 | 170 |
| 121 // ---------------------------------------------------------------------------- | 171 // ---------------------------------------------------------------------------- |
| 122 // Implementation of AsmTyper | 172 // Implementation of AsmTyper |
| 123 | 173 |
| 124 AsmTyper::AsmTyper(Isolate* isolate, Zone* zone, Script* script, | 174 AsmTyper::AsmTyper(Isolate* isolate, Zone* zone, Script* script, |
| 125 FunctionLiteral* root) | 175 FunctionLiteral* root) |
| 126 : isolate_(isolate), | 176 : isolate_(isolate), |
| 127 zone_(zone), | 177 zone_(zone), |
| 128 script_(script), | 178 script_(script), |
| 129 root_(root), | 179 root_(root), |
| 130 forward_definitions_(zone), | 180 forward_definitions_(zone), |
| 131 ffi_use_signatures_(zone), | 181 ffi_use_signatures_(zone), |
| 132 stdlib_types_(zone), | 182 stdlib_types_(zone), |
| 133 stdlib_math_types_(zone), | 183 stdlib_math_types_(zone), |
| 134 module_info_(VariableInfo::ForSpecialSymbol(zone_, kModule)), | 184 module_info_(VariableInfo::ForSpecialSymbol(zone_, kModule)), |
| 135 global_scope_(ZoneHashMap::kDefaultHashMapCapacity, | 185 global_scope_(ZoneHashMap::kDefaultHashMapCapacity, |
| 136 ZoneAllocationPolicy(zone)), | 186 ZoneAllocationPolicy(zone)), |
| 137 local_scope_(ZoneHashMap::kDefaultHashMapCapacity, | 187 local_scope_(ZoneHashMap::kDefaultHashMapCapacity, |
| 138 ZoneAllocationPolicy(zone)), | 188 ZoneAllocationPolicy(zone)), |
| 139 stack_limit_(isolate->stack_guard()->real_climit()), | 189 stack_limit_(isolate->stack_guard()->real_climit()), |
| 140 node_types_(zone_), | 190 module_node_types_(zone_), |
| 191 function_node_types_(zone_), | |
| 141 fround_type_(AsmType::FroundType(zone_)), | 192 fround_type_(AsmType::FroundType(zone_)), |
| 142 ffi_type_(AsmType::FFIType(zone_)) { | 193 ffi_type_(AsmType::FFIType(zone_)), |
| 194 function_pointer_tables_(zone_) { | |
| 143 InitializeStdlib(); | 195 InitializeStdlib(); |
| 144 } | 196 } |
| 145 | 197 |
| 146 namespace { | 198 namespace { |
| 147 bool ValidAsmIdentifier(Handle<String> name) { | 199 bool ValidAsmIdentifier(Handle<String> name) { |
| 148 static const char* kInvalidAsmNames[] = {"eval", "arguments"}; | 200 static const char* kInvalidAsmNames[] = {"eval", "arguments"}; |
| 149 | 201 |
| 150 for (size_t ii = 0; ii < arraysize(kInvalidAsmNames); ++ii) { | 202 for (size_t ii = 0; ii < arraysize(kInvalidAsmNames); ++ii) { |
| 151 if (strcmp(name->ToCString().get(), kInvalidAsmNames[ii]) == 0) { | 203 if (strcmp(name->ToCString().get(), kInvalidAsmNames[ii]) == 0) { |
| 152 return false; | 204 return false; |
| (...skipping 185 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 338 | 390 |
| 339 if (entry == nullptr && !module_name_.is_null() && | 391 if (entry == nullptr && !module_name_.is_null() && |
| 340 module_name_->Equals(*variable->name())) { | 392 module_name_->Equals(*variable->name())) { |
| 341 return module_info_; | 393 return module_info_; |
| 342 } | 394 } |
| 343 | 395 |
| 344 return entry ? reinterpret_cast<VariableInfo*>(entry->value) : nullptr; | 396 return entry ? reinterpret_cast<VariableInfo*>(entry->value) : nullptr; |
| 345 } | 397 } |
| 346 | 398 |
| 347 void AsmTyper::AddForwardReference(VariableProxy* proxy, VariableInfo* info) { | 399 void AsmTyper::AddForwardReference(VariableProxy* proxy, VariableInfo* info) { |
| 348 info->FirstForwardUseIs(proxy); | 400 info->FirstForwardUseIs(proxy->position() == kNoSourcePosition |
| 401 ? -1 | |
| 402 : script_->GetLineNumber(proxy->position())); | |
| 349 forward_definitions_.push_back(info); | 403 forward_definitions_.push_back(info); |
| 350 } | 404 } |
| 351 | 405 |
| 352 bool AsmTyper::AddGlobal(Variable* variable, VariableInfo* info) { | 406 bool AsmTyper::AddGlobal(Variable* variable, VariableInfo* info) { |
| 353 // We can't DCHECK(!in_function_) because function may actually install global | 407 // We can't DCHECK(!in_function_) because function may actually install global |
| 354 // names (forward defined functions and function tables.) | 408 // names (forward defined functions and function tables.) |
| 355 DCHECK(info->mutability() != VariableInfo::kInvalidMutability); | 409 DCHECK(info->mutability() != VariableInfo::kInvalidMutability); |
| 356 DCHECK(info->IsGlobal()); | 410 DCHECK(info->IsGlobal()); |
| 357 DCHECK(ValidAsmIdentifier(variable->name())); | 411 DCHECK(ValidAsmIdentifier(variable->name())); |
| 358 | 412 |
| (...skipping 24 matching lines...) Expand all Loading... | |
| 383 if (entry->value != nullptr) { | 437 if (entry->value != nullptr) { |
| 384 return false; | 438 return false; |
| 385 } | 439 } |
| 386 | 440 |
| 387 entry->value = info; | 441 entry->value = info; |
| 388 return true; | 442 return true; |
| 389 } | 443 } |
| 390 | 444 |
| 391 void AsmTyper::SetTypeOf(AstNode* node, AsmType* type) { | 445 void AsmTyper::SetTypeOf(AstNode* node, AsmType* type) { |
| 392 DCHECK_NE(type, AsmType::None()); | 446 DCHECK_NE(type, AsmType::None()); |
| 393 DCHECK(node_types_.find(node) == node_types_.end()); | 447 if (in_function_) { |
| 394 node_types_.insert(std::make_pair(node, type)); | 448 DCHECK(function_node_types_.find(node) == function_node_types_.end()); |
| 449 function_node_types_.insert(std::make_pair(node, type)); | |
| 450 } else { | |
| 451 DCHECK(module_node_types_.find(node) == module_node_types_.end()); | |
| 452 module_node_types_.insert(std::make_pair(node, type)); | |
| 453 } | |
| 395 } | 454 } |
| 396 | 455 |
| 397 AsmType* AsmTyper::TypeOf(AstNode* node) const { | 456 AsmType* AsmTyper::TypeOf(AstNode* node) const { |
| 398 auto node_type_iter = node_types_.find(node); | 457 auto node_type_iter = function_node_types_.find(node); |
| 399 if (node_type_iter != node_types_.end()) { | 458 if (node_type_iter != function_node_types_.end()) { |
| 459 return node_type_iter->second; | |
| 460 } | |
| 461 node_type_iter = module_node_types_.find(node); | |
| 462 if (node_type_iter != module_node_types_.end()) { | |
| 400 return node_type_iter->second; | 463 return node_type_iter->second; |
| 401 } | 464 } |
| 402 | 465 |
| 403 // Sometimes literal nodes are not added to the node_type_ map simply because | 466 // Sometimes literal nodes are not added to the node_type_ map simply because |
| 404 // their are not visited with ValidateExpression(). | 467 // their are not visited with ValidateExpression(). |
| 405 if (auto* literal = node->AsLiteral()) { | 468 if (auto* literal = node->AsLiteral()) { |
| 406 if (literal->raw_value()->ContainsDot()) { | 469 if (literal->raw_value()->ContainsDot()) { |
| 407 return AsmType::Double(); | 470 return AsmType::Double(); |
| 408 } | 471 } |
| 409 uint32_t u; | 472 uint32_t u; |
| (...skipping 17 matching lines...) Expand all Loading... | |
| 427 AsmTyper::StandardMember AsmTyper::VariableAsStandardMember(Variable* var) { | 490 AsmTyper::StandardMember AsmTyper::VariableAsStandardMember(Variable* var) { |
| 428 auto* var_info = Lookup(var); | 491 auto* var_info = Lookup(var); |
| 429 if (var_info == nullptr) { | 492 if (var_info == nullptr) { |
| 430 return kNone; | 493 return kNone; |
| 431 } | 494 } |
| 432 StandardMember member = var_info->standard_member(); | 495 StandardMember member = var_info->standard_member(); |
| 433 return member; | 496 return member; |
| 434 } | 497 } |
| 435 | 498 |
| 436 bool AsmTyper::Validate() { | 499 bool AsmTyper::Validate() { |
| 437 if (!AsmType::None()->IsExactly(ValidateModule(root_))) { | 500 return ValidateBeforeFunctionsPhase() && |
| 501 !AsmType::None()->IsExactly(ValidateModuleFunctions(root_)) && | |
| 502 ValidateAfterFunctionsPhase(); | |
| 503 } | |
| 504 | |
| 505 bool AsmTyper::ValidateBeforeFunctionsPhase() { | |
| 506 if (!AsmType::None()->IsExactly(ValidateModuleBeforeFunctionsPhase(root_))) { | |
| 438 return true; | 507 return true; |
| 439 } | 508 } |
| 440 return false; | 509 return false; |
| 441 } | 510 } |
| 442 | 511 |
| 512 bool AsmTyper::ValidateInnerFunction(FunctionDeclaration* fun_decl) { | |
| 513 if (!AsmType::None()->IsExactly(ValidateModuleFunction(fun_decl))) { | |
| 514 return true; | |
| 515 } | |
| 516 return false; | |
| 517 } | |
| 518 | |
| 519 bool AsmTyper::ValidateAfterFunctionsPhase() { | |
| 520 if (!AsmType::None()->IsExactly(ValidateModuleAfterFunctionsPhase(root_))) { | |
| 521 return true; | |
| 522 } | |
| 523 return false; | |
| 524 } | |
| 525 | |
| 526 void AsmTyper::ClearFunctionNodeTypes() { function_node_types_.clear(); } | |
| 527 | |
| 443 namespace { | 528 namespace { |
| 444 bool IsUseAsmDirective(Statement* first_statement) { | 529 bool IsUseAsmDirective(Statement* first_statement) { |
| 445 ExpressionStatement* use_asm = first_statement->AsExpressionStatement(); | 530 ExpressionStatement* use_asm = first_statement->AsExpressionStatement(); |
| 446 if (use_asm == nullptr) { | 531 if (use_asm == nullptr) { |
| 447 return false; | 532 return false; |
| 448 } | 533 } |
| 449 | 534 |
| 450 Literal* use_asm_literal = use_asm->expression()->AsLiteral(); | 535 Literal* use_asm_literal = use_asm->expression()->AsLiteral(); |
| 451 | 536 |
| 452 if (use_asm_literal == nullptr) { | 537 if (use_asm_literal == nullptr) { |
| (...skipping 17 matching lines...) Expand all Loading... | |
| 470 if (assign->op() != Token::INIT) { | 555 if (assign->op() != Token::INIT) { |
| 471 // Done with initializers. | 556 // Done with initializers. |
| 472 return nullptr; | 557 return nullptr; |
| 473 } | 558 } |
| 474 return assign; | 559 return assign; |
| 475 } | 560 } |
| 476 | 561 |
| 477 } // namespace | 562 } // namespace |
| 478 | 563 |
| 479 // 6.1 ValidateModule | 564 // 6.1 ValidateModule |
| 480 namespace { | 565 AsmType* AsmTyper::ValidateModuleBeforeFunctionsPhase(FunctionLiteral* fun) { |
| 481 // SourceLayoutTracker keeps track of the start and end positions of each | |
| 482 // section in the asm.js source. The sections should not overlap, otherwise the | |
| 483 // asm.js source is invalid. | |
| 484 class SourceLayoutTracker { | |
| 485 public: | |
| 486 SourceLayoutTracker() = default; | |
| 487 | |
| 488 bool IsValid() const { | |
| 489 const Section* kAllSections[] = {&use_asm_, &globals_, &functions_, | |
| 490 &tables_, &exports_}; | |
| 491 for (size_t ii = 0; ii < arraysize(kAllSections); ++ii) { | |
| 492 const auto& curr_section = *kAllSections[ii]; | |
| 493 for (size_t jj = ii + 1; jj < arraysize(kAllSections); ++jj) { | |
| 494 if (curr_section.OverlapsWith(*kAllSections[jj])) { | |
| 495 return false; | |
| 496 } | |
| 497 } | |
| 498 } | |
| 499 return true; | |
| 500 } | |
| 501 | |
| 502 void AddUseAsm(const AstNode& node) { use_asm_.AddNewElement(node); } | |
| 503 | |
| 504 void AddGlobal(const AstNode& node) { globals_.AddNewElement(node); } | |
| 505 | |
| 506 void AddFunction(const AstNode& node) { functions_.AddNewElement(node); } | |
| 507 | |
| 508 void AddTable(const AstNode& node) { tables_.AddNewElement(node); } | |
| 509 | |
| 510 void AddExport(const AstNode& node) { exports_.AddNewElement(node); } | |
| 511 | |
| 512 private: | |
| 513 class Section { | |
| 514 public: | |
| 515 Section() = default; | |
| 516 Section(const Section&) = default; | |
| 517 Section& operator=(const Section&) = default; | |
| 518 | |
| 519 void AddNewElement(const AstNode& node) { | |
| 520 const int node_pos = node.position(); | |
| 521 if (start_ == kNoSourcePosition) { | |
| 522 start_ = node_pos; | |
| 523 } else { | |
| 524 start_ = std::max(start_, node_pos); | |
| 525 } | |
| 526 if (end_ == kNoSourcePosition) { | |
| 527 end_ = node_pos; | |
| 528 } else { | |
| 529 end_ = std::max(end_, node_pos); | |
| 530 } | |
| 531 } | |
| 532 | |
| 533 bool OverlapsWith(const Section& other) const { | |
| 534 if (start_ == kNoSourcePosition) { | |
| 535 DCHECK_EQ(end_, kNoSourcePosition); | |
| 536 return false; | |
| 537 } | |
| 538 if (other.start_ == kNoSourcePosition) { | |
| 539 DCHECK_EQ(other.end_, kNoSourcePosition); | |
| 540 return false; | |
| 541 } | |
| 542 return other.start_ < end_ || other.end_ < start_; | |
| 543 } | |
| 544 | |
| 545 private: | |
| 546 int start_ = kNoSourcePosition; | |
| 547 int end_ = kNoSourcePosition; | |
| 548 }; | |
| 549 | |
| 550 Section use_asm_; | |
| 551 Section globals_; | |
| 552 Section functions_; | |
| 553 Section tables_; | |
| 554 Section exports_; | |
| 555 | |
| 556 DISALLOW_COPY_AND_ASSIGN(SourceLayoutTracker); | |
| 557 }; | |
| 558 } // namespace | |
| 559 | |
| 560 AsmType* AsmTyper::ValidateModule(FunctionLiteral* fun) { | |
| 561 SourceLayoutTracker source_layout; | |
| 562 | |
| 563 DeclarationScope* scope = fun->scope(); | 566 DeclarationScope* scope = fun->scope(); |
| 564 if (!scope->is_function_scope()) FAIL(fun, "Not at function scope."); | 567 if (!scope->is_function_scope()) FAIL(fun, "Not at function scope."); |
| 565 if (!ValidAsmIdentifier(fun->name())) | 568 if (!ValidAsmIdentifier(fun->name())) |
| 566 FAIL(fun, "Invalid asm.js identifier in module name."); | 569 FAIL(fun, "Invalid asm.js identifier in module name."); |
| 567 module_name_ = fun->name(); | 570 module_name_ = fun->name(); |
| 568 | 571 |
| 569 // Allowed parameters: Stdlib, FFI, Mem | 572 // Allowed parameters: Stdlib, FFI, Mem |
| 570 static const int MaxModuleParameters = 3; | 573 static const int MaxModuleParameters = 3; |
| 571 if (scope->num_parameters() > MaxModuleParameters) { | 574 if (scope->num_parameters() > MaxModuleParameters) { |
| 572 FAIL(fun, "asm.js modules may not have more than three parameters."); | 575 FAIL(fun, "asm.js modules may not have more than three parameters."); |
| (...skipping 14 matching lines...) Expand all Loading... | |
| 587 } | 590 } |
| 588 | 591 |
| 589 auto* param_info = VariableInfo::ForSpecialSymbol( | 592 auto* param_info = VariableInfo::ForSpecialSymbol( |
| 590 zone_, kModuleParamInfo[ii].standard_member); | 593 zone_, kModuleParamInfo[ii].standard_member); |
| 591 | 594 |
| 592 if (!AddGlobal(param, param_info)) { | 595 if (!AddGlobal(param, param_info)) { |
| 593 FAIL(fun, "Redeclared identifier in module parameter."); | 596 FAIL(fun, "Redeclared identifier in module parameter."); |
| 594 } | 597 } |
| 595 } | 598 } |
| 596 | 599 |
| 597 ZoneVector<Assignment*> function_pointer_tables(zone_); | |
| 598 FlattenedStatements iter(zone_, fun->body()); | 600 FlattenedStatements iter(zone_, fun->body()); |
| 599 auto* use_asm_directive = iter.Next(); | 601 auto* use_asm_directive = iter.Next(); |
| 600 if (use_asm_directive == nullptr) { | 602 if (use_asm_directive == nullptr) { |
| 601 FAIL(fun, "Missing \"use asm\"."); | 603 FAIL(fun, "Missing \"use asm\"."); |
| 602 } | 604 } |
| 603 // Check for extra assignment inserted by the parser when in this form: | 605 // Check for extra assignment inserted by the parser when in this form: |
| 604 // (function Module(a, b, c) {... }) | 606 // (function Module(a, b, c) {... }) |
| 605 ExpressionStatement* estatement = use_asm_directive->AsExpressionStatement(); | 607 ExpressionStatement* estatement = use_asm_directive->AsExpressionStatement(); |
| 606 if (estatement != nullptr) { | 608 if (estatement != nullptr) { |
| 607 Assignment* assignment = estatement->expression()->AsAssignment(); | 609 Assignment* assignment = estatement->expression()->AsAssignment(); |
| 608 if (assignment != nullptr && assignment->target()->IsVariableProxy() && | 610 if (assignment != nullptr && assignment->target()->IsVariableProxy() && |
| 609 assignment->target() | 611 assignment->target() |
| 610 ->AsVariableProxy() | 612 ->AsVariableProxy() |
| 611 ->var() | 613 ->var() |
| 612 ->is_sloppy_function_name()) { | 614 ->is_sloppy_function_name()) { |
| 613 use_asm_directive = iter.Next(); | 615 use_asm_directive = iter.Next(); |
| 614 } | 616 } |
| 615 } | 617 } |
| 616 if (!IsUseAsmDirective(use_asm_directive)) { | 618 if (!IsUseAsmDirective(use_asm_directive)) { |
| 617 FAIL(fun, "Missing \"use asm\"."); | 619 FAIL(fun, "Missing \"use asm\"."); |
| 618 } | 620 } |
| 619 source_layout.AddUseAsm(*use_asm_directive); | 621 source_layout_.AddUseAsm(*use_asm_directive); |
| 620 ReturnStatement* module_return = nullptr; | 622 module_return_ = nullptr; |
| 621 | 623 |
| 622 // *VIOLATION* The spec states that globals should be followed by function | 624 // *VIOLATION* The spec states that globals should be followed by function |
| 623 // declarations, which should be followed by function pointer tables, followed | 625 // declarations, which should be followed by function pointer tables, followed |
| 624 // by the module export (return) statement. Our AST might be rearraged by the | 626 // by the module export (return) statement. Our AST might be rearraged by the |
| 625 // parser, so we can't rely on it being in source code order. | 627 // parser, so we can't rely on it being in source code order. |
| 626 while (Statement* current = iter.Next()) { | 628 while (Statement* current = iter.Next()) { |
| 627 if (auto* assign = ExtractInitializerExpression(current)) { | 629 if (auto* assign = ExtractInitializerExpression(current)) { |
| 628 if (assign->value()->IsArrayLiteral()) { | 630 if (assign->value()->IsArrayLiteral()) { |
| 629 // Save function tables for later validation. | 631 // Save function tables for later validation. |
| 630 function_pointer_tables.push_back(assign); | 632 function_pointer_tables_.push_back(assign); |
| 631 } else { | 633 } else { |
| 632 RECURSE(ValidateGlobalDeclaration(assign)); | 634 RECURSE(ValidateGlobalDeclaration(assign)); |
| 633 source_layout.AddGlobal(*assign); | 635 source_layout_.AddGlobal(*assign); |
| 634 } | 636 } |
| 635 continue; | 637 continue; |
| 636 } | 638 } |
| 637 | 639 |
| 638 if (auto* current_as_return = current->AsReturnStatement()) { | 640 if (auto* current_as_return = current->AsReturnStatement()) { |
| 639 if (module_return != nullptr) { | 641 if (module_return_ != nullptr) { |
| 640 FAIL(fun, "Multiple export statements."); | 642 FAIL(fun, "Multiple export statements."); |
| 641 } | 643 } |
| 642 module_return = current_as_return; | 644 module_return_ = current_as_return; |
| 643 source_layout.AddExport(*module_return); | 645 source_layout_.AddExport(*module_return_); |
| 644 continue; | 646 continue; |
| 645 } | 647 } |
| 646 | 648 |
| 647 FAIL(current, "Invalid top-level statement in asm.js module."); | 649 FAIL(current, "Invalid top-level statement in asm.js module."); |
| 648 } | 650 } |
| 649 | 651 |
| 652 return AsmType::Int(); // Any type that is not AsmType::None(); | |
| 653 } | |
| 654 | |
| 655 AsmType* AsmTyper::ValidateModuleFunction(FunctionDeclaration* fun_decl) { | |
| 656 RECURSE(ValidateFunction(fun_decl)); | |
| 657 source_layout_.AddFunction(*fun_decl); | |
| 658 | |
| 659 return AsmType::Int(); // Any type that is not AsmType::None(); | |
| 660 } | |
| 661 | |
| 662 AsmType* AsmTyper::ValidateModuleFunctions(FunctionLiteral* fun) { | |
| 663 DeclarationScope* scope = fun->scope(); | |
| 650 Declaration::List* decls = scope->declarations(); | 664 Declaration::List* decls = scope->declarations(); |
| 651 for (Declaration* decl : *decls) { | 665 for (Declaration* decl : *decls) { |
| 652 if (FunctionDeclaration* fun_decl = decl->AsFunctionDeclaration()) { | 666 if (FunctionDeclaration* fun_decl = decl->AsFunctionDeclaration()) { |
| 653 RECURSE(ValidateFunction(fun_decl)); | 667 RECURSE(ValidateModuleFunction(fun_decl)); |
| 654 source_layout.AddFunction(*fun_decl); | |
| 655 continue; | 668 continue; |
| 656 } | 669 } |
| 657 } | 670 } |
| 658 | 671 |
| 659 for (auto* function_table : function_pointer_tables) { | 672 return AsmType::Int(); // Any type that is not AsmType::None(); |
| 673 } | |
| 674 | |
| 675 AsmType* AsmTyper::ValidateModuleAfterFunctionsPhase(FunctionLiteral* fun) { | |
| 676 for (auto* function_table : function_pointer_tables_) { | |
| 660 RECURSE(ValidateFunctionTable(function_table)); | 677 RECURSE(ValidateFunctionTable(function_table)); |
| 661 source_layout.AddTable(*function_table); | 678 source_layout_.AddTable(*function_table); |
| 662 } | 679 } |
| 663 | 680 |
| 681 DeclarationScope* scope = fun->scope(); | |
| 682 Declaration::List* decls = scope->declarations(); | |
| 664 for (Declaration* decl : *decls) { | 683 for (Declaration* decl : *decls) { |
| 665 if (decl->IsFunctionDeclaration()) { | 684 if (decl->IsFunctionDeclaration()) { |
| 666 continue; | 685 continue; |
| 667 } | 686 } |
| 668 | 687 |
| 669 VariableDeclaration* var_decl = decl->AsVariableDeclaration(); | 688 VariableDeclaration* var_decl = decl->AsVariableDeclaration(); |
| 670 if (var_decl == nullptr) { | 689 if (var_decl == nullptr) { |
| 671 FAIL(decl, "Invalid asm.js declaration."); | 690 FAIL(decl, "Invalid asm.js declaration."); |
| 672 } | 691 } |
| 673 | 692 |
| 674 auto* var_proxy = var_decl->proxy(); | 693 auto* var_proxy = var_decl->proxy(); |
| 675 if (var_proxy == nullptr) { | 694 if (var_proxy == nullptr) { |
| 676 FAIL(decl, "Invalid asm.js declaration."); | 695 FAIL(decl, "Invalid asm.js declaration."); |
| 677 } | 696 } |
| 678 | 697 |
| 679 if (Lookup(var_proxy->var()) == nullptr) { | 698 if (Lookup(var_proxy->var()) == nullptr) { |
| 680 FAIL(decl, "Global variable missing initializer in asm.js module."); | 699 FAIL(decl, "Global variable missing initializer in asm.js module."); |
| 681 } | 700 } |
| 682 } | 701 } |
| 683 | 702 |
| 684 // 6.2 ValidateExport | 703 // 6.2 ValidateExport |
| 685 if (module_return == nullptr) { | 704 if (module_return_ == nullptr) { |
| 686 FAIL(fun, "Missing asm.js module export."); | 705 FAIL(fun, "Missing asm.js module export."); |
| 687 } | 706 } |
| 688 | 707 |
| 689 for (auto* forward_def : forward_definitions_) { | 708 for (auto* forward_def : forward_definitions_) { |
| 690 if (forward_def->missing_definition()) { | 709 if (forward_def->missing_definition()) { |
| 691 FAIL(forward_def->first_forward_use(), | 710 FAIL_LINE(forward_def->source_location(), |
| 692 "Missing definition for forward declared identifier."); | 711 "Missing definition for forward declared identifier."); |
| 693 } | 712 } |
| 694 } | 713 } |
| 695 | 714 |
| 696 RECURSE(ValidateExport(module_return)); | 715 RECURSE(ValidateExport(module_return_)); |
| 697 | 716 |
| 698 if (!source_layout.IsValid()) { | 717 if (!source_layout_.IsValid()) { |
| 699 FAIL(fun, "Invalid asm.js source code layout."); | 718 FAIL(fun, "Invalid asm.js source code layout."); |
| 700 } | 719 } |
| 701 | 720 |
| 702 return AsmType::Int(); // Any type that is not AsmType::None(); | 721 return AsmType::Int(); // Any type that is not AsmType::None(); |
| 703 } | 722 } |
| 704 | 723 |
| 705 namespace { | 724 namespace { |
| 706 bool IsDoubleAnnotation(BinaryOperation* binop) { | 725 bool IsDoubleAnnotation(BinaryOperation* binop) { |
| 707 // *VIOLATION* The parser replaces uses of +x with x*1.0. | 726 // *VIOLATION* The parser replaces uses of +x with x*1.0. |
| 708 if (binop->op() != Token::MUL) { | 727 if (binop->op() != Token::MUL) { |
| (...skipping 2148 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 2857 return true; | 2876 return true; |
| 2858 } | 2877 } |
| 2859 | 2878 |
| 2860 *error_message = typer.error_message(); | 2879 *error_message = typer.error_message(); |
| 2861 return false; | 2880 return false; |
| 2862 } | 2881 } |
| 2863 | 2882 |
| 2864 } // namespace wasm | 2883 } // namespace wasm |
| 2865 } // namespace internal | 2884 } // namespace internal |
| 2866 } // namespace v8 | 2885 } // namespace v8 |
| OLD | NEW |