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 "Identifier.h" 26 #include "JSGlobalObject.h" 27 #include "JSObject.h" 28 #include "PropertySlot.h" 29 #include <stdio.h> 30 #include <wtf/Assertions.h> 31 32 // Bug #26843: Work around Metrowerks compiler bug 33 #if COMPILER(WINSCW) 34 #define JSC_CONST_HASHTABLE 35 #else 36 #define JSC_CONST_HASHTABLE const 37 #endif 38 39 namespace JSC { 40 41 // Hash table generated by the create_hash_table script. 42 struct HashTableValue { 43 const char* key; // property name 44 unsigned char attributes; // JSObject attributes 45 intptr_t value1; 46 intptr_t value2; 47 }; 48 49 // FIXME: There is no reason this get function can't be simpler. 50 // ie. typedef JSValue (*GetFunction)(ExecState*, JSObject* baseObject) 51 typedef PropertySlot::GetValueFunc GetFunction; 52 typedef void (*PutFunction)(ExecState*, JSObject* baseObject, JSValue value); 53 54 class HashEntry { 55 public: initialize(UString::Rep * key,unsigned char attributes,intptr_t v1,intptr_t v2)56 void initialize(UString::Rep* key, unsigned char attributes, intptr_t v1, intptr_t v2) 57 { 58 m_key = key; 59 m_attributes = attributes; 60 m_u.store.value1 = v1; 61 m_u.store.value2 = v2; 62 m_next = 0; 63 } 64 setKey(UString::Rep * key)65 void setKey(UString::Rep* key) { m_key = key; } key()66 UString::Rep* key() const { return m_key; } 67 attributes()68 unsigned char attributes() const { return m_attributes; } 69 function()70 NativeFunction function() const { ASSERT(m_attributes & Function); return m_u.function.functionValue; } functionLength()71 unsigned char functionLength() const { ASSERT(m_attributes & Function); return static_cast<unsigned char>(m_u.function.length); } 72 propertyGetter()73 GetFunction propertyGetter() const { ASSERT(!(m_attributes & Function)); return m_u.property.get; } propertyPutter()74 PutFunction propertyPutter() const { ASSERT(!(m_attributes & Function)); return m_u.property.put; } 75 lexerValue()76 intptr_t lexerValue() const { ASSERT(!m_attributes); return m_u.lexer.value; } 77 setNext(HashEntry * next)78 void setNext(HashEntry *next) { m_next = next; } next()79 HashEntry* next() const { return m_next; } 80 81 private: 82 UString::Rep* m_key; 83 unsigned char m_attributes; // JSObject attributes 84 85 union { 86 struct { 87 intptr_t value1; 88 intptr_t value2; 89 } store; 90 struct { 91 NativeFunction functionValue; 92 intptr_t length; // number of arguments for function 93 } function; 94 struct { 95 GetFunction get; 96 PutFunction put; 97 } property; 98 struct { 99 intptr_t value; 100 intptr_t unused; 101 } lexer; 102 } m_u; 103 104 HashEntry* m_next; 105 }; 106 107 struct HashTable { 108 109 int compactSize; 110 int compactHashSizeMask; 111 112 const HashTableValue* values; // Fixed values generated by script. 113 mutable const HashEntry* table; // Table allocated at runtime. 114 initializeIfNeededHashTable115 ALWAYS_INLINE void initializeIfNeeded(JSGlobalData* globalData) const 116 { 117 if (!table) 118 createTable(globalData); 119 } 120 initializeIfNeededHashTable121 ALWAYS_INLINE void initializeIfNeeded(ExecState* exec) const 122 { 123 if (!table) 124 createTable(&exec->globalData()); 125 } 126 127 void deleteTable() const; 128 129 // Find an entry in the table, and return the entry. entryHashTable130 ALWAYS_INLINE const HashEntry* entry(JSGlobalData* globalData, const Identifier& identifier) const 131 { 132 initializeIfNeeded(globalData); 133 return entry(identifier); 134 } 135 entryHashTable136 ALWAYS_INLINE const HashEntry* entry(ExecState* exec, const Identifier& identifier) const 137 { 138 initializeIfNeeded(exec); 139 return entry(identifier); 140 } 141 142 private: entryHashTable143 ALWAYS_INLINE const HashEntry* entry(const Identifier& identifier) const 144 { 145 ASSERT(table); 146 147 const HashEntry* entry = &table[identifier.ustring().rep()->computedHash() & compactHashSizeMask]; 148 149 if (!entry->key()) 150 return 0; 151 152 do { 153 if (entry->key() == identifier.ustring().rep()) 154 return entry; 155 entry = entry->next(); 156 } while (entry); 157 158 return 0; 159 } 160 161 // Convert the hash table keys to identifiers. 162 void createTable(JSGlobalData*) const; 163 }; 164 165 void setUpStaticFunctionSlot(ExecState*, const HashEntry*, JSObject* thisObject, const Identifier& propertyName, PropertySlot&); 166 167 /** 168 * This method does it all (looking in the hashtable, checking for function 169 * overrides, creating the function or retrieving from cache, calling 170 * getValueProperty in case of a non-function property, forwarding to parent if 171 * unknown property). 172 */ 173 template <class ThisImp, class ParentImp> getStaticPropertySlot(ExecState * exec,const HashTable * table,ThisImp * thisObj,const Identifier & propertyName,PropertySlot & slot)174 inline bool getStaticPropertySlot(ExecState* exec, const HashTable* table, ThisImp* thisObj, const Identifier& propertyName, PropertySlot& slot) 175 { 176 const HashEntry* entry = table->entry(exec, propertyName); 177 178 if (!entry) // not found, forward to parent 179 return thisObj->ParentImp::getOwnPropertySlot(exec, propertyName, slot); 180 181 if (entry->attributes() & Function) 182 setUpStaticFunctionSlot(exec, entry, thisObj, propertyName, slot); 183 else 184 slot.setCustom(thisObj, entry->propertyGetter()); 185 186 return true; 187 } 188 189 /** 190 * Simplified version of getStaticPropertySlot in case there are only functions. 191 * Using this instead of getStaticPropertySlot allows 'this' to avoid implementing 192 * a dummy getValueProperty. 193 */ 194 template <class ParentImp> getStaticFunctionSlot(ExecState * exec,const HashTable * table,JSObject * thisObj,const Identifier & propertyName,PropertySlot & slot)195 inline bool getStaticFunctionSlot(ExecState* exec, const HashTable* table, JSObject* thisObj, const Identifier& propertyName, PropertySlot& slot) 196 { 197 if (static_cast<ParentImp*>(thisObj)->ParentImp::getOwnPropertySlot(exec, propertyName, slot)) 198 return true; 199 200 const HashEntry* entry = table->entry(exec, propertyName); 201 if (!entry) 202 return false; 203 204 setUpStaticFunctionSlot(exec, entry, thisObj, propertyName, slot); 205 return true; 206 } 207 208 /** 209 * Simplified version of getStaticPropertySlot in case there are no functions, only "values". 210 * Using this instead of getStaticPropertySlot removes the need for a FuncImp class. 211 */ 212 template <class ThisImp, class ParentImp> getStaticValueSlot(ExecState * exec,const HashTable * table,ThisImp * thisObj,const Identifier & propertyName,PropertySlot & slot)213 inline bool getStaticValueSlot(ExecState* exec, const HashTable* table, ThisImp* thisObj, const Identifier& propertyName, PropertySlot& slot) 214 { 215 const HashEntry* entry = table->entry(exec, propertyName); 216 217 if (!entry) // not found, forward to parent 218 return thisObj->ParentImp::getOwnPropertySlot(exec, propertyName, slot); 219 220 ASSERT(!(entry->attributes() & Function)); 221 222 slot.setCustom(thisObj, entry->propertyGetter()); 223 return true; 224 } 225 226 /** 227 * This one is for "put". 228 * It looks up a hash entry for the property to be set. If an entry 229 * is found it sets the value and returns true, else it returns false. 230 */ 231 template <class ThisImp> lookupPut(ExecState * exec,const Identifier & propertyName,JSValue value,const HashTable * table,ThisImp * thisObj)232 inline bool lookupPut(ExecState* exec, const Identifier& propertyName, JSValue value, const HashTable* table, ThisImp* thisObj) 233 { 234 const HashEntry* entry = table->entry(exec, propertyName); 235 236 if (!entry) 237 return false; 238 239 if (entry->attributes() & Function) { // function: put as override property 240 if (LIKELY(value.isCell())) 241 thisObj->putDirectFunction(propertyName, value.asCell()); 242 else 243 thisObj->putDirect(propertyName, value); 244 } else if (!(entry->attributes() & ReadOnly)) 245 entry->propertyPutter()(exec, thisObj, value); 246 247 return true; 248 } 249 250 /** 251 * This one is for "put". 252 * It calls lookupPut<ThisImp>() to set the value. If that call 253 * returns false (meaning no entry in the hash table was found), 254 * then it calls put() on the ParentImp class. 255 */ 256 template <class ThisImp, class ParentImp> lookupPut(ExecState * exec,const Identifier & propertyName,JSValue value,const HashTable * table,ThisImp * thisObj,PutPropertySlot & slot)257 inline void lookupPut(ExecState* exec, const Identifier& propertyName, JSValue value, const HashTable* table, ThisImp* thisObj, PutPropertySlot& slot) 258 { 259 if (!lookupPut<ThisImp>(exec, propertyName, value, table, thisObj)) 260 thisObj->ParentImp::put(exec, propertyName, value, slot); // not found: forward to parent 261 } 262 263 } // namespace JSC 264 265 #endif // Lookup_h 266