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