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 "src/api.h"
32 #include "src/hashmap.h"
33 #include "src/utils.h"
34 
35 // AstString, AstValue and AstValueFactory are for storing strings and values
36 // independent of the V8 heap and internalizing them later. During parsing,
37 // AstStrings and AstValues are created and stored outside the heap, in
38 // AstValueFactory. After parsing, the strings and values are internalized
39 // (moved into the V8 heap).
40 namespace v8 {
41 namespace internal {
42 
43 class AstString : public ZoneObject {
44  public:
~AstString()45   virtual ~AstString() {}
46 
47   virtual int length() const = 0;
IsEmpty()48   bool IsEmpty() const { return length() == 0; }
49 
50   // Puts the string into the V8 heap.
51   virtual void Internalize(Isolate* isolate) = 0;
52 
53   // This function can be called after internalizing.
string()54   V8_INLINE Handle<String> string() const {
55     DCHECK(!string_.is_null());
56     return string_;
57   }
58 
59  protected:
60   // This is null until the string is internalized.
61   Handle<String> string_;
62 };
63 
64 
65 class AstRawString final : public AstString {
66  public:
length()67   int length() const override {
68     if (is_one_byte_)
69       return literal_bytes_.length();
70     return literal_bytes_.length() / 2;
71   }
72 
byte_length()73   int byte_length() const { return literal_bytes_.length(); }
74 
75   void Internalize(Isolate* isolate) override;
76 
77   bool AsArrayIndex(uint32_t* index) const;
78 
79   // The string is not null-terminated, use length() to find out the length.
raw_data()80   const unsigned char* raw_data() const {
81     return literal_bytes_.start();
82   }
is_one_byte()83   bool is_one_byte() const { return is_one_byte_; }
84   bool IsOneByteEqualTo(const char* data) const;
FirstCharacter()85   uint16_t FirstCharacter() const {
86     if (is_one_byte_)
87       return literal_bytes_[0];
88     const uint16_t* c =
89         reinterpret_cast<const uint16_t*>(literal_bytes_.start());
90     return *c;
91   }
92 
93   // For storing AstRawStrings in a hash map.
hash()94   uint32_t hash() const {
95     return hash_;
96   }
97 
98  private:
99   friend class AstValueFactory;
100   friend class AstRawStringInternalizationKey;
101 
AstRawString(bool is_one_byte,const Vector<const byte> & literal_bytes,uint32_t hash)102   AstRawString(bool is_one_byte, const Vector<const byte>& literal_bytes,
103             uint32_t hash)
104       : is_one_byte_(is_one_byte), literal_bytes_(literal_bytes), hash_(hash) {}
105 
AstRawString()106   AstRawString()
107       : is_one_byte_(true),
108         hash_(0) {}
109 
110   bool is_one_byte_;
111 
112   // Points to memory owned by Zone.
113   Vector<const byte> literal_bytes_;
114   uint32_t hash_;
115 };
116 
117 
118 class AstConsString final : public AstString {
119  public:
AstConsString(const AstString * left,const AstString * right)120   AstConsString(const AstString* left, const AstString* right)
121       : length_(left->length() + right->length()), left_(left), right_(right) {}
122 
length()123   int length() const override { return length_; }
124 
125   void Internalize(Isolate* isolate) override;
126 
127  private:
128   const int length_;
129   const AstString* left_;
130   const AstString* right_;
131 };
132 
133 
134 // AstValue is either a string, a number, a string array, a boolean, or a
135 // special value (null, undefined, the hole).
136 class AstValue : public ZoneObject {
137  public:
IsString()138   bool IsString() const {
139     return type_ == STRING;
140   }
141 
IsNumber()142   bool IsNumber() const {
143     return type_ == NUMBER || type_ == NUMBER_WITH_DOT || type_ == SMI;
144   }
145 
ContainsDot()146   bool ContainsDot() const { return type_ == NUMBER_WITH_DOT; }
147 
AsString()148   const AstRawString* AsString() const {
149     if (type_ == STRING)
150       return string_;
151     UNREACHABLE();
152     return 0;
153   }
154 
AsNumber()155   double AsNumber() const {
156     if (type_ == NUMBER || type_ == NUMBER_WITH_DOT)
157       return number_;
158     if (type_ == SMI)
159       return smi_;
160     UNREACHABLE();
161     return 0;
162   }
163 
EqualsString(const AstRawString * string)164   bool EqualsString(const AstRawString* string) const {
165     return type_ == STRING && string_ == string;
166   }
167 
168   bool IsPropertyName() const;
169 
170   bool BooleanValue() const;
171 
IsTheHole()172   bool IsTheHole() const { return type_ == THE_HOLE; }
173 
174   void Internalize(Isolate* isolate);
175 
176   // Can be called after Internalize has been called.
value()177   V8_INLINE Handle<Object> value() const {
178     if (type_ == STRING) {
179       return string_->string();
180     }
181     DCHECK(!value_.is_null());
182     return value_;
183   }
184 
185  private:
186   friend class AstValueFactory;
187 
188   enum Type {
189     STRING,
190     SYMBOL,
191     NUMBER,
192     NUMBER_WITH_DOT,
193     SMI,
194     BOOLEAN,
195     NULL_TYPE,
196     UNDEFINED,
197     THE_HOLE
198   };
199 
AstValue(const AstRawString * s)200   explicit AstValue(const AstRawString* s) : type_(STRING) { string_ = s; }
201 
AstValue(const char * name)202   explicit AstValue(const char* name) : type_(SYMBOL) { symbol_name_ = name; }
203 
AstValue(double n,bool with_dot)204   explicit AstValue(double n, bool with_dot) {
205     if (with_dot) {
206       type_ = NUMBER_WITH_DOT;
207     } else {
208       type_ = NUMBER;
209     }
210     number_ = n;
211   }
212 
AstValue(Type t,int i)213   AstValue(Type t, int i) : type_(t) {
214     DCHECK(type_ == SMI);
215     smi_ = i;
216   }
217 
AstValue(bool b)218   explicit AstValue(bool b) : type_(BOOLEAN) { bool_ = b; }
219 
AstValue(Type t)220   explicit AstValue(Type t) : type_(t) {
221     DCHECK(t == NULL_TYPE || t == UNDEFINED || t == THE_HOLE);
222   }
223 
224   Type type_;
225 
226   // Uninternalized value.
227   union {
228     const AstRawString* string_;
229     double number_;
230     int smi_;
231     bool bool_;
232     ZoneList<const AstRawString*>* strings_;
233     const char* symbol_name_;
234   };
235 
236   // Internalized value (empty before internalized).
237   Handle<Object> value_;
238 };
239 
240 
241 // For generating constants.
242 #define STRING_CONSTANTS(F)                     \
243   F(anonymous_function, "(anonymous function)") \
244   F(arguments, "arguments")                     \
245   F(constructor, "constructor")                 \
246   F(default, "default")                         \
247   F(done, "done")                               \
248   F(dot, ".")                                   \
249   F(dot_for, ".for")                            \
250   F(dot_generator, ".generator")                \
251   F(dot_generator_object, ".generator_object")  \
252   F(dot_iterator, ".iterator")                  \
253   F(dot_result, ".result")                      \
254   F(dot_switch_tag, ".switch_tag")              \
255   F(dot_catch, ".catch")                        \
256   F(empty, "")                                  \
257   F(eval, "eval")                               \
258   F(get_space, "get ")                          \
259   F(let, "let")                                 \
260   F(native, "native")                           \
261   F(new_target, ".new.target")                  \
262   F(next, "next")                               \
263   F(proto, "__proto__")                         \
264   F(prototype, "prototype")                     \
265   F(rest_parameter, ".rest_parameter")          \
266   F(set_space, "set ")                          \
267   F(this, "this")                               \
268   F(this_function, ".this_function")            \
269   F(undefined, "undefined")                     \
270   F(use_asm, "use asm")                         \
271   F(use_strong, "use strong")                   \
272   F(use_strict, "use strict")                   \
273   F(value, "value")
274 
275 #define OTHER_CONSTANTS(F) \
276   F(true_value)            \
277   F(false_value)           \
278   F(null_value)            \
279   F(undefined_value)       \
280   F(the_hole_value)
281 
282 class AstValueFactory {
283  public:
AstValueFactory(Zone * zone,uint32_t hash_seed)284   AstValueFactory(Zone* zone, uint32_t hash_seed)
285       : string_table_(AstRawStringCompare),
286         zone_(zone),
287         isolate_(NULL),
288         hash_seed_(hash_seed) {
289 #define F(name, str) name##_string_ = NULL;
290     STRING_CONSTANTS(F)
291 #undef F
292 #define F(name) name##_ = NULL;
293     OTHER_CONSTANTS(F)
294 #undef F
295   }
296 
zone()297   Zone* zone() const { return zone_; }
298 
GetOneByteString(Vector<const uint8_t> literal)299   const AstRawString* GetOneByteString(Vector<const uint8_t> literal) {
300     return GetOneByteStringInternal(literal);
301   }
GetOneByteString(const char * string)302   const AstRawString* GetOneByteString(const char* string) {
303     return GetOneByteString(Vector<const uint8_t>(
304         reinterpret_cast<const uint8_t*>(string), StrLength(string)));
305   }
GetTwoByteString(Vector<const uint16_t> literal)306   const AstRawString* GetTwoByteString(Vector<const uint16_t> literal) {
307     return GetTwoByteStringInternal(literal);
308   }
309   const AstRawString* GetString(Handle<String> literal);
310   const AstConsString* NewConsString(const AstString* left,
311                                      const AstString* right);
312 
313   void Internalize(Isolate* isolate);
IsInternalized()314   bool IsInternalized() {
315     return isolate_ != NULL;
316   }
317 
318 #define F(name, str)                                                    \
319   const AstRawString* name##_string() {                                 \
320     if (name##_string_ == NULL) {                                       \
321       const char* data = str;                                           \
322       name##_string_ = GetOneByteString(                                \
323           Vector<const uint8_t>(reinterpret_cast<const uint8_t*>(data), \
324                                 static_cast<int>(strlen(data))));       \
325     }                                                                   \
326     return name##_string_;                                              \
327   }
328   STRING_CONSTANTS(F)
329 #undef F
330 
331   const AstValue* NewString(const AstRawString* string);
332   // A JavaScript symbol (ECMA-262 edition 6).
333   const AstValue* NewSymbol(const char* name);
334   const AstValue* NewNumber(double number, bool with_dot = false);
335   const AstValue* NewSmi(int number);
336   const AstValue* NewBoolean(bool b);
337   const AstValue* NewStringList(ZoneList<const AstRawString*>* strings);
338   const AstValue* NewNull();
339   const AstValue* NewUndefined();
340   const AstValue* NewTheHole();
341 
342  private:
343   AstRawString* GetOneByteStringInternal(Vector<const uint8_t> literal);
344   AstRawString* GetTwoByteStringInternal(Vector<const uint16_t> literal);
345   AstRawString* GetString(uint32_t hash, bool is_one_byte,
346                           Vector<const byte> literal_bytes);
347 
348   static bool AstRawStringCompare(void* a, void* b);
349 
350   // All strings are copied here, one after another (no NULLs inbetween).
351   HashMap string_table_;
352   // For keeping track of all AstValues and AstRawStrings we've created (so that
353   // they can be internalized later).
354   List<AstValue*> values_;
355   List<AstString*> strings_;
356   Zone* zone_;
357   Isolate* isolate_;
358 
359   uint32_t hash_seed_;
360 
361 #define F(name, str) const AstRawString* name##_string_;
362   STRING_CONSTANTS(F)
363 #undef F
364 
365 #define F(name) AstValue* name##_;
366   OTHER_CONSTANTS(F)
367 #undef F
368 };
369 }  // namespace internal
370 }  // namespace v8
371 
372 #undef STRING_CONSTANTS
373 #undef OTHER_CONSTANTS
374 
375 #endif  // V8_AST_AST_VALUE_FACTORY_H_
376