OLD | NEW |
1 // Copyright 2011 the V8 project authors. All rights reserved. | 1 // Copyright 2011 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 13 matching lines...) Expand all Loading... |
24 // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | 24 // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
25 // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE | 25 // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE |
26 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | 26 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
27 | 27 |
28 #ifndef V8_PREPARSER_H | 28 #ifndef V8_PREPARSER_H |
29 #define V8_PREPARSER_H | 29 #define V8_PREPARSER_H |
30 | 30 |
31 namespace v8 { | 31 namespace v8 { |
32 namespace preparser { | 32 namespace preparser { |
33 | 33 |
34 typedef uint8_t byte; | |
35 | |
36 // Preparsing checks a JavaScript program and emits preparse-data that helps | 34 // Preparsing checks a JavaScript program and emits preparse-data that helps |
37 // a later parsing to be faster. | 35 // a later parsing to be faster. |
38 // See preparse-data-format.h for the data format. | 36 // See preparse-data-format.h for the data format. |
39 | 37 |
40 // The PreParser checks that the syntax follows the grammar for JavaScript, | 38 // The PreParser checks that the syntax follows the grammar for JavaScript, |
41 // and collects some information about the program along the way. | 39 // and collects some information about the program along the way. |
42 // The grammar check is only performed in order to understand the program | 40 // The grammar check is only performed in order to understand the program |
43 // sufficiently to deduce some information about it, that can be used | 41 // sufficiently to deduce some information about it, that can be used |
44 // to speed up later parsing. Finding errors is not the goal of pre-parsing, | 42 // to speed up later parsing. Finding errors is not the goal of pre-parsing, |
45 // rather it is to speed up properly written and correct programs. | 43 // rather it is to speed up properly written and correct programs. |
46 // That means that contextual checks (like a label being declared where | 44 // That means that contextual checks (like a label being declared where |
47 // it is used) are generally omitted. | 45 // it is used) are generally omitted. |
48 | 46 |
49 namespace i = v8::internal; | 47 namespace i = v8::internal; |
50 | 48 |
51 class DuplicateFinder { | |
52 public: | |
53 explicit DuplicateFinder(i::UnicodeCache* constants) | |
54 : unicode_constants_(constants), | |
55 backing_store_(16), | |
56 map_(new i::HashMap(&Match)) { } | |
57 | |
58 ~DuplicateFinder() { | |
59 delete map_; | |
60 } | |
61 | |
62 int AddAsciiSymbol(i::Vector<const char> key, int value); | |
63 int AddUC16Symbol(i::Vector<const uint16_t> key, int value); | |
64 // Add a a number literal by converting it (if necessary) | |
65 // to the string that ToString(ToNumber(literal)) would generate. | |
66 // and then adding that string with AddAsciiSymbol. | |
67 // This string is the actual value used as key in an object literal, | |
68 // and the one that must be different from the other keys. | |
69 int AddNumber(i::Vector<const char> key, int value); | |
70 | |
71 private: | |
72 int AddSymbol(i::Vector<const byte> key, bool is_ascii, int value); | |
73 // Backs up the key and its length in the backing store. | |
74 // The backup is stored with a base 127 encoding of the | |
75 // length (plus a bit saying whether the string is ASCII), | |
76 // followed by the bytes of the key. | |
77 byte* BackupKey(i::Vector<const byte> key, bool is_ascii); | |
78 | |
79 // Compare two encoded keys (both pointing into the backing store) | |
80 // for having the same base-127 encoded lengths and ASCII-ness, | |
81 // and then having the same 'length' bytes following. | |
82 static bool Match(void* first, void* second); | |
83 // Creates a hash from a sequence of bytes. | |
84 static uint32_t Hash(i::Vector<const byte> key, bool is_ascii); | |
85 // Checks whether a string containing a JS number is its canonical | |
86 // form. | |
87 static bool IsNumberCanonical(i::Vector<const char> key); | |
88 | |
89 // Size of buffer. Sufficient for using it to call DoubleToCString in | |
90 // from conversions.h. | |
91 static const int kBufferSize = 100; | |
92 | |
93 i::UnicodeCache* unicode_constants_; | |
94 // Backing store used to store strings used as hashmap keys. | |
95 i::SequenceCollector<unsigned char> backing_store_; | |
96 i::HashMap* map_; | |
97 // Buffer used for string->number->canonical string conversions. | |
98 char number_buffer_[kBufferSize]; | |
99 }; | |
100 | |
101 | |
102 class PreParser { | 49 class PreParser { |
103 public: | 50 public: |
104 enum PreParseResult { | 51 enum PreParseResult { |
105 kPreParseStackOverflow, | 52 kPreParseStackOverflow, |
106 kPreParseSuccess | 53 kPreParseSuccess |
107 }; | 54 }; |
108 | 55 |
109 ~PreParser() { } | 56 ~PreParser() { } |
110 | 57 |
111 // Pre-parse the program from the character stream; returns true on | 58 // Pre-parse the program from the character stream; returns true on |
112 // success (even if parsing failed, the pre-parse data successfully | 59 // success (even if parsing failed, the pre-parse data successfully |
113 // captured the syntax error), and false if a stack-overflow happened | 60 // captured the syntax error), and false if a stack-overflow happened |
114 // during parsing. | 61 // during parsing. |
115 static PreParseResult PreParseProgram(i::JavaScriptScanner* scanner, | 62 static PreParseResult PreParseProgram(i::JavaScriptScanner* scanner, |
116 i::ParserRecorder* log, | 63 i::ParserRecorder* log, |
117 bool allow_lazy, | 64 bool allow_lazy, |
118 uintptr_t stack_limit) { | 65 uintptr_t stack_limit) { |
119 return PreParser(scanner, log, stack_limit, allow_lazy).PreParse(); | 66 return PreParser(scanner, log, stack_limit, allow_lazy).PreParse(); |
120 } | 67 } |
121 | 68 |
122 private: | 69 private: |
123 // Used to detect duplicates in object literals. Each of the values | |
124 // kGetterProperty, kSetterProperty and kValueProperty represents | |
125 // a type of object literal property. When parsing a property, its | |
126 // type value is stored in the DuplicateFinder for the property name. | |
127 // Values are chosen so that having intersection bits means the there is | |
128 // an incompatibility. | |
129 // I.e., you can add a getter to a property that already has a setter, since | |
130 // kGetterProperty and kSetterProperty doesn't intersect, but not if it | |
131 // already has a getter or a value. Adding the getter to an existing | |
132 // setter will store the value (kGetterProperty | kSetterProperty), which | |
133 // is incompatible with adding any further properties. | |
134 enum PropertyType { | |
135 kNone = 0, | |
136 // Bit patterns representing different object literal property types. | |
137 kGetterProperty = 1, | |
138 kSetterProperty = 2, | |
139 kValueProperty = 7, | |
140 // Helper constants. | |
141 kValueFlag = 4 | |
142 }; | |
143 | |
144 // Checks the type of conflict based on values coming from PropertyType. | |
145 bool HasConflict(int type1, int type2) { return (type1 & type2) != 0; } | |
146 bool IsDataDataConflict(int type1, int type2) { | |
147 return ((type1 & type2) & kValueFlag) != 0; | |
148 } | |
149 bool IsDataAccessorConflict(int type1, int type2) { | |
150 return ((type1 ^ type2) & kValueFlag) != 0; | |
151 } | |
152 bool IsAccessorAccessorConflict(int type1, int type2) { | |
153 return ((type1 | type2) & kValueFlag) == 0; | |
154 } | |
155 | |
156 | |
157 void CheckDuplicate(DuplicateFinder* finder, | |
158 i::Token::Value property, | |
159 int type, | |
160 bool* ok); | |
161 | |
162 // These types form an algebra over syntactic categories that is just | 70 // These types form an algebra over syntactic categories that is just |
163 // rich enough to let us recognize and propagate the constructs that | 71 // rich enough to let us recognize and propagate the constructs that |
164 // are either being counted in the preparser data, or is important | 72 // are either being counted in the preparser data, or is important |
165 // to throw the correct syntax error exceptions. | 73 // to throw the correct syntax error exceptions. |
166 | 74 |
167 enum ScopeType { | 75 enum ScopeType { |
168 kTopLevelScope, | 76 kTopLevelScope, |
169 kFunctionScope | 77 kFunctionScope |
170 }; | 78 }; |
171 | 79 |
(...skipping 277 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
449 if (!ok) { | 357 if (!ok) { |
450 ReportUnexpectedToken(scanner_->current_token()); | 358 ReportUnexpectedToken(scanner_->current_token()); |
451 } else if (scope_->is_strict()) { | 359 } else if (scope_->is_strict()) { |
452 CheckOctalLiteral(start_position, scanner_->location().end_pos, &ok); | 360 CheckOctalLiteral(start_position, scanner_->location().end_pos, &ok); |
453 } | 361 } |
454 return kPreParseSuccess; | 362 return kPreParseSuccess; |
455 } | 363 } |
456 | 364 |
457 // Report syntax error | 365 // Report syntax error |
458 void ReportUnexpectedToken(i::Token::Value token); | 366 void ReportUnexpectedToken(i::Token::Value token); |
459 void ReportMessageAt(i::Scanner::Location location, | |
460 const char* type, | |
461 const char* name_opt) { | |
462 log_->LogMessage(location.beg_pos, location.end_pos, type, name_opt); | |
463 } | |
464 void ReportMessageAt(int start_pos, | 367 void ReportMessageAt(int start_pos, |
465 int end_pos, | 368 int end_pos, |
466 const char* type, | 369 const char* type, |
467 const char* name_opt) { | 370 const char* name_opt) { |
468 log_->LogMessage(start_pos, end_pos, type, name_opt); | 371 log_->LogMessage(start_pos, end_pos, type, name_opt); |
469 } | 372 } |
470 | 373 |
471 void CheckOctalLiteral(int beg_pos, int end_pos, bool* ok); | 374 void CheckOctalLiteral(int beg_pos, int end_pos, bool* ok); |
472 | 375 |
473 // All ParseXXX functions take as the last argument an *ok parameter | 376 // All ParseXXX functions take as the last argument an *ok parameter |
(...skipping 116 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
590 uintptr_t stack_limit_; | 493 uintptr_t stack_limit_; |
591 i::Scanner::Location strict_mode_violation_location_; | 494 i::Scanner::Location strict_mode_violation_location_; |
592 const char* strict_mode_violation_type_; | 495 const char* strict_mode_violation_type_; |
593 bool stack_overflow_; | 496 bool stack_overflow_; |
594 bool allow_lazy_; | 497 bool allow_lazy_; |
595 bool parenthesized_function_; | 498 bool parenthesized_function_; |
596 }; | 499 }; |
597 } } // v8::preparser | 500 } } // v8::preparser |
598 | 501 |
599 #endif // V8_PREPARSER_H | 502 #endif // V8_PREPARSER_H |
OLD | NEW |