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 | 38 class UnicodeCache; |
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 } | |
126 } | 39 } |
127 | 40 |
128 } // v8::internal | |
129 | |
130 namespace preparser { | 41 namespace preparser { |
131 | 42 |
132 typedef uint8_t byte; | 43 typedef uint8_t byte; |
133 | 44 |
134 // Preparsing checks a JavaScript program and emits preparse-data that helps | 45 // Preparsing checks a JavaScript program and emits preparse-data that helps |
135 // a later parsing to be faster. | 46 // a later parsing to be faster. |
136 // See preparse-data-format.h for the data format. | 47 // See preparse-data-format.h for the data format. |
137 | 48 |
138 // The PreParser checks that the syntax follows the grammar for JavaScript, | 49 // The PreParser checks that the syntax follows the grammar for JavaScript, |
139 // and collects some information about the program along the way. | 50 // and collects some information about the program along the way. |
140 // The grammar check is only performed in order to understand the program | 51 // The grammar check is only performed in order to understand the program |
141 // sufficiently to deduce some information about it, that can be used | 52 // sufficiently to deduce some information about it, that can be used |
142 // to speed up later parsing. Finding errors is not the goal of pre-parsing, | 53 // to speed up later parsing. Finding errors is not the goal of pre-parsing, |
143 // rather it is to speed up properly written and correct programs. | 54 // rather it is to speed up properly written and correct programs. |
144 // That means that contextual checks (like a label being declared where | 55 // That means that contextual checks (like a label being declared where |
145 // it is used) are generally omitted. | 56 // it is used) are generally omitted. |
146 | 57 |
147 namespace i = v8::internal; | 58 namespace i = v8::internal; |
148 | 59 |
| 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 |
149 class PreParser { | 107 class PreParser { |
150 public: | 108 public: |
151 enum PreParseResult { | 109 enum PreParseResult { |
152 kPreParseStackOverflow, | 110 kPreParseStackOverflow, |
153 kPreParseSuccess | 111 kPreParseSuccess |
154 }; | 112 }; |
155 | 113 |
156 | 114 |
157 PreParser(i::Scanner* scanner, | 115 PreParser(i::Scanner* scanner, |
158 i::ParserRecorder* log, | 116 i::ParserRecorder* log, |
(...skipping 59 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
218 // detail that it can be lazily compiled. | 176 // detail that it can be lazily compiled. |
219 // The scanner is expected to have matched the "function" or "function*" | 177 // The scanner is expected to have matched the "function" or "function*" |
220 // keyword and parameters, and have consumed the initial '{'. | 178 // keyword and parameters, and have consumed the initial '{'. |
221 // At return, unless an error occurred, the scanner is positioned before the | 179 // At return, unless an error occurred, the scanner is positioned before the |
222 // the final '}'. | 180 // the final '}'. |
223 PreParseResult PreParseLazyFunction(i::LanguageMode mode, | 181 PreParseResult PreParseLazyFunction(i::LanguageMode mode, |
224 bool is_generator, | 182 bool is_generator, |
225 i::ParserRecorder* log); | 183 i::ParserRecorder* log); |
226 | 184 |
227 private: | 185 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 |
228 // These types form an algebra over syntactic categories that is just | 225 // These types form an algebra over syntactic categories that is just |
229 // rich enough to let us recognize and propagate the constructs that | 226 // rich enough to let us recognize and propagate the constructs that |
230 // are either being counted in the preparser data, or is important | 227 // are either being counted in the preparser data, or is important |
231 // to throw the correct syntax error exceptions. | 228 // to throw the correct syntax error exceptions. |
232 | 229 |
233 enum ScopeType { | 230 enum ScopeType { |
234 kTopLevelScope, | 231 kTopLevelScope, |
235 kFunctionScope | 232 kFunctionScope |
236 }; | 233 }; |
237 | 234 |
(...skipping 289 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
527 int expected_properties_; | 524 int expected_properties_; |
528 int with_nesting_count_; | 525 int with_nesting_count_; |
529 i::LanguageMode language_mode_; | 526 i::LanguageMode language_mode_; |
530 bool is_generator_; | 527 bool is_generator_; |
531 }; | 528 }; |
532 | 529 |
533 // Report syntax error | 530 // Report syntax error |
534 void ReportUnexpectedToken(i::Token::Value token); | 531 void ReportUnexpectedToken(i::Token::Value token); |
535 void ReportMessageAt(i::Scanner::Location location, | 532 void ReportMessageAt(i::Scanner::Location location, |
536 const char* type, | 533 const char* type, |
537 const char* name_opt = NULL) { | 534 const char* name_opt) { |
538 log_->LogMessage(location.beg_pos, location.end_pos, type, name_opt); | 535 log_->LogMessage(location.beg_pos, location.end_pos, type, name_opt); |
539 } | 536 } |
540 void ReportMessageAt(int start_pos, | 537 void ReportMessageAt(int start_pos, |
541 int end_pos, | 538 int end_pos, |
542 const char* type, | 539 const char* type, |
543 const char* name_opt) { | 540 const char* name_opt) { |
544 log_->LogMessage(start_pos, end_pos, type, name_opt); | 541 log_->LogMessage(start_pos, end_pos, type, name_opt); |
545 } | 542 } |
546 | 543 |
547 void CheckOctalLiteral(int beg_pos, int end_pos, bool* ok); | 544 void CheckOctalLiteral(int beg_pos, int end_pos, bool* ok); |
(...skipping 134 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
682 Scope* scope_; | 679 Scope* scope_; |
683 uintptr_t stack_limit_; | 680 uintptr_t stack_limit_; |
684 i::Scanner::Location strict_mode_violation_location_; | 681 i::Scanner::Location strict_mode_violation_location_; |
685 const char* strict_mode_violation_type_; | 682 const char* strict_mode_violation_type_; |
686 bool stack_overflow_; | 683 bool stack_overflow_; |
687 bool allow_lazy_; | 684 bool allow_lazy_; |
688 bool allow_natives_syntax_; | 685 bool allow_natives_syntax_; |
689 bool allow_generators_; | 686 bool allow_generators_; |
690 bool allow_for_of_; | 687 bool allow_for_of_; |
691 bool parenthesized_function_; | 688 bool parenthesized_function_; |
692 | |
693 friend class i::ObjectLiteralChecker<PreParser>; | |
694 }; | 689 }; |
695 | |
696 } } // v8::preparser | 690 } } // v8::preparser |
697 | 691 |
698 #endif // V8_PREPARSER_H | 692 #endif // V8_PREPARSER_H |
OLD | NEW |