]> git.saurik.com Git - apple/javascriptcore.git/blame - runtime/Lookup.h
JavaScriptCore-7600.1.4.16.1.tar.gz
[apple/javascriptcore.git] / runtime / Lookup.h
CommitLineData
9dae56ea
A
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
81345200 24#include "BatchedTransitionOptimizer.h"
9dae56ea 25#include "CallFrame.h"
81345200 26#include "CustomGetterSetter.h"
9dae56ea 27#include "Identifier.h"
81345200
A
28#include "IdentifierInlines.h"
29#include "Intrinsic.h"
9dae56ea 30#include "JSGlobalObject.h"
9dae56ea 31#include "PropertySlot.h"
81345200 32#include "PutPropertySlot.h"
9dae56ea
A
33#include <wtf/Assertions.h>
34
9dae56ea 35namespace JSC {
81345200
A
36 struct CompactHashIndex {
37 const int16_t value;
38 const int16_t next;
9dae56ea
A
39 };
40
41 // FIXME: There is no reason this get function can't be simpler.
ba379fdc 42 // ie. typedef JSValue (*GetFunction)(ExecState*, JSObject* baseObject)
9dae56ea 43 typedef PropertySlot::GetValueFunc GetFunction;
81345200
A
44 typedef PutPropertySlot::PutValueFunc PutFunction;
45 typedef FunctionExecutable* (*BuiltinGenerator)(VM&);
9dae56ea 46
81345200
A
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;
6fe7ccc8 54
81345200 55 unsigned attributes() const { return m_attributes; }
9dae56ea 56
81345200
A
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); }
9dae56ea 61
81345200
A
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); }
9dae56ea 64
81345200 65 intptr_t constantInteger() const { ASSERT(m_attributes & ConstantInteger); return m_value1; }
9dae56ea 66
81345200 67 intptr_t lexerValue() const { ASSERT(!m_attributes); return m_value1; }
9dae56ea
A
68 };
69
70 struct HashTable {
81345200
A
71 mutable int numberOfValues;
72 int indexMask;
73 bool hasSetterOrReadonlyProperties;
ba379fdc 74
9dae56ea 75 const HashTableValue* values; // Fixed values generated by script.
81345200
A
76 mutable const char** keys; // Table allocated at runtime.
77 const CompactHashIndex* index;
9dae56ea 78
93a37866
A
79 ALWAYS_INLINE HashTable copy() const
80 {
81 // Don't copy dynamic table since it's thread specific.
81345200 82 HashTable result = { numberOfValues, indexMask, hasSetterOrReadonlyProperties, values, 0, index };
93a37866
A
83 return result;
84 }
85
81345200 86 ALWAYS_INLINE void initializeIfNeeded(VM& vm) const
9dae56ea 87 {
81345200 88 if (!keys)
93a37866 89 createTable(vm);
9dae56ea
A
90 }
91
92 ALWAYS_INLINE void initializeIfNeeded(ExecState* exec) const
93 {
81345200
A
94 if (!keys)
95 createTable(exec->vm());
9dae56ea
A
96 }
97
6fe7ccc8 98 JS_EXPORT_PRIVATE void deleteTable() const;
9dae56ea
A
99
100 // Find an entry in the table, and return the entry.
81345200 101 ALWAYS_INLINE const HashTableValue* entry(VM& vm, PropertyName identifier) const
9dae56ea 102 {
93a37866 103 initializeIfNeeded(vm);
9dae56ea
A
104 return entry(identifier);
105 }
106
81345200 107 ALWAYS_INLINE const HashTableValue* entry(ExecState* exec, PropertyName identifier) const
9dae56ea
A
108 {
109 initializeIfNeeded(exec);
110 return entry(identifier);
111 }
112
6fe7ccc8
A
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
81345200 122 const HashTableValue* value()
6fe7ccc8 123 {
81345200 124 return &m_table->values[m_position];
6fe7ccc8
A
125 }
126
81345200 127 const char* key()
6fe7ccc8 128 {
81345200
A
129 return m_table->keys[m_position];
130 }
131
132 const HashTableValue* operator->()
133 {
134 return value();
6fe7ccc8
A
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 {
81345200 145 ASSERT(m_position < m_table->numberOfValues);
6fe7ccc8
A
146 ++m_position;
147 skipInvalidKeys();
148 return *this;
149 }
150
151 private:
152 void skipInvalidKeys()
153 {
81345200
A
154 ASSERT(m_position <= m_table->numberOfValues);
155 while (m_position < m_table->numberOfValues && !m_table->keys[m_position])
6fe7ccc8 156 ++m_position;
81345200 157 ASSERT(m_position <= m_table->numberOfValues);
6fe7ccc8
A
158 }
159
160 const HashTable* m_table;
161 int m_position;
162 };
163
93a37866 164 ConstIterator begin(VM& vm) const
6fe7ccc8 165 {
81345200 166 initializeIfNeeded(vm);
6fe7ccc8
A
167 return ConstIterator(this, 0);
168 }
93a37866 169 ConstIterator end(VM& vm) const
6fe7ccc8 170 {
81345200
A
171 initializeIfNeeded(vm);
172 return ConstIterator(this, numberOfValues);
6fe7ccc8
A
173 }
174
9dae56ea 175 private:
81345200 176 ALWAYS_INLINE const HashTableValue* entry(PropertyName propertyName) const
9dae56ea 177 {
81345200 178 StringImpl* impl = propertyName.uid();
93a37866
A
179 if (!impl)
180 return 0;
181
81345200 182 ASSERT(keys);
9dae56ea 183
81345200
A
184 int indexEntry = impl->existingHash() & indexMask;
185 int valueIndex = index[indexEntry].value;
186 if (valueIndex == -1)
9dae56ea
A
187 return 0;
188
81345200
A
189 while (true) {
190 if (WTF::equal(impl, keys[valueIndex]))
191 return &values[valueIndex];
9dae56ea 192
81345200
A
193 indexEntry = index[indexEntry].next;
194 if (indexEntry == -1)
195 return nullptr;
196 valueIndex = index[indexEntry].value;
197 ASSERT(valueIndex != -1);
198 };
9dae56ea
A
199 }
200
201 // Convert the hash table keys to identifiers.
81345200 202 JS_EXPORT_PRIVATE void createTable(VM&) const;
9dae56ea
A
203 };
204
81345200 205 JS_EXPORT_PRIVATE bool setUpStaticFunctionSlot(ExecState*, const HashTableValue*, JSObject* thisObject, PropertyName, PropertySlot&);
9dae56ea
A
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>
81345200 214 inline bool getStaticPropertySlot(ExecState* exec, const HashTable& table, ThisImp* thisObj, PropertyName propertyName, PropertySlot& slot)
9dae56ea 215 {
81345200 216 const HashTableValue* entry = table.entry(exec, propertyName);
9dae56ea
A
217
218 if (!entry) // not found, forward to parent
6fe7ccc8 219 return ParentImp::getOwnPropertySlot(thisObj, exec, propertyName, slot);
9dae56ea 220
81345200 221 if (entry->attributes() & BuiltinOrFunction)
6fe7ccc8 222 return setUpStaticFunctionSlot(exec, entry, thisObj, propertyName, slot);
9dae56ea 223
81345200
A
224 if (entry->attributes() & ConstantInteger) {
225 slot.setValue(thisObj, entry->attributes(), jsNumber(entry->constantInteger()));
226 return true;
6fe7ccc8 227 }
81345200
A
228
229 slot.setCacheableCustom(thisObj, entry->attributes(), entry->propertyGetter());
f9bf01c6
A
230 return true;
231 }
232
9dae56ea
A
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>
81345200 239 inline bool getStaticFunctionSlot(ExecState* exec, const HashTable& table, JSObject* thisObj, PropertyName propertyName, PropertySlot& slot)
9dae56ea 240 {
6fe7ccc8 241 if (ParentImp::getOwnPropertySlot(thisObj, exec, propertyName, slot))
9dae56ea
A
242 return true;
243
81345200 244 const HashTableValue* entry = table.entry(exec, propertyName);
9dae56ea
A
245 if (!entry)
246 return false;
247
6fe7ccc8 248 return setUpStaticFunctionSlot(exec, entry, thisObj, propertyName, slot);
9dae56ea
A
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>
81345200 256 inline bool getStaticValueSlot(ExecState* exec, const HashTable& table, ThisImp* thisObj, PropertyName propertyName, PropertySlot& slot)
9dae56ea 257 {
81345200 258 const HashTableValue* entry = table.entry(exec, propertyName);
9dae56ea
A
259
260 if (!entry) // not found, forward to parent
6fe7ccc8 261 return ParentImp::getOwnPropertySlot(thisObj, exec, propertyName, slot);
9dae56ea 262
81345200 263 ASSERT(!(entry->attributes() & BuiltinOrFunction));
9dae56ea 264
81345200
A
265 if (entry->attributes() & ConstantInteger) {
266 slot.setValue(thisObj, entry->attributes(), jsNumber(entry->constantInteger()));
267 return true;
268 }
9dae56ea 269
81345200 270 slot.setCacheableCustom(thisObj, entry->attributes(), entry->propertyGetter());
f9bf01c6
A
271 return true;
272 }
273
81345200 274 inline void putEntry(ExecState* exec, const HashTableValue* entry, JSObject* base, PropertyName propertyName, JSValue value, PutPropertySlot& slot)
93a37866
A
275 {
276 // If this is a function put it as an override property.
81345200
A
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())
93a37866
A
284 throwTypeError(exec, StrictModeReadonlyPropertyWriteError);
285 }
286
9dae56ea
A
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 */
81345200 292 inline bool lookupPut(ExecState* exec, PropertyName propertyName, JSObject* base, JSValue value, const HashTable& table, PutPropertySlot& slot)
9dae56ea 293 {
81345200
A
294 const HashTableValue* entry = table.entry(exec, propertyName);
295
9dae56ea
A
296 if (!entry)
297 return false;
298
81345200 299 putEntry(exec, entry, base, propertyName, value, slot);
9dae56ea
A
300 return true;
301 }
302
81345200
A
303 template<unsigned numberOfValues>
304 inline void reifyStaticProperties(VM& vm, const HashTableValue (&values)[numberOfValues], JSObject& thisObj)
9dae56ea 305 {
81345200
A
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 }
9dae56ea
A
336 }
337
338} // namespace JSC
339
340#endif // Lookup_h