source: webkit/trunk/JavaScriptCore/runtime/Lookup.h@ 57879

Last change on this file since 57879 was 55564, checked in by [email protected], 15 years ago

2010-03-03 Oliver Hunt <[email protected]>

Reviewed by Gavin Barraclough.

Allow static property getters to interact with JSCs caching
https://bugs.webkit.org/show_bug.cgi?id=35716

Add new opcodes for handling cached lookup of static value getters.
More or less the same as with JS getters, all that changes is that
instead of calling through a JSFunction we always know that we have
a C function to call.

For the patching routines in the JIT we now need to pass a few
new parameters to allow us to pass enough information to the stub
function to allow us to call the C function correctly. Logically
this shouldn't actually be necessary as all of these functions ignore
the identifier, but removing the ident parameter would require
somewhat involved changes to the way we implement getOwnPropertySlot,
etc.

  • bytecode/CodeBlock.cpp: (JSC::CodeBlock::dump): (JSC::CodeBlock::derefStructures): (JSC::CodeBlock::refStructures):
  • bytecode/Instruction.h: (JSC::Instruction::Instruction): (JSC::Instruction::):
  • bytecode/Opcode.h:
  • interpreter/Interpreter.cpp: (JSC::Interpreter::tryCacheGetByID): (JSC::Interpreter::privateExecute):
  • jit/JIT.cpp: (JSC::JIT::privateCompileMainPass):
  • jit/JIT.h: (JSC::JIT::compileGetByIdProto): (JSC::JIT::compileGetByIdSelfList): (JSC::JIT::compileGetByIdProtoList): (JSC::JIT::compileGetByIdChainList): (JSC::JIT::compileGetByIdChain):
  • jit/JITPropertyAccess.cpp: (JSC::JIT::privateCompileGetByIdProto): (JSC::JIT::privateCompileGetByIdSelfList): (JSC::JIT::privateCompileGetByIdProtoList): (JSC::JIT::privateCompileGetByIdChainList): (JSC::JIT::privateCompileGetByIdChain):
  • jit/JITPropertyAccess32_64.cpp: (JSC::JIT::privateCompileGetByIdProto): (JSC::JIT::privateCompileGetByIdSelfList): (JSC::JIT::privateCompileGetByIdProtoList): (JSC::JIT::privateCompileGetByIdChainList): (JSC::JIT::privateCompileGetByIdChain):
  • jit/JITStubs.cpp: (JSC::JITThunks::tryCacheGetByID): (JSC::DEFINE_STUB_FUNCTION):
  • jit/JITStubs.h: (JSC::):
  • runtime/JSFunction.cpp: (JSC::JSFunction::getOwnPropertySlot):
  • runtime/Lookup.h: (JSC::getStaticPropertySlot): (JSC::getStaticValueSlot):
  • runtime/PropertySlot.h: (JSC::PropertySlot::): (JSC::PropertySlot::PropertySlot): (JSC::PropertySlot::cachedPropertyType): (JSC::PropertySlot::isCacheable): (JSC::PropertySlot::isCacheableValue): (JSC::PropertySlot::setValueSlot): (JSC::PropertySlot::setCacheableCustom): (JSC::PropertySlot::setGetterSlot): (JSC::PropertySlot::setCacheableGetterSlot): (JSC::PropertySlot::clearOffset): (JSC::PropertySlot::customGetter):

2010-03-03 Oliver Hunt <[email protected]>

Reviewed by Gavin Barraclough.

Allow static property getters to interact with JSCs caching
https://bugs.webkit.org/show_bug.cgi?id=35716

Add tests to ensure nothing horrifying happens to static property
getters if they're in a path where we end up caching lookups.

  • fast/js/pic/cached-named-property-getter-expected.txt: Added.
  • fast/js/pic/cached-named-property-getter.html: Added.

2010-03-03 Oliver Hunt <[email protected]>

Reviewed by Gavin Barraclough.

Allow static property getters to interact with JSCs caching
https://bugs.webkit.org/show_bug.cgi?id=35716

Update the obviously safe getters to allow caching

Test: fast/js/pic/cached-named-property-getter.html

  • bridge/runtime_array.cpp: (JSC::RuntimeArray::getOwnPropertySlot):
  • bridge/runtime_method.cpp: (JSC::RuntimeMethod::getOwnPropertySlot):
  • Property svn:eol-style set to native
File size: 11.8 KB
Line 
1/*
2 * Copyright (C) 1999-2000 Harri Porten ([email protected])
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
39namespace 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 : public FastAllocBase {
55 public:
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
65 void setKey(UString::Rep* key) { m_key = key; }
66 UString::Rep* key() const { return m_key; }
67
68 unsigned char attributes() const { return m_attributes; }
69
70 NativeFunction function() const { ASSERT(m_attributes & Function); return m_u.function.functionValue; }
71 unsigned char functionLength() const { ASSERT(m_attributes & Function); return static_cast<unsigned char>(m_u.function.length); }
72
73 GetFunction propertyGetter() const { ASSERT(!(m_attributes & Function)); return m_u.property.get; }
74 PutFunction propertyPutter() const { ASSERT(!(m_attributes & Function)); return m_u.property.put; }
75
76 intptr_t lexerValue() const { ASSERT(!m_attributes); return m_u.lexer.value; }
77
78 void setNext(HashEntry *next) { m_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
115 ALWAYS_INLINE void initializeIfNeeded(JSGlobalData* globalData) const
116 {
117 if (!table)
118 createTable(globalData);
119 }
120
121 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.
130 ALWAYS_INLINE const HashEntry* entry(JSGlobalData* globalData, const Identifier& identifier) const
131 {
132 initializeIfNeeded(globalData);
133 return entry(identifier);
134 }
135
136 ALWAYS_INLINE const HashEntry* entry(ExecState* exec, const Identifier& identifier) const
137 {
138 initializeIfNeeded(exec);
139 return entry(identifier);
140 }
141
142 private:
143 ALWAYS_INLINE const HashEntry* entry(const Identifier& identifier) const
144 {
145 ASSERT(table);
146
147 const HashEntry* entry = &table[identifier.ustring().rep()->existingHash() & 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>
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.setCacheableCustom(thisObj, entry->propertyGetter());
185
186 return true;
187 }
188
189 template <class ThisImp, class ParentImp>
190 inline bool getStaticPropertyDescriptor(ExecState* exec, const HashTable* table, ThisImp* thisObj, const Identifier& propertyName, PropertyDescriptor& descriptor)
191 {
192 const HashEntry* entry = table->entry(exec, propertyName);
193
194 if (!entry) // not found, forward to parent
195 return thisObj->ParentImp::getOwnPropertyDescriptor(exec, propertyName, descriptor);
196
197 PropertySlot slot;
198 if (entry->attributes() & Function)
199 setUpStaticFunctionSlot(exec, entry, thisObj, propertyName, slot);
200 else
201 slot.setCustom(thisObj, entry->propertyGetter());
202
203 descriptor.setDescriptor(slot.getValue(exec, propertyName), entry->attributes());
204 return true;
205 }
206
207 /**
208 * Simplified version of getStaticPropertySlot in case there are only functions.
209 * Using this instead of getStaticPropertySlot allows 'this' to avoid implementing
210 * a dummy getValueProperty.
211 */
212 template <class ParentImp>
213 inline bool getStaticFunctionSlot(ExecState* exec, const HashTable* table, JSObject* thisObj, const Identifier& propertyName, PropertySlot& slot)
214 {
215 if (static_cast<ParentImp*>(thisObj)->ParentImp::getOwnPropertySlot(exec, propertyName, slot))
216 return true;
217
218 const HashEntry* entry = table->entry(exec, propertyName);
219 if (!entry)
220 return false;
221
222 setUpStaticFunctionSlot(exec, entry, thisObj, propertyName, slot);
223 return true;
224 }
225
226 /**
227 * Simplified version of getStaticPropertyDescriptor in case there are only functions.
228 * Using this instead of getStaticPropertyDescriptor allows 'this' to avoid implementing
229 * a dummy getValueProperty.
230 */
231 template <class ParentImp>
232 inline bool getStaticFunctionDescriptor(ExecState* exec, const HashTable* table, JSObject* thisObj, const Identifier& propertyName, PropertyDescriptor& descriptor)
233 {
234 if (static_cast<ParentImp*>(thisObj)->ParentImp::getOwnPropertyDescriptor(exec, propertyName, descriptor))
235 return true;
236
237 const HashEntry* entry = table->entry(exec, propertyName);
238 if (!entry)
239 return false;
240
241 PropertySlot slot;
242 setUpStaticFunctionSlot(exec, entry, thisObj, propertyName, slot);
243 descriptor.setDescriptor(slot.getValue(exec, propertyName), entry->attributes());
244 return true;
245 }
246
247 /**
248 * Simplified version of getStaticPropertySlot in case there are no functions, only "values".
249 * Using this instead of getStaticPropertySlot removes the need for a FuncImp class.
250 */
251 template <class ThisImp, class ParentImp>
252 inline bool getStaticValueSlot(ExecState* exec, const HashTable* table, ThisImp* thisObj, const Identifier& propertyName, PropertySlot& slot)
253 {
254 const HashEntry* entry = table->entry(exec, propertyName);
255
256 if (!entry) // not found, forward to parent
257 return thisObj->ParentImp::getOwnPropertySlot(exec, propertyName, slot);
258
259 ASSERT(!(entry->attributes() & Function));
260
261 slot.setCacheableCustom(thisObj, entry->propertyGetter());
262 return true;
263 }
264
265 /**
266 * Simplified version of getStaticPropertyDescriptor in case there are no functions, only "values".
267 * Using this instead of getStaticPropertyDescriptor removes the need for a FuncImp class.
268 */
269 template <class ThisImp, class ParentImp>
270 inline bool getStaticValueDescriptor(ExecState* exec, const HashTable* table, ThisImp* thisObj, const Identifier& propertyName, PropertyDescriptor& descriptor)
271 {
272 const HashEntry* entry = table->entry(exec, propertyName);
273
274 if (!entry) // not found, forward to parent
275 return thisObj->ParentImp::getOwnPropertyDescriptor(exec, propertyName, descriptor);
276
277 ASSERT(!(entry->attributes() & Function));
278 PropertySlot slot;
279 slot.setCustom(thisObj, entry->propertyGetter());
280 descriptor.setDescriptor(slot.getValue(exec, propertyName), entry->attributes());
281 return true;
282 }
283
284 /**
285 * This one is for "put".
286 * It looks up a hash entry for the property to be set. If an entry
287 * is found it sets the value and returns true, else it returns false.
288 */
289 template <class ThisImp>
290 inline bool lookupPut(ExecState* exec, const Identifier& propertyName, JSValue value, const HashTable* table, ThisImp* thisObj)
291 {
292 const HashEntry* entry = table->entry(exec, propertyName);
293
294 if (!entry)
295 return false;
296
297 if (entry->attributes() & Function) { // function: put as override property
298 if (LIKELY(value.isCell()))
299 thisObj->putDirectFunction(propertyName, value.asCell());
300 else
301 thisObj->putDirect(propertyName, value);
302 } else if (!(entry->attributes() & ReadOnly))
303 entry->propertyPutter()(exec, thisObj, value);
304
305 return true;
306 }
307
308 /**
309 * This one is for "put".
310 * It calls lookupPut<ThisImp>() to set the value. If that call
311 * returns false (meaning no entry in the hash table was found),
312 * then it calls put() on the ParentImp class.
313 */
314 template <class ThisImp, class ParentImp>
315 inline void lookupPut(ExecState* exec, const Identifier& propertyName, JSValue value, const HashTable* table, ThisImp* thisObj, PutPropertySlot& slot)
316 {
317 if (!lookupPut<ThisImp>(exec, propertyName, value, table, thisObj))
318 thisObj->ParentImp::put(exec, propertyName, value, slot); // not found: forward to parent
319 }
320
321} // namespace JSC
322
323#endif // Lookup_h
Note: See TracBrowser for help on using the repository browser.