[Qt][Symbian] Remove support for WINSCW compiler
[WebKit-https.git] / Source / JavaScriptCore / runtime / Lookup.h
1 /*
2  *  Copyright (C) 1999-2000 Harri Porten (porten@kde.org)
3  *  Copyright (C) 2003, 2006, 2007, 2008, 2009 Apple Inc. All rights reserved.
4  *
5  *  This library is free software; you can redistribute it and/or
6  *  modify it under the terms of the GNU Lesser General Public
7  *  License as published by the Free Software Foundation; either
8  *  version 2 of the License, or (at your option) any later version.
9  *
10  *  This library is distributed in the hope that it will be useful,
11  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
12  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13  *  Lesser General Public License for more details.
14  *
15  *  You should have received a copy of the GNU Lesser General Public
16  *  License along with this library; if not, write to the Free Software
17  *  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
18  *
19  */
20
21 #ifndef Lookup_h
22 #define Lookup_h
23
24 #include "CallFrame.h"
25 #include "DFGIntrinsic.h"
26 #include "Identifier.h"
27 #include "JSGlobalObject.h"
28 #include "PropertySlot.h"
29 #include <stdio.h>
30 #include <wtf/Assertions.h>
31
32 namespace JSC {
33     // Hash table generated by the create_hash_table script.
34     struct HashTableValue {
35         const char* key; // property name
36         unsigned char attributes; // JSObject attributes
37         intptr_t value1;
38         intptr_t value2;
39 #if ENABLE(JIT)
40         ThunkGenerator generator;
41 #if ENABLE(DFG_JIT)
42         DFG::Intrinsic intrinsic;
43 #endif
44 #endif
45     };
46
47     // FIXME: There is no reason this get function can't be simpler.
48     // ie. typedef JSValue (*GetFunction)(ExecState*, JSObject* baseObject)
49     typedef PropertySlot::GetValueFunc GetFunction;
50     typedef void (*PutFunction)(ExecState*, JSObject* baseObject, JSValue value);
51
52     class HashEntry {
53         WTF_MAKE_FAST_ALLOCATED;
54     public:
55         void initialize(StringImpl* key, unsigned char attributes, intptr_t v1, intptr_t v2
56 #if ENABLE(JIT)
57                         , ThunkGenerator generator = 0
58 #if ENABLE(DFG_JIT)
59                         , DFG::Intrinsic intrinsic = DFG::NoIntrinsic
60 #endif
61 #endif
62                         )
63         {
64             m_key = key;
65             m_attributes = attributes;
66             m_u.store.value1 = v1;
67             m_u.store.value2 = v2;
68 #if ENABLE(JIT)
69             m_u.function.generator = generator;
70 #if ENABLE(DFG_JIT)
71             m_u.function.intrinsic = intrinsic;
72 #endif
73 #endif
74             m_next = 0;
75         }
76
77         void setKey(StringImpl* key) { m_key = key; }
78         StringImpl* key() const { return m_key; }
79
80         unsigned char attributes() const { return m_attributes; }
81
82 #if ENABLE(JIT)
83         ThunkGenerator generator() const { ASSERT(m_attributes & Function); return m_u.function.generator; }
84         DFG::Intrinsic intrinsic() const
85         {
86             ASSERT(m_attributes & Function);
87 #if ENABLE(DFG_JIT)
88             return m_u.function.intrinsic;
89 #else
90             return DFG::NoIntrinsic;
91 #endif
92         }
93 #endif
94         NativeFunction function() const { ASSERT(m_attributes & Function); return m_u.function.functionValue; }
95         unsigned char functionLength() const { ASSERT(m_attributes & Function); return static_cast<unsigned char>(m_u.function.length); }
96
97         GetFunction propertyGetter() const { ASSERT(!(m_attributes & Function)); return m_u.property.get; }
98         PutFunction propertyPutter() const { ASSERT(!(m_attributes & Function)); return m_u.property.put; }
99
100         intptr_t lexerValue() const { ASSERT(!m_attributes); return m_u.lexer.value; }
101
102         void setNext(HashEntry *next) { m_next = next; }
103         HashEntry* next() const { return m_next; }
104
105     private:
106         StringImpl* m_key;
107         unsigned char m_attributes; // JSObject attributes
108
109         union {
110             struct {
111                 intptr_t value1;
112                 intptr_t value2;
113             } store;
114             struct {
115                 NativeFunction functionValue;
116                 intptr_t length; // number of arguments for function
117 #if ENABLE(JIT)
118                 ThunkGenerator generator;
119 #if ENABLE(DFG_JIT)
120                 DFG::Intrinsic intrinsic;
121 #endif
122 #endif
123             } function;
124             struct {
125                 GetFunction get;
126                 PutFunction put;
127             } property;
128             struct {
129                 intptr_t value;
130                 intptr_t unused;
131             } lexer;
132         } m_u;
133
134         HashEntry* m_next;
135     };
136
137     struct HashTable {
138
139         int compactSize;
140         int compactHashSizeMask;
141
142         const HashTableValue* values; // Fixed values generated by script.
143         mutable const HashEntry* table; // Table allocated at runtime.
144
145         ALWAYS_INLINE void initializeIfNeeded(JSGlobalData* globalData) const
146         {
147             if (!table)
148                 createTable(globalData);
149         }
150
151         ALWAYS_INLINE void initializeIfNeeded(ExecState* exec) const
152         {
153             if (!table)
154                 createTable(&exec->globalData());
155         }
156
157         void deleteTable() const;
158
159         // Find an entry in the table, and return the entry.
160         ALWAYS_INLINE const HashEntry* entry(JSGlobalData* globalData, const Identifier& identifier) const
161         {
162             initializeIfNeeded(globalData);
163             return entry(identifier);
164         }
165
166         ALWAYS_INLINE const HashEntry* entry(ExecState* exec, const Identifier& identifier) const
167         {
168             initializeIfNeeded(exec);
169             return entry(identifier);
170         }
171
172         class ConstIterator {
173         public:
174             ConstIterator(const HashTable* table, int position)
175                 : m_table(table)
176                 , m_position(position)
177             {
178                 skipInvalidKeys();
179             }
180
181             const HashEntry* operator->()
182             {
183                 return &m_table->table[m_position];
184             }
185
186             const HashEntry* operator*()
187             {
188                 return &m_table->table[m_position];
189             }
190
191             bool operator!=(const ConstIterator& other)
192             {
193                 ASSERT(m_table == other.m_table);
194                 return m_position != other.m_position;
195             }
196             
197             ConstIterator& operator++()
198             {
199                 ASSERT(m_position < m_table->compactSize);
200                 ++m_position;
201                 skipInvalidKeys();
202                 return *this;
203             }
204
205         private:
206             void skipInvalidKeys()
207             {
208                 ASSERT(m_position <= m_table->compactSize);
209                 while (m_position < m_table->compactSize && !m_table->table[m_position].key())
210                     ++m_position;
211                 ASSERT(m_position <= m_table->compactSize);
212             }
213             
214             const HashTable* m_table;
215             int m_position;
216         };
217
218         ConstIterator begin(JSGlobalData& globalData) const
219         {
220             initializeIfNeeded(&globalData);
221             return ConstIterator(this, 0);
222         }
223         ConstIterator end(JSGlobalData& globalData) const
224         {
225             initializeIfNeeded(&globalData);
226             return ConstIterator(this, compactSize);
227         }
228
229     private:
230         ALWAYS_INLINE const HashEntry* entry(const Identifier& identifier) const
231         {
232             ASSERT(table);
233
234             const HashEntry* entry = &table[identifier.impl()->existingHash() & compactHashSizeMask];
235
236             if (!entry->key())
237                 return 0;
238
239             do {
240                 if (entry->key() == identifier.impl())
241                     return entry;
242                 entry = entry->next();
243             } while (entry);
244
245             return 0;
246         }
247
248         // Convert the hash table keys to identifiers.
249         void createTable(JSGlobalData*) const;
250     };
251
252     bool setUpStaticFunctionSlot(ExecState*, const HashEntry*, JSObject* thisObject, const Identifier& propertyName, PropertySlot&);
253
254     /**
255      * This method does it all (looking in the hashtable, checking for function
256      * overrides, creating the function or retrieving from cache, calling
257      * getValueProperty in case of a non-function property, forwarding to parent if
258      * unknown property).
259      */
260     template <class ThisImp, class ParentImp>
261     inline bool getStaticPropertySlot(ExecState* exec, const HashTable* table, ThisImp* thisObj, const Identifier& propertyName, PropertySlot& slot)
262     {
263         const HashEntry* entry = table->entry(exec, propertyName);
264
265         if (!entry) // not found, forward to parent
266             return ParentImp::getOwnPropertySlot(thisObj, exec, propertyName, slot);
267
268         if (entry->attributes() & Function)
269             return setUpStaticFunctionSlot(exec, entry, thisObj, propertyName, slot);
270
271         slot.setCacheableCustom(thisObj, entry->propertyGetter());
272         return true;
273     }
274
275     template <class ThisImp, class ParentImp>
276     inline bool getStaticPropertyDescriptor(ExecState* exec, const HashTable* table, ThisImp* thisObj, const Identifier& propertyName, PropertyDescriptor& descriptor)
277     {
278         const HashEntry* entry = table->entry(exec, propertyName);
279         
280         if (!entry) // not found, forward to parent
281             return ParentImp::getOwnPropertyDescriptor(thisObj, exec, propertyName, descriptor);
282  
283         PropertySlot slot;
284         if (entry->attributes() & Function) {
285             bool present = setUpStaticFunctionSlot(exec, entry, thisObj, propertyName, slot);
286             if (present)
287                 descriptor.setDescriptor(slot.getValue(exec, propertyName), entry->attributes());
288             return present;
289         }
290
291         slot.setCustom(thisObj, entry->propertyGetter());
292         descriptor.setDescriptor(slot.getValue(exec, propertyName), entry->attributes());
293         return true;
294     }
295
296     /**
297      * Simplified version of getStaticPropertySlot in case there are only functions.
298      * Using this instead of getStaticPropertySlot allows 'this' to avoid implementing
299      * a dummy getValueProperty.
300      */
301     template <class ParentImp>
302     inline bool getStaticFunctionSlot(ExecState* exec, const HashTable* table, JSObject* thisObj, const Identifier& propertyName, PropertySlot& slot)
303     {
304         if (ParentImp::getOwnPropertySlot(thisObj, exec, propertyName, slot))
305             return true;
306
307         const HashEntry* entry = table->entry(exec, propertyName);
308         if (!entry)
309             return false;
310
311         return setUpStaticFunctionSlot(exec, entry, thisObj, propertyName, slot);
312     }
313     
314     /**
315      * Simplified version of getStaticPropertyDescriptor in case there are only functions.
316      * Using this instead of getStaticPropertyDescriptor allows 'this' to avoid implementing
317      * a dummy getValueProperty.
318      */
319     template <class ParentImp>
320     inline bool getStaticFunctionDescriptor(ExecState* exec, const HashTable* table, JSObject* thisObj, const Identifier& propertyName, PropertyDescriptor& descriptor)
321     {
322         if (ParentImp::getOwnPropertyDescriptor(static_cast<ParentImp*>(thisObj), exec, propertyName, descriptor))
323             return true;
324         
325         const HashEntry* entry = table->entry(exec, propertyName);
326         if (!entry)
327             return false;
328         
329         PropertySlot slot;
330         bool present = setUpStaticFunctionSlot(exec, entry, thisObj, propertyName, slot);
331         if (present)
332             descriptor.setDescriptor(slot.getValue(exec, propertyName), entry->attributes());
333         return present;
334     }
335
336     /**
337      * Simplified version of getStaticPropertySlot in case there are no functions, only "values".
338      * Using this instead of getStaticPropertySlot removes the need for a FuncImp class.
339      */
340     template <class ThisImp, class ParentImp>
341     inline bool getStaticValueSlot(ExecState* exec, const HashTable* table, ThisImp* thisObj, const Identifier& propertyName, PropertySlot& slot)
342     {
343         const HashEntry* entry = table->entry(exec, propertyName);
344
345         if (!entry) // not found, forward to parent
346             return ParentImp::getOwnPropertySlot(thisObj, exec, propertyName, slot);
347
348         ASSERT(!(entry->attributes() & Function));
349
350         slot.setCacheableCustom(thisObj, entry->propertyGetter());
351         return true;
352     }
353
354     /**
355      * Simplified version of getStaticPropertyDescriptor in case there are no functions, only "values".
356      * Using this instead of getStaticPropertyDescriptor removes the need for a FuncImp class.
357      */
358     template <class ThisImp, class ParentImp>
359     inline bool getStaticValueDescriptor(ExecState* exec, const HashTable* table, ThisImp* thisObj, const Identifier& propertyName, PropertyDescriptor& descriptor)
360     {
361         const HashEntry* entry = table->entry(exec, propertyName);
362         
363         if (!entry) // not found, forward to parent
364             return ParentImp::getOwnPropertyDescriptor(thisObj, exec, propertyName, descriptor);
365         
366         ASSERT(!(entry->attributes() & Function));
367         PropertySlot slot;
368         slot.setCustom(thisObj, entry->propertyGetter());
369         descriptor.setDescriptor(slot.getValue(exec, propertyName), entry->attributes());
370         return true;
371     }
372
373     /**
374      * This one is for "put".
375      * It looks up a hash entry for the property to be set.  If an entry
376      * is found it sets the value and returns true, else it returns false.
377      */
378     template <class ThisImp>
379     inline bool lookupPut(ExecState* exec, const Identifier& propertyName, JSValue value, const HashTable* table, ThisImp* thisObj)
380     {
381         const HashEntry* entry = table->entry(exec, propertyName);
382
383         if (!entry)
384             return false;
385
386         // If this is a function put it as an override property.
387         if (entry->attributes() & Function)
388             thisObj->putDirect(exec->globalData(), propertyName, value);
389         else if (!(entry->attributes() & ReadOnly))
390             entry->propertyPutter()(exec, thisObj, value);
391
392         return true;
393     }
394
395     /**
396      * This one is for "put".
397      * It calls lookupPut<ThisImp>() to set the value.  If that call
398      * returns false (meaning no entry in the hash table was found),
399      * then it calls put() on the ParentImp class.
400      */
401     template <class ThisImp, class ParentImp>
402     inline void lookupPut(ExecState* exec, const Identifier& propertyName, JSValue value, const HashTable* table, ThisImp* thisObj, PutPropertySlot& slot)
403     {
404         if (!lookupPut<ThisImp>(exec, propertyName, value, table, thisObj))
405             ParentImp::put(thisObj, exec, propertyName, value, slot); // not found: forward to parent
406     }
407
408 } // namespace JSC
409
410 #endif // Lookup_h