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