OLD | NEW |
1 // Copyright 2012 the V8 project authors. All rights reserved. | 1 // Copyright 2012 the V8 project authors. All rights reserved. |
2 // Redistribution and use in source and binary forms, with or without | 2 // Redistribution and use in source and binary forms, with or without |
3 // modification, are permitted provided that the following conditions are | 3 // modification, are permitted provided that the following conditions are |
4 // met: | 4 // met: |
5 // | 5 // |
6 // * Redistributions of source code must retain the above copyright | 6 // * Redistributions of source code must retain the above copyright |
7 // notice, this list of conditions and the following disclaimer. | 7 // notice, this list of conditions and the following disclaimer. |
8 // * Redistributions in binary form must reproduce the above | 8 // * Redistributions in binary form must reproduce the above |
9 // copyright notice, this list of conditions and the following | 9 // copyright notice, this list of conditions and the following |
10 // disclaimer in the documentation and/or other materials provided | 10 // disclaimer in the documentation and/or other materials provided |
(...skipping 17 matching lines...) Expand all Loading... |
28 #ifndef V8_PREPARSER_H | 28 #ifndef V8_PREPARSER_H |
29 #define V8_PREPARSER_H | 29 #define V8_PREPARSER_H |
30 | 30 |
31 #include "hashmap.h" | 31 #include "hashmap.h" |
32 #include "token.h" | 32 #include "token.h" |
33 #include "scanner.h" | 33 #include "scanner.h" |
34 | 34 |
35 namespace v8 { | 35 namespace v8 { |
36 | 36 |
37 namespace internal { | 37 namespace internal { |
38 class UnicodeCache; | 38 |
| 39 // Used to detect duplicates in object literals. Each of the values |
| 40 // kGetterProperty, kSetterProperty and kValueProperty represents |
| 41 // a type of object literal property. When parsing a property, its |
| 42 // type value is stored in the DuplicateFinder for the property name. |
| 43 // Values are chosen so that having intersection bits means the there is |
| 44 // an incompatibility. |
| 45 // I.e., you can add a getter to a property that already has a setter, since |
| 46 // kGetterProperty and kSetterProperty doesn't intersect, but not if it |
| 47 // already has a getter or a value. Adding the getter to an existing |
| 48 // setter will store the value (kGetterProperty | kSetterProperty), which |
| 49 // is incompatible with adding any further properties. |
| 50 enum PropertyKind { |
| 51 kNone = 0, |
| 52 // Bit patterns representing different object literal property types. |
| 53 kGetterProperty = 1, |
| 54 kSetterProperty = 2, |
| 55 kValueProperty = 7, |
| 56 // Helper constants. |
| 57 kValueFlag = 4 |
| 58 }; |
| 59 |
| 60 |
| 61 // Validation per 11.1.5 Object Initialiser |
| 62 template<typename P> |
| 63 class ObjectLiteralChecker { |
| 64 public: |
| 65 ObjectLiteralChecker(P* parser, Scanner* scanner, LanguageMode mode) |
| 66 : parser_(parser), |
| 67 scanner_(scanner), |
| 68 finder_(scanner->unicode_cache()), |
| 69 language_mode_(mode) { } |
| 70 |
| 71 void CheckProperty(Token::Value property, PropertyKind type, bool* ok); |
| 72 |
| 73 private: |
| 74 // Checks the type of conflict based on values coming from PropertyType. |
| 75 bool HasConflict(PropertyKind type1, PropertyKind type2) { |
| 76 return (type1 & type2) != 0; |
| 77 } |
| 78 bool IsDataDataConflict(PropertyKind type1, PropertyKind type2) { |
| 79 return ((type1 & type2) & kValueFlag) != 0; |
| 80 } |
| 81 bool IsDataAccessorConflict(PropertyKind type1, PropertyKind type2) { |
| 82 return ((type1 ^ type2) & kValueFlag) != 0; |
| 83 } |
| 84 bool IsAccessorAccessorConflict(PropertyKind type1, PropertyKind type2) { |
| 85 return ((type1 | type2) & kValueFlag) == 0; |
| 86 } |
| 87 |
| 88 P* parser_; |
| 89 Scanner* scanner_; |
| 90 DuplicateFinder finder_; |
| 91 LanguageMode language_mode_; |
| 92 }; |
| 93 |
| 94 |
| 95 template<typename P> |
| 96 void ObjectLiteralChecker<P>::CheckProperty(Token::Value property, |
| 97 PropertyKind type, |
| 98 bool* ok) { |
| 99 int old; |
| 100 if (property == Token::NUMBER) { |
| 101 old = finder_.AddNumber(scanner_->literal_ascii_string(), type); |
| 102 } else if (scanner_->is_literal_ascii()) { |
| 103 old = finder_.AddAsciiSymbol(scanner_->literal_ascii_string(), type); |
| 104 } else { |
| 105 old = finder_.AddUtf16Symbol(scanner_->literal_utf16_string(), type); |
| 106 } |
| 107 PropertyKind old_type = static_cast<PropertyKind>(old); |
| 108 if (HasConflict(old_type, type)) { |
| 109 if (IsDataDataConflict(old_type, type)) { |
| 110 // Both are data properties. |
| 111 if (language_mode_ == CLASSIC_MODE) return; |
| 112 parser_->ReportMessageAt(scanner_->location(), |
| 113 "strict_duplicate_property"); |
| 114 } else if (IsDataAccessorConflict(old_type, type)) { |
| 115 // Both a data and an accessor property with the same name. |
| 116 parser_->ReportMessageAt(scanner_->location(), |
| 117 "accessor_data_property"); |
| 118 } else { |
| 119 ASSERT(IsAccessorAccessorConflict(old_type, type)); |
| 120 // Both accessors of the same type. |
| 121 parser_->ReportMessageAt(scanner_->location(), |
| 122 "accessor_get_set"); |
| 123 } |
| 124 *ok = false; |
| 125 } |
39 } | 126 } |
40 | 127 |
| 128 } // v8::internal |
| 129 |
41 namespace preparser { | 130 namespace preparser { |
42 | 131 |
43 typedef uint8_t byte; | 132 typedef uint8_t byte; |
44 | 133 |
45 // Preparsing checks a JavaScript program and emits preparse-data that helps | 134 // Preparsing checks a JavaScript program and emits preparse-data that helps |
46 // a later parsing to be faster. | 135 // a later parsing to be faster. |
47 // See preparse-data-format.h for the data format. | 136 // See preparse-data-format.h for the data format. |
48 | 137 |
49 // The PreParser checks that the syntax follows the grammar for JavaScript, | 138 // The PreParser checks that the syntax follows the grammar for JavaScript, |
50 // and collects some information about the program along the way. | 139 // and collects some information about the program along the way. |
51 // The grammar check is only performed in order to understand the program | 140 // The grammar check is only performed in order to understand the program |
52 // sufficiently to deduce some information about it, that can be used | 141 // sufficiently to deduce some information about it, that can be used |
53 // to speed up later parsing. Finding errors is not the goal of pre-parsing, | 142 // to speed up later parsing. Finding errors is not the goal of pre-parsing, |
54 // rather it is to speed up properly written and correct programs. | 143 // rather it is to speed up properly written and correct programs. |
55 // That means that contextual checks (like a label being declared where | 144 // That means that contextual checks (like a label being declared where |
56 // it is used) are generally omitted. | 145 // it is used) are generally omitted. |
57 | 146 |
58 namespace i = v8::internal; | 147 namespace i = v8::internal; |
59 | 148 |
60 class DuplicateFinder { | |
61 public: | |
62 explicit DuplicateFinder(i::UnicodeCache* constants) | |
63 : unicode_constants_(constants), | |
64 backing_store_(16), | |
65 map_(&Match) { } | |
66 | |
67 int AddAsciiSymbol(i::Vector<const char> key, int value); | |
68 int AddUtf16Symbol(i::Vector<const uint16_t> key, int value); | |
69 // Add a a number literal by converting it (if necessary) | |
70 // to the string that ToString(ToNumber(literal)) would generate. | |
71 // and then adding that string with AddAsciiSymbol. | |
72 // This string is the actual value used as key in an object literal, | |
73 // and the one that must be different from the other keys. | |
74 int AddNumber(i::Vector<const char> key, int value); | |
75 | |
76 private: | |
77 int AddSymbol(i::Vector<const byte> key, bool is_ascii, int value); | |
78 // Backs up the key and its length in the backing store. | |
79 // The backup is stored with a base 127 encoding of the | |
80 // length (plus a bit saying whether the string is ASCII), | |
81 // followed by the bytes of the key. | |
82 byte* BackupKey(i::Vector<const byte> key, bool is_ascii); | |
83 | |
84 // Compare two encoded keys (both pointing into the backing store) | |
85 // for having the same base-127 encoded lengths and ASCII-ness, | |
86 // and then having the same 'length' bytes following. | |
87 static bool Match(void* first, void* second); | |
88 // Creates a hash from a sequence of bytes. | |
89 static uint32_t Hash(i::Vector<const byte> key, bool is_ascii); | |
90 // Checks whether a string containing a JS number is its canonical | |
91 // form. | |
92 static bool IsNumberCanonical(i::Vector<const char> key); | |
93 | |
94 // Size of buffer. Sufficient for using it to call DoubleToCString in | |
95 // from conversions.h. | |
96 static const int kBufferSize = 100; | |
97 | |
98 i::UnicodeCache* unicode_constants_; | |
99 // Backing store used to store strings used as hashmap keys. | |
100 i::SequenceCollector<unsigned char> backing_store_; | |
101 i::HashMap map_; | |
102 // Buffer used for string->number->canonical string conversions. | |
103 char number_buffer_[kBufferSize]; | |
104 }; | |
105 | |
106 | |
107 class PreParser { | 149 class PreParser { |
108 public: | 150 public: |
109 enum PreParseResult { | 151 enum PreParseResult { |
110 kPreParseStackOverflow, | 152 kPreParseStackOverflow, |
111 kPreParseSuccess | 153 kPreParseSuccess |
112 }; | 154 }; |
113 | 155 |
114 | 156 |
115 PreParser(i::Scanner* scanner, | 157 PreParser(i::Scanner* scanner, |
116 i::ParserRecorder* log, | 158 i::ParserRecorder* log, |
(...skipping 59 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
176 // detail that it can be lazily compiled. | 218 // detail that it can be lazily compiled. |
177 // The scanner is expected to have matched the "function" or "function*" | 219 // The scanner is expected to have matched the "function" or "function*" |
178 // keyword and parameters, and have consumed the initial '{'. | 220 // keyword and parameters, and have consumed the initial '{'. |
179 // At return, unless an error occurred, the scanner is positioned before the | 221 // At return, unless an error occurred, the scanner is positioned before the |
180 // the final '}'. | 222 // the final '}'. |
181 PreParseResult PreParseLazyFunction(i::LanguageMode mode, | 223 PreParseResult PreParseLazyFunction(i::LanguageMode mode, |
182 bool is_generator, | 224 bool is_generator, |
183 i::ParserRecorder* log); | 225 i::ParserRecorder* log); |
184 | 226 |
185 private: | 227 private: |
186 // Used to detect duplicates in object literals. Each of the values | |
187 // kGetterProperty, kSetterProperty and kValueProperty represents | |
188 // a type of object literal property. When parsing a property, its | |
189 // type value is stored in the DuplicateFinder for the property name. | |
190 // Values are chosen so that having intersection bits means the there is | |
191 // an incompatibility. | |
192 // I.e., you can add a getter to a property that already has a setter, since | |
193 // kGetterProperty and kSetterProperty doesn't intersect, but not if it | |
194 // already has a getter or a value. Adding the getter to an existing | |
195 // setter will store the value (kGetterProperty | kSetterProperty), which | |
196 // is incompatible with adding any further properties. | |
197 enum PropertyType { | |
198 kNone = 0, | |
199 // Bit patterns representing different object literal property types. | |
200 kGetterProperty = 1, | |
201 kSetterProperty = 2, | |
202 kValueProperty = 7, | |
203 // Helper constants. | |
204 kValueFlag = 4 | |
205 }; | |
206 | |
207 // Checks the type of conflict based on values coming from PropertyType. | |
208 bool HasConflict(int type1, int type2) { return (type1 & type2) != 0; } | |
209 bool IsDataDataConflict(int type1, int type2) { | |
210 return ((type1 & type2) & kValueFlag) != 0; | |
211 } | |
212 bool IsDataAccessorConflict(int type1, int type2) { | |
213 return ((type1 ^ type2) & kValueFlag) != 0; | |
214 } | |
215 bool IsAccessorAccessorConflict(int type1, int type2) { | |
216 return ((type1 | type2) & kValueFlag) == 0; | |
217 } | |
218 | |
219 | |
220 void CheckDuplicate(DuplicateFinder* finder, | |
221 i::Token::Value property, | |
222 int type, | |
223 bool* ok); | |
224 | |
225 // These types form an algebra over syntactic categories that is just | 228 // These types form an algebra over syntactic categories that is just |
226 // rich enough to let us recognize and propagate the constructs that | 229 // rich enough to let us recognize and propagate the constructs that |
227 // are either being counted in the preparser data, or is important | 230 // are either being counted in the preparser data, or is important |
228 // to throw the correct syntax error exceptions. | 231 // to throw the correct syntax error exceptions. |
229 | 232 |
230 enum ScopeType { | 233 enum ScopeType { |
231 kTopLevelScope, | 234 kTopLevelScope, |
232 kFunctionScope | 235 kFunctionScope |
233 }; | 236 }; |
234 | 237 |
(...skipping 289 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
524 int expected_properties_; | 527 int expected_properties_; |
525 int with_nesting_count_; | 528 int with_nesting_count_; |
526 i::LanguageMode language_mode_; | 529 i::LanguageMode language_mode_; |
527 bool is_generator_; | 530 bool is_generator_; |
528 }; | 531 }; |
529 | 532 |
530 // Report syntax error | 533 // Report syntax error |
531 void ReportUnexpectedToken(i::Token::Value token); | 534 void ReportUnexpectedToken(i::Token::Value token); |
532 void ReportMessageAt(i::Scanner::Location location, | 535 void ReportMessageAt(i::Scanner::Location location, |
533 const char* type, | 536 const char* type, |
534 const char* name_opt) { | 537 const char* name_opt = NULL) { |
535 log_->LogMessage(location.beg_pos, location.end_pos, type, name_opt); | 538 log_->LogMessage(location.beg_pos, location.end_pos, type, name_opt); |
536 } | 539 } |
537 void ReportMessageAt(int start_pos, | 540 void ReportMessageAt(int start_pos, |
538 int end_pos, | 541 int end_pos, |
539 const char* type, | 542 const char* type, |
540 const char* name_opt) { | 543 const char* name_opt) { |
541 log_->LogMessage(start_pos, end_pos, type, name_opt); | 544 log_->LogMessage(start_pos, end_pos, type, name_opt); |
542 } | 545 } |
543 | 546 |
544 void CheckOctalLiteral(int beg_pos, int end_pos, bool* ok); | 547 void CheckOctalLiteral(int beg_pos, int end_pos, bool* ok); |
(...skipping 134 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
679 Scope* scope_; | 682 Scope* scope_; |
680 uintptr_t stack_limit_; | 683 uintptr_t stack_limit_; |
681 i::Scanner::Location strict_mode_violation_location_; | 684 i::Scanner::Location strict_mode_violation_location_; |
682 const char* strict_mode_violation_type_; | 685 const char* strict_mode_violation_type_; |
683 bool stack_overflow_; | 686 bool stack_overflow_; |
684 bool allow_lazy_; | 687 bool allow_lazy_; |
685 bool allow_natives_syntax_; | 688 bool allow_natives_syntax_; |
686 bool allow_generators_; | 689 bool allow_generators_; |
687 bool allow_for_of_; | 690 bool allow_for_of_; |
688 bool parenthesized_function_; | 691 bool parenthesized_function_; |
| 692 |
| 693 friend class i::ObjectLiteralChecker<PreParser>; |
689 }; | 694 }; |
| 695 |
690 } } // v8::preparser | 696 } } // v8::preparser |
691 | 697 |
692 #endif // V8_PREPARSER_H | 698 #endif // V8_PREPARSER_H |
OLD | NEW |