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

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

2010-04-26 Oliver Hunt <[email protected]>

Reviewed by Gavin Barraclough.

Need to support more efficient dispatch of lightweight builtins
https://bugs.webkit.org/show_bug.cgi?id=38155

The problem with calling lightweight builtins is that marshalling
the call from the nitro calling convention to the system calling
convention is very expensive relative to the cost of the actually
evaluating the function. To work around this problem this patch
adds the ability to define a custom thunk for a builtin.

This allows us to use high performance custom implementations of
the common and sensible versions of simple builtins. This patch
includes a simple (use of which is currently hardcoded) thunk for
charCodeAt.

This adds a JSInterfaceJIT subclass called SpecializedThunkJIT
that has helper functions to remove (or at least reduce) the need
to have separate thunk implementations for each JSValue encoding.

  • create_hash_table: Add thunk generation callbacks to the hash tables, currently we hardcode the script to only support charCodeAt
  • jit/JITStubCall.h:
  • jit/JITStubs.cpp: (JSC::JITThunks::~JITThunks): (JSC::JITThunks::specializedThunk):
  • jit/JITStubs.h:
  • jit/SpecializedThunkJIT.h: Added. (JSC::SpecializedThunkJIT::SpecializedThunkJIT): (JSC::SpecializedThunkJIT::loadCellArgument): (JSC::SpecializedThunkJIT::loadJSStringArgument): (JSC::SpecializedThunkJIT::loadInt32Argument): (JSC::SpecializedThunkJIT::appendFailure): (JSC::SpecializedThunkJIT::returnInt32): (JSC::SpecializedThunkJIT::finalize): (JSC::SpecializedThunkJIT::argumentToVirtualRegister): (JSC::SpecializedThunkJIT::tagReturnAsInt32):
  • jit/ThunkGenerators.cpp: Added. (JSC::ThunkHelpers::stringImplDataOffset): (JSC::ThunkHelpers::jsStringLengthOffset): (JSC::ThunkHelpers::jsStringValueOffset): (JSC::charCodeAtThunkGenerator):
  • jit/ThunkGenerators.h: Added.
  • runtime/Executable.h: (JSC::NativeExecutable::NativeExecutable):
  • runtime/JSFunction.cpp: (JSC::JSFunction::JSFunction):
  • runtime/JSFunction.h:
  • runtime/JSGlobalData.h: (JSC::JSGlobalData::getThunk):
  • runtime/JSString.h: (JSC::):
  • runtime/JSValue.h: Protect some of the JSVALUE32 and JSVALUE32_64 only constants and function behind appropriate USE() guards to make it harder to use the wrong flags for the target build.
  • runtime/Lookup.cpp: (JSC::HashTable::createTable): (JSC::setUpStaticFunctionSlot):
  • runtime/Lookup.h: (JSC::HashEntry::initialize): (JSC::HashEntry::generator): (JSC::HashEntry::): Make the lookup tables use a specialized thunkGenerator if present
  • wtf/text/StringImpl.h:

2010-04-26 Oliver Hunt <[email protected]>

Reviewed by Gavin Barraclough.

Need to support more efficient dispatch of lightweight builtins
https://bugs.webkit.org/show_bug.cgi?id=38155

Update bindings generation to include new thunk generator field
in the property map hash tables.

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