1 // Copyright 2014 the V8 project authors. All rights reserved.
2 // Redistribution and use in source and binary forms, with or without
3 // modification, are permitted provided that the following conditions are
4 // met:
5 //
6 //     * Redistributions of source code must retain the above copyright
7 //       notice, this list of conditions and the following disclaimer.
8 //     * Redistributions in binary form must reproduce the above
9 //       copyright notice, this list of conditions and the following
10 //       disclaimer in the documentation and/or other materials provided
11 //       with the distribution.
12 //     * Neither the name of Google Inc. nor the names of its
13 //       contributors may be used to endorse or promote products derived
14 //       from this software without specific prior written permission.
15 //
16 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
17 // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
18 // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
19 // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
20 // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
21 // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
22 // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23 // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24 // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
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.
27 
28 #ifndef V8_AST_AST_VALUE_FACTORY_H_
29 #define V8_AST_AST_VALUE_FACTORY_H_
30 
31 #include <forward_list>
32 
33 #include "src/base/hashmap.h"
34 #include "src/base/logging.h"
35 #include "src/common/globals.h"
36 #include "src/heap/factory.h"
37 #include "src/numbers/conversions.h"
38 
39 // Ast(Raw|Cons)String and AstValueFactory are for storing strings and
40 // values independent of the V8 heap and internalizing them later. During
41 // parsing, they are created and stored outside the heap, in AstValueFactory.
42 // After parsing, the strings and values are internalized (moved into the V8
43 // heap).
44 namespace v8 {
45 namespace internal {
46 
47 class Isolate;
48 
49 class AstRawString final : public ZoneObject {
50  public:
51   static bool Equal(const AstRawString* lhs, const AstRawString* rhs);
52 
53   // Returns 0 if lhs is equal to rhs.
54   // Returns <0 if lhs is less than rhs in code point order.
55   // Returns >0 if lhs is greater than than rhs in code point order.
56   static int Compare(const AstRawString* lhs, const AstRawString* rhs);
57 
IsEmpty()58   bool IsEmpty() const { return literal_bytes_.length() == 0; }
length()59   int length() const {
60     return is_one_byte() ? literal_bytes_.length()
61                          : literal_bytes_.length() / 2;
62   }
63   bool AsArrayIndex(uint32_t* index) const;
64   bool IsIntegerIndex() const;
65   V8_EXPORT_PRIVATE bool IsOneByteEqualTo(const char* data) const;
66   uint16_t FirstCharacter() const;
67 
68   template <typename IsolateT>
69   void Internalize(IsolateT* isolate);
70 
71   // Access the physical representation:
is_one_byte()72   bool is_one_byte() const { return is_one_byte_; }
byte_length()73   int byte_length() const { return literal_bytes_.length(); }
raw_data()74   const unsigned char* raw_data() const { return literal_bytes_.begin(); }
75 
IsPrivateName()76   bool IsPrivateName() const { return length() > 0 && FirstCharacter() == '#'; }
77 
78   // For storing AstRawStrings in a hash map.
raw_hash_field()79   uint32_t raw_hash_field() const { return raw_hash_field_; }
Hash()80   uint32_t Hash() const {
81     // Hash field must be computed.
82     DCHECK_EQ(raw_hash_field_ & Name::kHashNotComputedMask, 0);
83     return raw_hash_field_ >> Name::kHashShift;
84   }
85 
86   // This function can be called after internalizing.
string()87   V8_INLINE Handle<String> string() const {
88     DCHECK(has_string_);
89     return string_;
90   }
91 
92  private:
93   friend class AstRawStringInternalizationKey;
94   friend class AstStringConstants;
95   friend class AstValueFactory;
96   friend Zone;
97 
98   // Members accessed only by the AstValueFactory & related classes:
AstRawString(bool is_one_byte,const base::Vector<const byte> & literal_bytes,uint32_t raw_hash_field)99   AstRawString(bool is_one_byte, const base::Vector<const byte>& literal_bytes,
100                uint32_t raw_hash_field)
101       : next_(nullptr),
102         literal_bytes_(literal_bytes),
103         raw_hash_field_(raw_hash_field),
104         is_one_byte_(is_one_byte) {}
next()105   AstRawString* next() {
106     DCHECK(!has_string_);
107     return next_;
108   }
next_location()109   AstRawString** next_location() {
110     DCHECK(!has_string_);
111     return &next_;
112   }
113 
set_string(Handle<String> string)114   void set_string(Handle<String> string) {
115     DCHECK(!string.is_null());
116     DCHECK(!has_string_);
117     string_ = string;
118 #ifdef DEBUG
119     has_string_ = true;
120 #endif
121   }
122 
123   union {
124     AstRawString* next_;
125     Handle<String> string_;
126   };
127 
128   base::Vector<const byte> literal_bytes_;  // Memory owned by Zone.
129   uint32_t raw_hash_field_;
130   bool is_one_byte_;
131 #ifdef DEBUG
132   // (Debug-only:) Verify the object life-cylce: Some functions may only be
133   // called after internalization (that is, after a v8::internal::String has
134   // been set); some only before.
135   bool has_string_ = false;
136 #endif
137 };
138 
139 extern template EXPORT_TEMPLATE_DECLARE(
140     V8_EXPORT_PRIVATE) void AstRawString::Internalize(Isolate* isolate);
141 extern template EXPORT_TEMPLATE_DECLARE(
142     V8_EXPORT_PRIVATE) void AstRawString::Internalize(LocalIsolate* isolate);
143 
144 class AstConsString final : public ZoneObject {
145  public:
AddString(Zone * zone,const AstRawString * s)146   AstConsString* AddString(Zone* zone, const AstRawString* s) {
147     if (s->IsEmpty()) return this;
148     if (!IsEmpty()) {
149       // We're putting the new string to the head of the list, meaning
150       // the string segments will be in reverse order.
151       Segment* tmp = zone->New<Segment>(segment_);
152       segment_.next = tmp;
153     }
154     segment_.string = s;
155     return this;
156   }
157 
IsEmpty()158   bool IsEmpty() const {
159     DCHECK_IMPLIES(segment_.string == nullptr, segment_.next == nullptr);
160     DCHECK_IMPLIES(segment_.string != nullptr, !segment_.string->IsEmpty());
161     return segment_.string == nullptr;
162   }
163 
164   template <typename IsolateT>
GetString(IsolateT * isolate)165   Handle<String> GetString(IsolateT* isolate) {
166     if (string_.is_null()) {
167       string_ = Allocate(isolate);
168     }
169     return string_;
170   }
171 
172   template <typename IsolateT>
173   EXPORT_TEMPLATE_DECLARE(V8_EXPORT_PRIVATE)
174   Handle<String> AllocateFlat(IsolateT* isolate) const;
175 
176   std::forward_list<const AstRawString*> ToRawStrings() const;
177 
178  private:
179   friend class AstValueFactory;
180   friend Zone;
181 
AstConsString()182   AstConsString() : string_(), segment_({nullptr, nullptr}) {}
183 
184   template <typename IsolateT>
185   EXPORT_TEMPLATE_DECLARE(V8_EXPORT_PRIVATE)
186   Handle<String> Allocate(IsolateT* isolate) const;
187 
188   Handle<String> string_;
189 
190   // A linked list of AstRawStrings of the contents of this AstConsString.
191   // This list has several properties:
192   //
193   //   * For empty strings the string pointer is null,
194   //   * Appended raw strings are added to the head of the list, so they are in
195   //     reverse order
196   struct Segment {
197     const AstRawString* string;
198     AstConsString::Segment* next;
199   };
200   Segment segment_;
201 };
202 
203 class AstBigInt {
204  public:
205   // |bigint| must be a NUL-terminated string of ASCII characters
206   // representing a BigInt (suitable for passing to BigIntLiteral()
207   // from conversions.h).
AstBigInt(const char * bigint)208   explicit AstBigInt(const char* bigint) : bigint_(bigint) {}
209 
c_str()210   const char* c_str() const { return bigint_; }
211 
212  private:
213   const char* bigint_;
214 };
215 
216 struct AstRawStringMapMatcher {
operatorAstRawStringMapMatcher217   bool operator()(uint32_t hash1, uint32_t hash2,
218                   const AstRawString* lookup_key,
219                   const AstRawString* entry_key) const {
220     return hash1 == hash2 && AstRawString::Equal(lookup_key, entry_key);
221   }
222 };
223 
224 using AstRawStringMap =
225     base::TemplateHashMapImpl<const AstRawString*, base::NoHashMapValue,
226                               AstRawStringMapMatcher,
227                               base::DefaultAllocationPolicy>;
228 
229 // For generating constants.
230 #define AST_STRING_CONSTANTS(F)                    \
231   F(anonymous, "anonymous")                        \
232   F(anonymous_function, "(anonymous function)")    \
233   F(arguments, "arguments")                        \
234   F(as, "as")                                      \
235   F(assert, "assert")                              \
236   F(async, "async")                                \
237   F(await, "await")                                \
238   F(bigint, "bigint")                              \
239   F(boolean, "boolean")                            \
240   F(computed, "<computed>")                        \
241   F(dot_brand, ".brand")                           \
242   F(constructor, "constructor")                    \
243   F(default, "default")                            \
244   F(done, "done")                                  \
245   F(dot, ".")                                      \
246   F(dot_default, ".default")                       \
247   F(dot_for, ".for")                               \
248   F(dot_generator_object, ".generator_object")     \
249   F(dot_home_object, ".home_object")               \
250   F(dot_result, ".result")                         \
251   F(dot_repl_result, ".repl_result")               \
252   F(dot_static_home_object, ".static_home_object") \
253   F(dot_switch_tag, ".switch_tag")                 \
254   F(dot_catch, ".catch")                           \
255   F(empty, "")                                     \
256   F(eval, "eval")                                  \
257   F(from, "from")                                  \
258   F(function, "function")                          \
259   F(get, "get")                                    \
260   F(get_space, "get ")                             \
261   F(length, "length")                              \
262   F(let, "let")                                    \
263   F(meta, "meta")                                  \
264   F(name, "name")                                  \
265   F(native, "native")                              \
266   F(new_target, ".new.target")                     \
267   F(next, "next")                                  \
268   F(number, "number")                              \
269   F(object, "object")                              \
270   F(of, "of")                                      \
271   F(private_constructor, "#constructor")           \
272   F(proto, "__proto__")                            \
273   F(prototype, "prototype")                        \
274   F(return, "return")                              \
275   F(set, "set")                                    \
276   F(set_space, "set ")                             \
277   F(string, "string")                              \
278   F(symbol, "symbol")                              \
279   F(target, "target")                              \
280   F(this, "this")                                  \
281   F(this_function, ".this_function")               \
282   F(throw, "throw")                                \
283   F(undefined, "undefined")                        \
284   F(value, "value")
285 
286 class AstStringConstants final {
287  public:
288   AstStringConstants(Isolate* isolate, uint64_t hash_seed);
289   AstStringConstants(const AstStringConstants&) = delete;
290   AstStringConstants& operator=(const AstStringConstants&) = delete;
291 
292 #define F(name, str) \
293   const AstRawString* name##_string() const { return name##_string_; }
AST_STRING_CONSTANTS(F)294   AST_STRING_CONSTANTS(F)
295 #undef F
296 
297   uint64_t hash_seed() const { return hash_seed_; }
string_table()298   const AstRawStringMap* string_table() const { return &string_table_; }
299 
300  private:
301   Zone zone_;
302   AstRawStringMap string_table_;
303   uint64_t hash_seed_;
304 
305 #define F(name, str) AstRawString* name##_string_;
306   AST_STRING_CONSTANTS(F)
307 #undef F
308 };
309 
310 class AstValueFactory {
311  public:
AstValueFactory(Zone * zone,const AstStringConstants * string_constants,uint64_t hash_seed)312   AstValueFactory(Zone* zone, const AstStringConstants* string_constants,
313                   uint64_t hash_seed)
314       : string_table_(string_constants->string_table()),
315         strings_(nullptr),
316         strings_end_(&strings_),
317         string_constants_(string_constants),
318         empty_cons_string_(nullptr),
319         zone_(zone),
320         hash_seed_(hash_seed) {
321     DCHECK_NOT_NULL(zone_);
322     DCHECK_EQ(hash_seed, string_constants->hash_seed());
323     std::fill(one_character_strings_,
324               one_character_strings_ + arraysize(one_character_strings_),
325               nullptr);
326     empty_cons_string_ = NewConsString();
327   }
328 
zone()329   Zone* zone() const {
330     DCHECK_NOT_NULL(zone_);
331     return zone_;
332   }
333 
GetOneByteString(base::Vector<const uint8_t> literal)334   const AstRawString* GetOneByteString(base::Vector<const uint8_t> literal) {
335     return GetOneByteStringInternal(literal);
336   }
GetOneByteString(const char * string)337   const AstRawString* GetOneByteString(const char* string) {
338     return GetOneByteString(base::OneByteVector(string));
339   }
GetTwoByteString(base::Vector<const uint16_t> literal)340   const AstRawString* GetTwoByteString(base::Vector<const uint16_t> literal) {
341     return GetTwoByteStringInternal(literal);
342   }
343   const AstRawString* GetString(Handle<String> literal);
344 
345   // Clones an AstRawString from another ast value factory, adding it to this
346   // factory and returning the clone.
347   const AstRawString* CloneFromOtherFactory(const AstRawString* raw_string);
348 
349   V8_EXPORT_PRIVATE AstConsString* NewConsString();
350   V8_EXPORT_PRIVATE AstConsString* NewConsString(const AstRawString* str);
351   V8_EXPORT_PRIVATE AstConsString* NewConsString(const AstRawString* str1,
352                                                  const AstRawString* str2);
353 
354   // Internalize all the strings in the factory, and prevent any more from being
355   // allocated. Multiple calls to Internalize are allowed, for simplicity, where
356   // subsequent calls are a no-op.
357   template <typename IsolateT>
358   void Internalize(IsolateT* isolate);
359 
360 #define F(name, str)                           \
361   const AstRawString* name##_string() const {  \
362     return string_constants_->name##_string(); \
363   }
AST_STRING_CONSTANTS(F)364   AST_STRING_CONSTANTS(F)
365 #undef F
366   AstConsString* empty_cons_string() const { return empty_cons_string_; }
367 
368  private:
AddString(AstRawString * string)369   AstRawString* AddString(AstRawString* string) {
370     *strings_end_ = string;
371     strings_end_ = string->next_location();
372     return string;
373   }
ResetStrings()374   void ResetStrings() {
375     strings_ = nullptr;
376     strings_end_ = &strings_;
377   }
378   V8_EXPORT_PRIVATE const AstRawString* GetOneByteStringInternal(
379       base::Vector<const uint8_t> literal);
380   const AstRawString* GetTwoByteStringInternal(
381       base::Vector<const uint16_t> literal);
382   const AstRawString* GetString(uint32_t raw_hash_field, bool is_one_byte,
383                                 base::Vector<const byte> literal_bytes);
384 
385   // All strings are copied here.
386   AstRawStringMap string_table_;
387 
388   AstRawString* strings_;
389   AstRawString** strings_end_;
390 
391   // Holds constant string values which are shared across the isolate.
392   const AstStringConstants* string_constants_;
393 
394   AstConsString* empty_cons_string_;
395 
396   // Caches one character lowercase strings (for minified code).
397   static const int kMaxOneCharStringValue = 128;
398   const AstRawString* one_character_strings_[kMaxOneCharStringValue];
399 
400   Zone* zone_;
401 
402   uint64_t hash_seed_;
403 };
404 
405 extern template EXPORT_TEMPLATE_DECLARE(
406     V8_EXPORT_PRIVATE) void AstValueFactory::Internalize<Isolate>(Isolate*
407                                                                       isolate);
408 
409 extern template EXPORT_TEMPLATE_DECLARE(
410     V8_EXPORT_PRIVATE) void AstValueFactory::
411     Internalize<LocalIsolate>(LocalIsolate* isolate);
412 
413 }  // namespace internal
414 }  // namespace v8
415 
416 #endif  // V8_AST_AST_VALUE_FACTORY_H_
417