source: webkit/trunk/JavaScriptCore/runtime/JSGlobalObject.h@ 43383

Last change on this file since 43383 was 43220, checked in by [email protected], 16 years ago

Bug 25559: Improve native function call performance
<https://bugs.webkit.org/show_bug.cgi?id=25559>

Reviewed by Gavin Barraclough

In order to cache calls to native functions we now make the standard
prototype functions use a small assembly thunk that converts the JS
calling convention into the native calling convention. As this is
only beneficial in the JIT we use the NativeFunctionWrapper typedef
to alternate between PrototypeFunction and JSFunction to keep the
code sane. This change from PrototypeFunction to NativeFunctionWrapper
is the bulk of this patch.

  • Property svn:eol-style set to native
File size: 16.0 KB
Line 
1/*
2 * Copyright (C) 2007 Eric Seidel <[email protected]>
3 * Copyright (C) 2007, 2008 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 Library 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 * Library General Public License for more details.
14 *
15 * You should have received a copy of the GNU Library General Public License
16 * along with this library; see the file COPYING.LIB. If not, write to
17 * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
18 * Boston, MA 02110-1301, USA.
19 *
20 */
21
22#ifndef JSGlobalObject_h
23#define JSGlobalObject_h
24
25#include "JSGlobalData.h"
26#include "JSVariableObject.h"
27#include "NativeFunctionWrapper.h"
28#include "NumberPrototype.h"
29#include "StringPrototype.h"
30#include <wtf/HashSet.h>
31#include <wtf/OwnPtr.h>
32
33namespace JSC {
34
35 class ArrayPrototype;
36 class BooleanPrototype;
37 class DatePrototype;
38 class Debugger;
39 class ErrorConstructor;
40 class FunctionPrototype;
41 class GlobalEvalFunction;
42 class NativeErrorConstructor;
43 class ProgramCodeBlock;
44 class PrototypeFunction;
45 class RegExpConstructor;
46 class RegExpPrototype;
47 class RegisterFile;
48
49 struct ActivationStackNode;
50 struct HashTable;
51
52 typedef Vector<ExecState*, 16> ExecStateStack;
53
54 class JSGlobalObject : public JSVariableObject {
55 protected:
56 using JSVariableObject::JSVariableObjectData;
57
58 struct JSGlobalObjectData : public JSVariableObjectData {
59 JSGlobalObjectData()
60 : JSVariableObjectData(&symbolTable, 0)
61 , registerArraySize(0)
62 , globalScopeChain(NoScopeChain())
63 , regExpConstructor(0)
64 , errorConstructor(0)
65 , evalErrorConstructor(0)
66 , rangeErrorConstructor(0)
67 , referenceErrorConstructor(0)
68 , syntaxErrorConstructor(0)
69 , typeErrorConstructor(0)
70 , URIErrorConstructor(0)
71 , evalFunction(0)
72 , callFunction(0)
73 , applyFunction(0)
74 , objectPrototype(0)
75 , functionPrototype(0)
76 , arrayPrototype(0)
77 , booleanPrototype(0)
78 , stringPrototype(0)
79 , numberPrototype(0)
80 , datePrototype(0)
81 , regExpPrototype(0)
82 {
83 }
84
85 virtual ~JSGlobalObjectData()
86 {
87 }
88
89 size_t registerArraySize;
90
91 JSGlobalObject* next;
92 JSGlobalObject* prev;
93
94 Debugger* debugger;
95
96 ScopeChain globalScopeChain;
97 Register globalCallFrame[RegisterFile::CallFrameHeaderSize];
98
99 int recursion;
100
101 RegExpConstructor* regExpConstructor;
102 ErrorConstructor* errorConstructor;
103 NativeErrorConstructor* evalErrorConstructor;
104 NativeErrorConstructor* rangeErrorConstructor;
105 NativeErrorConstructor* referenceErrorConstructor;
106 NativeErrorConstructor* syntaxErrorConstructor;
107 NativeErrorConstructor* typeErrorConstructor;
108 NativeErrorConstructor* URIErrorConstructor;
109
110 GlobalEvalFunction* evalFunction;
111 NativeFunctionWrapper* callFunction;
112 NativeFunctionWrapper* applyFunction;
113
114 ObjectPrototype* objectPrototype;
115 FunctionPrototype* functionPrototype;
116 ArrayPrototype* arrayPrototype;
117 BooleanPrototype* booleanPrototype;
118 StringPrototype* stringPrototype;
119 NumberPrototype* numberPrototype;
120 DatePrototype* datePrototype;
121 RegExpPrototype* regExpPrototype;
122
123 RefPtr<Structure> argumentsStructure;
124 RefPtr<Structure> arrayStructure;
125 RefPtr<Structure> booleanObjectStructure;
126 RefPtr<Structure> callbackConstructorStructure;
127 RefPtr<Structure> callbackFunctionStructure;
128 RefPtr<Structure> callbackObjectStructure;
129 RefPtr<Structure> dateStructure;
130 RefPtr<Structure> emptyObjectStructure;
131 RefPtr<Structure> errorStructure;
132 RefPtr<Structure> functionStructure;
133 RefPtr<Structure> numberObjectStructure;
134 RefPtr<Structure> prototypeFunctionStructure;
135 RefPtr<Structure> regExpMatchesArrayStructure;
136 RefPtr<Structure> regExpStructure;
137 RefPtr<Structure> stringObjectStructure;
138
139 SymbolTable symbolTable;
140 unsigned profileGroup;
141
142 RefPtr<JSGlobalData> globalData;
143
144 HashSet<ProgramCodeBlock*> codeBlocks;
145 };
146
147 public:
148 void* operator new(size_t, JSGlobalData*);
149
150 explicit JSGlobalObject()
151 : JSVariableObject(JSGlobalObject::createStructure(jsNull()), new JSGlobalObjectData)
152 {
153 init(this);
154 }
155
156 protected:
157 JSGlobalObject(PassRefPtr<Structure> structure, JSGlobalObjectData* data, JSObject* thisValue)
158 : JSVariableObject(structure, data)
159 {
160 init(thisValue);
161 }
162
163 public:
164 virtual ~JSGlobalObject();
165
166 virtual void mark();
167
168 virtual bool getOwnPropertySlot(ExecState*, const Identifier&, PropertySlot&);
169 virtual bool getOwnPropertySlot(ExecState*, const Identifier&, PropertySlot&, bool& slotIsWriteable);
170 virtual void put(ExecState*, const Identifier&, JSValue, PutPropertySlot&);
171 virtual void putWithAttributes(ExecState*, const Identifier& propertyName, JSValue value, unsigned attributes);
172
173 virtual void defineGetter(ExecState*, const Identifier& propertyName, JSObject* getterFunc);
174 virtual void defineSetter(ExecState*, const Identifier& propertyName, JSObject* setterFunc);
175
176 // Linked list of all global objects that use the same JSGlobalData.
177 JSGlobalObject*& head() { return d()->globalData->head; }
178 JSGlobalObject* next() { return d()->next; }
179
180 // The following accessors return pristine values, even if a script
181 // replaces the global object's associated property.
182
183 RegExpConstructor* regExpConstructor() const { return d()->regExpConstructor; }
184
185 ErrorConstructor* errorConstructor() const { return d()->errorConstructor; }
186 NativeErrorConstructor* evalErrorConstructor() const { return d()->evalErrorConstructor; }
187 NativeErrorConstructor* rangeErrorConstructor() const { return d()->rangeErrorConstructor; }
188 NativeErrorConstructor* referenceErrorConstructor() const { return d()->referenceErrorConstructor; }
189 NativeErrorConstructor* syntaxErrorConstructor() const { return d()->syntaxErrorConstructor; }
190 NativeErrorConstructor* typeErrorConstructor() const { return d()->typeErrorConstructor; }
191 NativeErrorConstructor* URIErrorConstructor() const { return d()->URIErrorConstructor; }
192
193 GlobalEvalFunction* evalFunction() const { return d()->evalFunction; }
194
195 ObjectPrototype* objectPrototype() const { return d()->objectPrototype; }
196 FunctionPrototype* functionPrototype() const { return d()->functionPrototype; }
197 ArrayPrototype* arrayPrototype() const { return d()->arrayPrototype; }
198 BooleanPrototype* booleanPrototype() const { return d()->booleanPrototype; }
199 StringPrototype* stringPrototype() const { return d()->stringPrototype; }
200 NumberPrototype* numberPrototype() const { return d()->numberPrototype; }
201 DatePrototype* datePrototype() const { return d()->datePrototype; }
202 RegExpPrototype* regExpPrototype() const { return d()->regExpPrototype; }
203
204 Structure* argumentsStructure() const { return d()->argumentsStructure.get(); }
205 Structure* arrayStructure() const { return d()->arrayStructure.get(); }
206 Structure* booleanObjectStructure() const { return d()->booleanObjectStructure.get(); }
207 Structure* callbackConstructorStructure() const { return d()->callbackConstructorStructure.get(); }
208 Structure* callbackFunctionStructure() const { return d()->callbackFunctionStructure.get(); }
209 Structure* callbackObjectStructure() const { return d()->callbackObjectStructure.get(); }
210 Structure* dateStructure() const { return d()->dateStructure.get(); }
211 Structure* emptyObjectStructure() const { return d()->emptyObjectStructure.get(); }
212 Structure* errorStructure() const { return d()->errorStructure.get(); }
213 Structure* functionStructure() const { return d()->functionStructure.get(); }
214 Structure* numberObjectStructure() const { return d()->numberObjectStructure.get(); }
215 Structure* prototypeFunctionStructure() const { return d()->prototypeFunctionStructure.get(); }
216 Structure* regExpMatchesArrayStructure() const { return d()->regExpMatchesArrayStructure.get(); }
217 Structure* regExpStructure() const { return d()->regExpStructure.get(); }
218 Structure* stringObjectStructure() const { return d()->stringObjectStructure.get(); }
219
220 void setProfileGroup(unsigned value) { d()->profileGroup = value; }
221 unsigned profileGroup() const { return d()->profileGroup; }
222
223 Debugger* debugger() const { return d()->debugger; }
224 void setDebugger(Debugger* debugger) { d()->debugger = debugger; }
225
226 virtual bool supportsProfiling() const { return false; }
227
228 int recursion() { return d()->recursion; }
229 void incRecursion() { ++d()->recursion; }
230 void decRecursion() { --d()->recursion; }
231
232 ScopeChain& globalScopeChain() { return d()->globalScopeChain; }
233
234 virtual bool isGlobalObject() const { return true; }
235
236 virtual ExecState* globalExec();
237
238 virtual bool shouldInterruptScript() const { return true; }
239
240 virtual bool allowsAccessFrom(const JSGlobalObject*) const { return true; }
241
242 virtual bool isDynamicScope() const;
243
244 HashSet<ProgramCodeBlock*>& codeBlocks() { return d()->codeBlocks; }
245
246 void copyGlobalsFrom(RegisterFile&);
247 void copyGlobalsTo(RegisterFile&);
248
249 void resetPrototype(JSValue prototype);
250
251 JSGlobalData* globalData() { return d()->globalData.get(); }
252 JSGlobalObjectData* d() const { return static_cast<JSGlobalObjectData*>(JSVariableObject::d); }
253
254 static PassRefPtr<Structure> createStructure(JSValue prototype)
255 {
256 return Structure::create(prototype, TypeInfo(ObjectType));
257 }
258
259 protected:
260 struct GlobalPropertyInfo {
261 GlobalPropertyInfo(const Identifier& i, JSValue v, unsigned a)
262 : identifier(i)
263 , value(v)
264 , attributes(a)
265 {
266 }
267
268 const Identifier identifier;
269 JSValue value;
270 unsigned attributes;
271 };
272 void addStaticGlobals(GlobalPropertyInfo*, int count);
273
274 private:
275 // FIXME: Fold reset into init.
276 void init(JSObject* thisValue);
277 void reset(JSValue prototype);
278
279 void setRegisters(Register* registers, Register* registerArray, size_t count);
280
281 void* operator new(size_t); // can only be allocated with JSGlobalData
282 };
283
284 JSGlobalObject* asGlobalObject(JSValue);
285
286 inline JSGlobalObject* asGlobalObject(JSValue value)
287 {
288 ASSERT(asObject(value)->isGlobalObject());
289 return static_cast<JSGlobalObject*>(asObject(value));
290 }
291
292 inline void JSGlobalObject::setRegisters(Register* registers, Register* registerArray, size_t count)
293 {
294 JSVariableObject::setRegisters(registers, registerArray);
295 d()->registerArraySize = count;
296 }
297
298 inline void JSGlobalObject::addStaticGlobals(GlobalPropertyInfo* globals, int count)
299 {
300 size_t oldSize = d()->registerArraySize;
301 size_t newSize = oldSize + count;
302 Register* registerArray = new Register[newSize];
303 if (d()->registerArray)
304 memcpy(registerArray + count, d()->registerArray.get(), oldSize * sizeof(Register));
305 setRegisters(registerArray + newSize, registerArray, newSize);
306
307 for (int i = 0, index = -static_cast<int>(oldSize) - 1; i < count; ++i, --index) {
308 GlobalPropertyInfo& global = globals[i];
309 ASSERT(global.attributes & DontDelete);
310 SymbolTableEntry newEntry(index, global.attributes);
311 symbolTable().add(global.identifier.ustring().rep(), newEntry);
312 registerAt(index) = global.value;
313 }
314 }
315
316 inline bool JSGlobalObject::getOwnPropertySlot(ExecState* exec, const Identifier& propertyName, PropertySlot& slot)
317 {
318 if (JSVariableObject::getOwnPropertySlot(exec, propertyName, slot))
319 return true;
320 return symbolTableGet(propertyName, slot);
321 }
322
323 inline bool JSGlobalObject::getOwnPropertySlot(ExecState* exec, const Identifier& propertyName, PropertySlot& slot, bool& slotIsWriteable)
324 {
325 if (JSVariableObject::getOwnPropertySlotForWrite(exec, propertyName, slot, slotIsWriteable))
326 return true;
327 return symbolTableGet(propertyName, slot, slotIsWriteable);
328 }
329
330 inline JSGlobalObject* ScopeChainNode::globalObject() const
331 {
332 const ScopeChainNode* n = this;
333 while (n->next)
334 n = n->next;
335 return asGlobalObject(n->object);
336 }
337
338 inline JSValue Structure::prototypeForLookup(ExecState* exec) const
339 {
340 if (typeInfo().type() == ObjectType)
341 return m_prototype;
342
343 if (typeInfo().type() == StringType)
344 return exec->lexicalGlobalObject()->stringPrototype();
345
346 ASSERT(typeInfo().type() == NumberType);
347 return exec->lexicalGlobalObject()->numberPrototype();
348 }
349
350 inline StructureChain* Structure::prototypeChain(ExecState* exec) const
351 {
352 // We cache our prototype chain so our clients can share it.
353 if (!isValid(exec, m_cachedPrototypeChain.get())) {
354 JSValue prototype = prototypeForLookup(exec);
355 m_cachedPrototypeChain = StructureChain::create(prototype.isNull() ? 0 : asObject(prototype)->structure());
356 }
357 return m_cachedPrototypeChain.get();
358 }
359
360 inline bool Structure::isValid(ExecState* exec, StructureChain* cachedPrototypeChain) const
361 {
362 if (!cachedPrototypeChain)
363 return false;
364
365 JSValue prototype = prototypeForLookup(exec);
366 RefPtr<Structure>* cachedStructure = cachedPrototypeChain->head();
367 while(*cachedStructure && !prototype.isNull()) {
368 if (asObject(prototype)->structure() != *cachedStructure)
369 return false;
370 ++cachedStructure;
371 prototype = asObject(prototype)->prototype();
372 }
373 return prototype.isNull() && !*cachedStructure;
374 }
375
376 inline JSGlobalObject* ExecState::dynamicGlobalObject()
377 {
378 if (this == lexicalGlobalObject()->globalExec())
379 return lexicalGlobalObject();
380
381 // For any ExecState that's not a globalExec, the
382 // dynamic global object must be set since code is running
383 ASSERT(globalData().dynamicGlobalObject);
384 return globalData().dynamicGlobalObject;
385 }
386
387 class DynamicGlobalObjectScope : Noncopyable {
388 public:
389 DynamicGlobalObjectScope(CallFrame* callFrame, JSGlobalObject* dynamicGlobalObject)
390 : m_dynamicGlobalObjectSlot(callFrame->globalData().dynamicGlobalObject)
391 , m_savedDynamicGlobalObject(m_dynamicGlobalObjectSlot)
392 {
393 m_dynamicGlobalObjectSlot = dynamicGlobalObject;
394 }
395
396 ~DynamicGlobalObjectScope()
397 {
398 m_dynamicGlobalObjectSlot = m_savedDynamicGlobalObject;
399 }
400
401 private:
402 JSGlobalObject*& m_dynamicGlobalObjectSlot;
403 JSGlobalObject* m_savedDynamicGlobalObject;
404 };
405
406} // namespace JSC
407
408#endif // JSGlobalObject_h
Note: See TracBrowser for help on using the repository browser.