2 * Copyright (C) 2007 Eric Seidel <eric@webkit.org>
3 * Copyright (C) 2007, 2008, 2009 Apple Inc. All rights reserved.
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.
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.
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.
22 #ifndef JSGlobalObject_h
23 #define JSGlobalObject_h
26 #include "JSGlobalData.h"
27 #include "JSVariableObject.h"
28 #include "NativeFunctionWrapper.h"
29 #include "NumberPrototype.h"
30 #include "StringPrototype.h"
31 #include <wtf/HashSet.h>
32 #include <wtf/OwnPtr.h>
37 class BooleanPrototype
;
40 class ErrorConstructor
;
41 class FunctionPrototype
;
42 class GlobalCodeBlock
;
43 class GlobalEvalFunction
;
44 class NativeErrorConstructor
;
45 class ProgramCodeBlock
;
46 class PrototypeFunction
;
47 class RegExpConstructor
;
48 class RegExpPrototype
;
51 struct ActivationStackNode
;
54 typedef Vector
<ExecState
*, 16> ExecStateStack
;
56 class JSGlobalObject
: public JSVariableObject
{
58 using JSVariableObject::JSVariableObjectData
;
60 struct JSGlobalObjectData
: public JSVariableObjectData
{
61 // We use an explicit destructor function pointer instead of a
62 // virtual destructor because we want to avoid adding a vtable
63 // pointer to this struct. Adding a vtable pointer would force the
64 // compiler to emit costly pointer fixup code when casting from
65 // JSVariableObjectData* to JSGlobalObjectData*.
66 typedef void (*Destructor
)(void*);
68 JSGlobalObjectData(Destructor destructor
)
69 : JSVariableObjectData(&symbolTable
, 0)
70 , destructor(destructor
)
71 , registerArraySize(0)
72 , globalScopeChain(NoScopeChain())
73 , regExpConstructor(0)
75 , evalErrorConstructor(0)
76 , rangeErrorConstructor(0)
77 , referenceErrorConstructor(0)
78 , syntaxErrorConstructor(0)
79 , typeErrorConstructor(0)
80 , URIErrorConstructor(0)
85 , functionPrototype(0)
96 Destructor destructor
;
98 size_t registerArraySize
;
100 JSGlobalObject
* next
;
101 JSGlobalObject
* prev
;
105 ScopeChain globalScopeChain
;
106 Register globalCallFrame
[RegisterFile::CallFrameHeaderSize
];
110 RegExpConstructor
* regExpConstructor
;
111 ErrorConstructor
* errorConstructor
;
112 NativeErrorConstructor
* evalErrorConstructor
;
113 NativeErrorConstructor
* rangeErrorConstructor
;
114 NativeErrorConstructor
* referenceErrorConstructor
;
115 NativeErrorConstructor
* syntaxErrorConstructor
;
116 NativeErrorConstructor
* typeErrorConstructor
;
117 NativeErrorConstructor
* URIErrorConstructor
;
119 GlobalEvalFunction
* evalFunction
;
120 NativeFunctionWrapper
* callFunction
;
121 NativeFunctionWrapper
* applyFunction
;
123 ObjectPrototype
* objectPrototype
;
124 FunctionPrototype
* functionPrototype
;
125 ArrayPrototype
* arrayPrototype
;
126 BooleanPrototype
* booleanPrototype
;
127 StringPrototype
* stringPrototype
;
128 NumberPrototype
* numberPrototype
;
129 DatePrototype
* datePrototype
;
130 RegExpPrototype
* regExpPrototype
;
132 JSObject
* methodCallDummy
;
134 RefPtr
<Structure
> argumentsStructure
;
135 RefPtr
<Structure
> arrayStructure
;
136 RefPtr
<Structure
> booleanObjectStructure
;
137 RefPtr
<Structure
> callbackConstructorStructure
;
138 RefPtr
<Structure
> callbackFunctionStructure
;
139 RefPtr
<Structure
> callbackObjectStructure
;
140 RefPtr
<Structure
> dateStructure
;
141 RefPtr
<Structure
> emptyObjectStructure
;
142 RefPtr
<Structure
> errorStructure
;
143 RefPtr
<Structure
> functionStructure
;
144 RefPtr
<Structure
> numberObjectStructure
;
145 RefPtr
<Structure
> prototypeFunctionStructure
;
146 RefPtr
<Structure
> regExpMatchesArrayStructure
;
147 RefPtr
<Structure
> regExpStructure
;
148 RefPtr
<Structure
> stringObjectStructure
;
150 SymbolTable symbolTable
;
151 unsigned profileGroup
;
153 RefPtr
<JSGlobalData
> globalData
;
155 HashSet
<GlobalCodeBlock
*> codeBlocks
;
159 void* operator new(size_t, JSGlobalData
*);
161 explicit JSGlobalObject()
162 : JSVariableObject(JSGlobalObject::createStructure(jsNull()), new JSGlobalObjectData(destroyJSGlobalObjectData
))
168 JSGlobalObject(NonNullPassRefPtr
<Structure
> structure
, JSGlobalObjectData
* data
, JSObject
* thisValue
)
169 : JSVariableObject(structure
, data
)
175 virtual ~JSGlobalObject();
177 virtual void markChildren(MarkStack
&);
179 virtual bool getOwnPropertySlot(ExecState
*, const Identifier
&, PropertySlot
&);
180 virtual bool getOwnPropertyDescriptor(ExecState
*, const Identifier
&, PropertyDescriptor
&);
181 virtual bool hasOwnPropertyForWrite(ExecState
*, const Identifier
&);
182 virtual void put(ExecState
*, const Identifier
&, JSValue
, PutPropertySlot
&);
183 virtual void putWithAttributes(ExecState
*, const Identifier
& propertyName
, JSValue value
, unsigned attributes
);
185 virtual void defineGetter(ExecState
*, const Identifier
& propertyName
, JSObject
* getterFunc
, unsigned attributes
);
186 virtual void defineSetter(ExecState
*, const Identifier
& propertyName
, JSObject
* setterFunc
, unsigned attributes
);
188 // Linked list of all global objects that use the same JSGlobalData.
189 JSGlobalObject
*& head() { return d()->globalData
->head
; }
190 JSGlobalObject
* next() { return d()->next
; }
192 // The following accessors return pristine values, even if a script
193 // replaces the global object's associated property.
195 RegExpConstructor
* regExpConstructor() const { return d()->regExpConstructor
; }
197 ErrorConstructor
* errorConstructor() const { return d()->errorConstructor
; }
198 NativeErrorConstructor
* evalErrorConstructor() const { return d()->evalErrorConstructor
; }
199 NativeErrorConstructor
* rangeErrorConstructor() const { return d()->rangeErrorConstructor
; }
200 NativeErrorConstructor
* referenceErrorConstructor() const { return d()->referenceErrorConstructor
; }
201 NativeErrorConstructor
* syntaxErrorConstructor() const { return d()->syntaxErrorConstructor
; }
202 NativeErrorConstructor
* typeErrorConstructor() const { return d()->typeErrorConstructor
; }
203 NativeErrorConstructor
* URIErrorConstructor() const { return d()->URIErrorConstructor
; }
205 GlobalEvalFunction
* evalFunction() const { return d()->evalFunction
; }
207 ObjectPrototype
* objectPrototype() const { return d()->objectPrototype
; }
208 FunctionPrototype
* functionPrototype() const { return d()->functionPrototype
; }
209 ArrayPrototype
* arrayPrototype() const { return d()->arrayPrototype
; }
210 BooleanPrototype
* booleanPrototype() const { return d()->booleanPrototype
; }
211 StringPrototype
* stringPrototype() const { return d()->stringPrototype
; }
212 NumberPrototype
* numberPrototype() const { return d()->numberPrototype
; }
213 DatePrototype
* datePrototype() const { return d()->datePrototype
; }
214 RegExpPrototype
* regExpPrototype() const { return d()->regExpPrototype
; }
216 JSObject
* methodCallDummy() const { return d()->methodCallDummy
; }
218 Structure
* argumentsStructure() const { return d()->argumentsStructure
.get(); }
219 Structure
* arrayStructure() const { return d()->arrayStructure
.get(); }
220 Structure
* booleanObjectStructure() const { return d()->booleanObjectStructure
.get(); }
221 Structure
* callbackConstructorStructure() const { return d()->callbackConstructorStructure
.get(); }
222 Structure
* callbackFunctionStructure() const { return d()->callbackFunctionStructure
.get(); }
223 Structure
* callbackObjectStructure() const { return d()->callbackObjectStructure
.get(); }
224 Structure
* dateStructure() const { return d()->dateStructure
.get(); }
225 Structure
* emptyObjectStructure() const { return d()->emptyObjectStructure
.get(); }
226 Structure
* errorStructure() const { return d()->errorStructure
.get(); }
227 Structure
* functionStructure() const { return d()->functionStructure
.get(); }
228 Structure
* numberObjectStructure() const { return d()->numberObjectStructure
.get(); }
229 Structure
* prototypeFunctionStructure() const { return d()->prototypeFunctionStructure
.get(); }
230 Structure
* regExpMatchesArrayStructure() const { return d()->regExpMatchesArrayStructure
.get(); }
231 Structure
* regExpStructure() const { return d()->regExpStructure
.get(); }
232 Structure
* stringObjectStructure() const { return d()->stringObjectStructure
.get(); }
234 void setProfileGroup(unsigned value
) { d()->profileGroup
= value
; }
235 unsigned profileGroup() const { return d()->profileGroup
; }
237 Debugger
* debugger() const { return d()->debugger
; }
238 void setDebugger(Debugger
* debugger
) { d()->debugger
= debugger
; }
240 virtual bool supportsProfiling() const { return false; }
242 int recursion() { return d()->recursion
; }
243 void incRecursion() { ++d()->recursion
; }
244 void decRecursion() { --d()->recursion
; }
246 ScopeChain
& globalScopeChain() { return d()->globalScopeChain
; }
248 virtual bool isGlobalObject() const { return true; }
250 virtual ExecState
* globalExec();
252 virtual bool shouldInterruptScriptBeforeTimeout() const { return false; }
253 virtual bool shouldInterruptScript() const { return true; }
255 virtual bool allowsAccessFrom(const JSGlobalObject
*) const { return true; }
257 virtual bool isDynamicScope() const;
259 HashSet
<GlobalCodeBlock
*>& codeBlocks() { return d()->codeBlocks
; }
261 void copyGlobalsFrom(RegisterFile
&);
262 void copyGlobalsTo(RegisterFile
&);
264 void resetPrototype(JSValue prototype
);
266 JSGlobalData
* globalData() { return d()->globalData
.get(); }
267 JSGlobalObjectData
* d() const { return static_cast<JSGlobalObjectData
*>(JSVariableObject::d
); }
269 static PassRefPtr
<Structure
> createStructure(JSValue prototype
)
271 return Structure::create(prototype
, TypeInfo(ObjectType
, StructureFlags
), AnonymousSlotCount
);
276 static const unsigned StructureFlags
= OverridesGetOwnPropertySlot
| OverridesMarkChildren
| OverridesGetPropertyNames
| JSVariableObject::StructureFlags
;
278 struct GlobalPropertyInfo
{
279 GlobalPropertyInfo(const Identifier
& i
, JSValue v
, unsigned a
)
286 const Identifier identifier
;
290 void addStaticGlobals(GlobalPropertyInfo
*, int count
);
293 static void destroyJSGlobalObjectData(void*);
295 // FIXME: Fold reset into init.
296 void init(JSObject
* thisValue
);
297 void reset(JSValue prototype
);
299 void setRegisters(Register
* registers
, Register
* registerArray
, size_t count
);
301 void* operator new(size_t); // can only be allocated with JSGlobalData
304 JSGlobalObject
* asGlobalObject(JSValue
);
306 inline JSGlobalObject
* asGlobalObject(JSValue value
)
308 ASSERT(asObject(value
)->isGlobalObject());
309 return static_cast<JSGlobalObject
*>(asObject(value
));
312 inline void JSGlobalObject::setRegisters(Register
* registers
, Register
* registerArray
, size_t count
)
314 JSVariableObject::setRegisters(registers
, registerArray
);
315 d()->registerArraySize
= count
;
318 inline void JSGlobalObject::addStaticGlobals(GlobalPropertyInfo
* globals
, int count
)
320 size_t oldSize
= d()->registerArraySize
;
321 size_t newSize
= oldSize
+ count
;
322 Register
* registerArray
= new Register
[newSize
];
323 if (d()->registerArray
)
324 memcpy(registerArray
+ count
, d()->registerArray
.get(), oldSize
* sizeof(Register
));
325 setRegisters(registerArray
+ newSize
, registerArray
, newSize
);
327 for (int i
= 0, index
= -static_cast<int>(oldSize
) - 1; i
< count
; ++i
, --index
) {
328 GlobalPropertyInfo
& global
= globals
[i
];
329 ASSERT(global
.attributes
& DontDelete
);
330 SymbolTableEntry
newEntry(index
, global
.attributes
);
331 symbolTable().add(global
.identifier
.ustring().rep(), newEntry
);
332 registerAt(index
) = global
.value
;
336 inline bool JSGlobalObject::getOwnPropertySlot(ExecState
* exec
, const Identifier
& propertyName
, PropertySlot
& slot
)
338 if (JSVariableObject::getOwnPropertySlot(exec
, propertyName
, slot
))
340 return symbolTableGet(propertyName
, slot
);
343 inline bool JSGlobalObject::getOwnPropertyDescriptor(ExecState
* exec
, const Identifier
& propertyName
, PropertyDescriptor
& descriptor
)
345 if (symbolTableGet(propertyName
, descriptor
))
347 return JSVariableObject::getOwnPropertyDescriptor(exec
, propertyName
, descriptor
);
350 inline bool JSGlobalObject::hasOwnPropertyForWrite(ExecState
* exec
, const Identifier
& propertyName
)
353 if (JSVariableObject::getOwnPropertySlot(exec
, propertyName
, slot
))
355 bool slotIsWriteable
;
356 return symbolTableGet(propertyName
, slot
, slotIsWriteable
);
359 inline JSValue
Structure::prototypeForLookup(ExecState
* exec
) const
361 if (typeInfo().type() == ObjectType
)
365 if (typeInfo().type() == StringType
)
366 return exec
->lexicalGlobalObject()->stringPrototype();
368 ASSERT(typeInfo().type() == NumberType
);
369 return exec
->lexicalGlobalObject()->numberPrototype();
371 ASSERT(typeInfo().type() == StringType
);
372 return exec
->lexicalGlobalObject()->stringPrototype();
376 inline StructureChain
* Structure::prototypeChain(ExecState
* exec
) const
378 // We cache our prototype chain so our clients can share it.
379 if (!isValid(exec
, m_cachedPrototypeChain
.get())) {
380 JSValue prototype
= prototypeForLookup(exec
);
381 m_cachedPrototypeChain
= StructureChain::create(prototype
.isNull() ? 0 : asObject(prototype
)->structure());
383 return m_cachedPrototypeChain
.get();
386 inline bool Structure::isValid(ExecState
* exec
, StructureChain
* cachedPrototypeChain
) const
388 if (!cachedPrototypeChain
)
391 JSValue prototype
= prototypeForLookup(exec
);
392 RefPtr
<Structure
>* cachedStructure
= cachedPrototypeChain
->head();
393 while(*cachedStructure
&& !prototype
.isNull()) {
394 if (asObject(prototype
)->structure() != *cachedStructure
)
397 prototype
= asObject(prototype
)->prototype();
399 return prototype
.isNull() && !*cachedStructure
;
402 inline JSGlobalObject
* ExecState::dynamicGlobalObject()
404 if (this == lexicalGlobalObject()->globalExec())
405 return lexicalGlobalObject();
407 // For any ExecState that's not a globalExec, the
408 // dynamic global object must be set since code is running
409 ASSERT(globalData().dynamicGlobalObject
);
410 return globalData().dynamicGlobalObject
;
413 inline JSObject
* constructEmptyObject(ExecState
* exec
)
415 return new (exec
) JSObject(exec
->lexicalGlobalObject()->emptyObjectStructure());
418 inline JSObject
* constructEmptyObject(ExecState
* exec
, JSGlobalObject
* globalObject
)
420 return new (exec
) JSObject(globalObject
->emptyObjectStructure());
423 inline JSArray
* constructEmptyArray(ExecState
* exec
)
425 return new (exec
) JSArray(exec
->lexicalGlobalObject()->arrayStructure());
428 inline JSArray
* constructEmptyArray(ExecState
* exec
, JSGlobalObject
* globalObject
)
430 return new (exec
) JSArray(globalObject
->arrayStructure());
433 inline JSArray
* constructEmptyArray(ExecState
* exec
, unsigned initialLength
)
435 return new (exec
) JSArray(exec
->lexicalGlobalObject()->arrayStructure(), initialLength
);
438 inline JSArray
* constructArray(ExecState
* exec
, JSValue singleItemValue
)
440 MarkedArgumentBuffer values
;
441 values
.append(singleItemValue
);
442 return new (exec
) JSArray(exec
->lexicalGlobalObject()->arrayStructure(), values
);
445 inline JSArray
* constructArray(ExecState
* exec
, const ArgList
& values
)
447 return new (exec
) JSArray(exec
->lexicalGlobalObject()->arrayStructure(), values
);
450 class DynamicGlobalObjectScope
: public Noncopyable
{
452 DynamicGlobalObjectScope(CallFrame
* callFrame
, JSGlobalObject
* dynamicGlobalObject
)
453 : m_dynamicGlobalObjectSlot(callFrame
->globalData().dynamicGlobalObject
)
454 , m_savedDynamicGlobalObject(m_dynamicGlobalObjectSlot
)
456 if (!m_dynamicGlobalObjectSlot
) {
457 m_dynamicGlobalObjectSlot
= dynamicGlobalObject
;
459 // Reset the date cache between JS invocations to force the VM
460 // to observe time zone changes.
461 callFrame
->globalData().resetDateCache();
465 ~DynamicGlobalObjectScope()
467 m_dynamicGlobalObjectSlot
= m_savedDynamicGlobalObject
;
471 JSGlobalObject
*& m_dynamicGlobalObjectSlot
;
472 JSGlobalObject
* m_savedDynamicGlobalObject
;
477 #endif // JSGlobalObject_h