Lookup.h 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401
  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. #ifndef Lookup_h
  21. #define Lookup_h
  22. #include "CallFrame.h"
  23. #include "Intrinsic.h"
  24. #include "Identifier.h"
  25. #include "JSGlobalObject.h"
  26. #include "PropertySlot.h"
  27. #include <stdio.h>
  28. #include <wtf/Assertions.h>
  29. namespace JSC {
  30. // Hash table generated by the create_hash_table script.
  31. struct HashTableValue {
  32. const char* key; // property name
  33. unsigned char attributes; // JSObject attributes
  34. intptr_t value1;
  35. intptr_t value2;
  36. Intrinsic intrinsic;
  37. };
  38. // FIXME: There is no reason this get function can't be simpler.
  39. // ie. typedef JSValue (*GetFunction)(ExecState*, JSObject* baseObject)
  40. typedef PropertySlot::GetValueFunc GetFunction;
  41. typedef void (*PutFunction)(ExecState*, JSObject* baseObject, JSValue value);
  42. class HashEntry {
  43. WTF_MAKE_FAST_ALLOCATED;
  44. public:
  45. void initialize(StringImpl* key, unsigned char attributes, intptr_t v1, intptr_t v2, Intrinsic intrinsic)
  46. {
  47. m_key = key;
  48. m_attributes = attributes;
  49. m_u.store.value1 = v1;
  50. m_u.store.value2 = v2;
  51. m_intrinsic = intrinsic;
  52. m_next = 0;
  53. }
  54. void setKey(StringImpl* key) { m_key = key; }
  55. StringImpl* key() const { return m_key; }
  56. unsigned char attributes() const { return m_attributes; }
  57. Intrinsic intrinsic() const
  58. {
  59. ASSERT(m_attributes & Function);
  60. return m_intrinsic;
  61. }
  62. NativeFunction function() const { ASSERT(m_attributes & Function); return m_u.function.functionValue; }
  63. unsigned char functionLength() const { ASSERT(m_attributes & Function); return static_cast<unsigned char>(m_u.function.length); }
  64. GetFunction propertyGetter() const { ASSERT(!(m_attributes & Function)); return m_u.property.get; }
  65. PutFunction propertyPutter() const { ASSERT(!(m_attributes & Function)); return m_u.property.put; }
  66. intptr_t lexerValue() const { ASSERT(!m_attributes); return m_u.lexer.value; }
  67. void setNext(HashEntry *next) { m_next = next; }
  68. HashEntry* next() const { return m_next; }
  69. private:
  70. StringImpl* m_key;
  71. unsigned char m_attributes; // JSObject attributes
  72. Intrinsic m_intrinsic;
  73. union {
  74. struct {
  75. intptr_t value1;
  76. intptr_t value2;
  77. } store;
  78. struct {
  79. NativeFunction functionValue;
  80. intptr_t length; // number of arguments for function
  81. } function;
  82. struct {
  83. GetFunction get;
  84. PutFunction put;
  85. } property;
  86. struct {
  87. intptr_t value;
  88. intptr_t unused;
  89. } lexer;
  90. } m_u;
  91. HashEntry* m_next;
  92. };
  93. struct HashTable {
  94. int compactSize;
  95. int compactHashSizeMask;
  96. const HashTableValue* values; // Fixed values generated by script.
  97. mutable const HashEntry* table; // Table allocated at runtime.
  98. ALWAYS_INLINE HashTable copy() const
  99. {
  100. // Don't copy dynamic table since it's thread specific.
  101. HashTable result = { compactSize, compactHashSizeMask, values, 0 };
  102. return result;
  103. }
  104. ALWAYS_INLINE void initializeIfNeeded(VM* vm) const
  105. {
  106. if (!table)
  107. createTable(vm);
  108. }
  109. ALWAYS_INLINE void initializeIfNeeded(ExecState* exec) const
  110. {
  111. if (!table)
  112. createTable(&exec->vm());
  113. }
  114. JS_EXPORT_PRIVATE void deleteTable() const;
  115. // Find an entry in the table, and return the entry.
  116. ALWAYS_INLINE const HashEntry* entry(VM* vm, PropertyName identifier) const
  117. {
  118. initializeIfNeeded(vm);
  119. return entry(identifier);
  120. }
  121. ALWAYS_INLINE const HashEntry* entry(ExecState* exec, PropertyName identifier) const
  122. {
  123. initializeIfNeeded(exec);
  124. return entry(identifier);
  125. }
  126. class ConstIterator {
  127. public:
  128. ConstIterator(const HashTable* table, int position)
  129. : m_table(table)
  130. , m_position(position)
  131. {
  132. skipInvalidKeys();
  133. }
  134. const HashEntry* operator->()
  135. {
  136. return &m_table->table[m_position];
  137. }
  138. const HashEntry* operator*()
  139. {
  140. return &m_table->table[m_position];
  141. }
  142. bool operator!=(const ConstIterator& other)
  143. {
  144. ASSERT(m_table == other.m_table);
  145. return m_position != other.m_position;
  146. }
  147. ConstIterator& operator++()
  148. {
  149. ASSERT(m_position < m_table->compactSize);
  150. ++m_position;
  151. skipInvalidKeys();
  152. return *this;
  153. }
  154. private:
  155. void skipInvalidKeys()
  156. {
  157. ASSERT(m_position <= m_table->compactSize);
  158. while (m_position < m_table->compactSize && !m_table->table[m_position].key())
  159. ++m_position;
  160. ASSERT(m_position <= m_table->compactSize);
  161. }
  162. const HashTable* m_table;
  163. int m_position;
  164. };
  165. ConstIterator begin(VM& vm) const
  166. {
  167. initializeIfNeeded(&vm);
  168. return ConstIterator(this, 0);
  169. }
  170. ConstIterator end(VM& vm) const
  171. {
  172. initializeIfNeeded(&vm);
  173. return ConstIterator(this, compactSize);
  174. }
  175. private:
  176. ALWAYS_INLINE const HashEntry* entry(PropertyName propertyName) const
  177. {
  178. StringImpl* impl = propertyName.publicName();
  179. if (!impl)
  180. return 0;
  181. ASSERT(table);
  182. const HashEntry* entry = &table[impl->existingHash() & compactHashSizeMask];
  183. if (!entry->key())
  184. return 0;
  185. do {
  186. if (entry->key() == impl)
  187. return entry;
  188. entry = entry->next();
  189. } while (entry);
  190. return 0;
  191. }
  192. // Convert the hash table keys to identifiers.
  193. JS_EXPORT_PRIVATE void createTable(VM*) const;
  194. };
  195. JS_EXPORT_PRIVATE bool setUpStaticFunctionSlot(ExecState*, const HashEntry*, JSObject* thisObject, PropertyName, PropertySlot&);
  196. /**
  197. * This method does it all (looking in the hashtable, checking for function
  198. * overrides, creating the function or retrieving from cache, calling
  199. * getValueProperty in case of a non-function property, forwarding to parent if
  200. * unknown property).
  201. */
  202. template <class ThisImp, class ParentImp>
  203. inline bool getStaticPropertySlot(ExecState* exec, const HashTable* table, ThisImp* thisObj, PropertyName propertyName, PropertySlot& slot)
  204. {
  205. const HashEntry* entry = table->entry(exec, propertyName);
  206. if (!entry) // not found, forward to parent
  207. return ParentImp::getOwnPropertySlot(thisObj, exec, propertyName, slot);
  208. if (entry->attributes() & Function)
  209. return setUpStaticFunctionSlot(exec, entry, thisObj, propertyName, slot);
  210. slot.setCacheableCustom(thisObj, entry->propertyGetter());
  211. return true;
  212. }
  213. template <class ThisImp, class ParentImp>
  214. inline bool getStaticPropertyDescriptor(ExecState* exec, const HashTable* table, ThisImp* thisObj, PropertyName propertyName, PropertyDescriptor& descriptor)
  215. {
  216. const HashEntry* entry = table->entry(exec, propertyName);
  217. if (!entry) // not found, forward to parent
  218. return ParentImp::getOwnPropertyDescriptor(thisObj, exec, propertyName, descriptor);
  219. PropertySlot slot;
  220. if (entry->attributes() & Function) {
  221. bool present = setUpStaticFunctionSlot(exec, entry, thisObj, propertyName, slot);
  222. if (present)
  223. descriptor.setDescriptor(slot.getValue(exec, propertyName), entry->attributes());
  224. return present;
  225. }
  226. slot.setCustom(thisObj, entry->propertyGetter());
  227. descriptor.setDescriptor(slot.getValue(exec, propertyName), entry->attributes());
  228. return true;
  229. }
  230. /**
  231. * Simplified version of getStaticPropertySlot in case there are only functions.
  232. * Using this instead of getStaticPropertySlot allows 'this' to avoid implementing
  233. * a dummy getValueProperty.
  234. */
  235. template <class ParentImp>
  236. inline bool getStaticFunctionSlot(ExecState* exec, const HashTable* table, JSObject* thisObj, PropertyName propertyName, PropertySlot& slot)
  237. {
  238. if (ParentImp::getOwnPropertySlot(thisObj, exec, propertyName, slot))
  239. return true;
  240. const HashEntry* entry = table->entry(exec, propertyName);
  241. if (!entry)
  242. return false;
  243. return setUpStaticFunctionSlot(exec, entry, thisObj, propertyName, slot);
  244. }
  245. /**
  246. * Simplified version of getStaticPropertyDescriptor in case there are only functions.
  247. * Using this instead of getStaticPropertyDescriptor allows 'this' to avoid implementing
  248. * a dummy getValueProperty.
  249. */
  250. template <class ParentImp>
  251. inline bool getStaticFunctionDescriptor(ExecState* exec, const HashTable* table, JSObject* thisObj, PropertyName propertyName, PropertyDescriptor& descriptor)
  252. {
  253. if (ParentImp::getOwnPropertyDescriptor(static_cast<ParentImp*>(thisObj), exec, propertyName, descriptor))
  254. return true;
  255. const HashEntry* entry = table->entry(exec, propertyName);
  256. if (!entry)
  257. return false;
  258. PropertySlot slot;
  259. bool present = setUpStaticFunctionSlot(exec, entry, thisObj, propertyName, slot);
  260. if (present)
  261. descriptor.setDescriptor(slot.getValue(exec, propertyName), entry->attributes());
  262. return present;
  263. }
  264. /**
  265. * Simplified version of getStaticPropertySlot in case there are no functions, only "values".
  266. * Using this instead of getStaticPropertySlot removes the need for a FuncImp class.
  267. */
  268. template <class ThisImp, class ParentImp>
  269. inline bool getStaticValueSlot(ExecState* exec, const HashTable* table, ThisImp* thisObj, PropertyName propertyName, PropertySlot& slot)
  270. {
  271. const HashEntry* entry = table->entry(exec, propertyName);
  272. if (!entry) // not found, forward to parent
  273. return ParentImp::getOwnPropertySlot(thisObj, exec, propertyName, slot);
  274. ASSERT(!(entry->attributes() & Function));
  275. slot.setCacheableCustom(thisObj, entry->propertyGetter());
  276. return true;
  277. }
  278. /**
  279. * Simplified version of getStaticPropertyDescriptor in case there are no functions, only "values".
  280. * Using this instead of getStaticPropertyDescriptor removes the need for a FuncImp class.
  281. */
  282. template <class ThisImp, class ParentImp>
  283. inline bool getStaticValueDescriptor(ExecState* exec, const HashTable* table, ThisImp* thisObj, PropertyName propertyName, PropertyDescriptor& descriptor)
  284. {
  285. const HashEntry* entry = table->entry(exec, propertyName);
  286. if (!entry) // not found, forward to parent
  287. return ParentImp::getOwnPropertyDescriptor(thisObj, exec, propertyName, descriptor);
  288. ASSERT(!(entry->attributes() & Function));
  289. PropertySlot slot;
  290. slot.setCustom(thisObj, entry->propertyGetter());
  291. descriptor.setDescriptor(slot.getValue(exec, propertyName), entry->attributes());
  292. return true;
  293. }
  294. template <class ThisImp>
  295. inline void putEntry(ExecState* exec, const HashEntry* entry, PropertyName propertyName, JSValue value, ThisImp* thisObj, bool shouldThrow = false)
  296. {
  297. // If this is a function put it as an override property.
  298. if (entry->attributes() & Function)
  299. thisObj->putDirect(exec->vm(), propertyName, value);
  300. else if (!(entry->attributes() & ReadOnly))
  301. entry->propertyPutter()(exec, thisObj, value);
  302. else if (shouldThrow)
  303. throwTypeError(exec, StrictModeReadonlyPropertyWriteError);
  304. }
  305. /**
  306. * This one is for "put".
  307. * It looks up a hash entry for the property to be set. If an entry
  308. * is found it sets the value and returns true, else it returns false.
  309. */
  310. template <class ThisImp>
  311. inline bool lookupPut(ExecState* exec, PropertyName propertyName, JSValue value, const HashTable* table, ThisImp* thisObj, bool shouldThrow = false)
  312. {
  313. const HashEntry* entry = table->entry(exec, propertyName);
  314. if (!entry)
  315. return false;
  316. putEntry<ThisImp>(exec, entry, propertyName, value, thisObj, shouldThrow);
  317. return true;
  318. }
  319. /**
  320. * This one is for "put".
  321. * It calls lookupPut<ThisImp>() to set the value. If that call
  322. * returns false (meaning no entry in the hash table was found),
  323. * then it calls put() on the ParentImp class.
  324. */
  325. template <class ThisImp, class ParentImp>
  326. inline void lookupPut(ExecState* exec, PropertyName propertyName, JSValue value, const HashTable* table, ThisImp* thisObj, PutPropertySlot& slot)
  327. {
  328. if (!lookupPut<ThisImp>(exec, propertyName, value, table, thisObj, slot.isStrictMode()))
  329. ParentImp::put(thisObj, exec, propertyName, value, slot); // not found: forward to parent
  330. }
  331. } // namespace JSC
  332. #endif // Lookup_h