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