1/*
2 * Copyright (C) 2007 Eric Seidel <eric@webkit.org>
3 * Copyright (C) 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 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 "JSArray.h"
26#include "JSGlobalData.h"
27#include "JSVariableObject.h"
28#include "NativeFunctionWrapper.h"
29#include "NumberPrototype.h"
30#include "StringPrototype.h"
31#include "StructureChain.h"
32#include <wtf/HashSet.h>
33#include <wtf/OwnPtr.h>
34#include <wtf/RandomNumber.h>
35
36namespace JSC {
37
38 class ArrayPrototype;
39 class BooleanPrototype;
40 class DatePrototype;
41 class Debugger;
42 class ErrorConstructor;
43 class FunctionPrototype;
44 class GlobalCodeBlock;
45 class GlobalEvalFunction;
46 class NativeErrorConstructor;
47 class ProgramCodeBlock;
48 class PrototypeFunction;
49 class RegExpConstructor;
50 class RegExpPrototype;
51 class RegisterFile;
52
53 struct ActivationStackNode;
54 struct HashTable;
55
56 typedef Vector<ExecState*, 16> ExecStateStack;
57
58 class JSGlobalObject : public JSVariableObject {
59 protected:
60 struct JSGlobalObjectData : public JSVariableObject::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*);
67
68 JSGlobalObjectData(Destructor destructor)
69 : JSVariableObjectData(&symbolTable, 0)
70 , destructor(destructor)
71 , registerArraySize(0)
72 , globalScopeChain(NoScopeChain())
73 , regExpConstructor(0)
74 , errorConstructor(0)
75 , evalErrorConstructor(0)
76 , rangeErrorConstructor(0)
77 , referenceErrorConstructor(0)
78 , syntaxErrorConstructor(0)
79 , typeErrorConstructor(0)
80 , URIErrorConstructor(0)
81 , evalFunction(0)
82 , callFunction(0)
83 , applyFunction(0)
84 , objectPrototype(0)
85 , functionPrototype(0)
86 , arrayPrototype(0)
87 , booleanPrototype(0)
88 , stringPrototype(0)
89 , numberPrototype(0)
90 , datePrototype(0)
91 , regExpPrototype(0)
92 , methodCallDummy(0)
93 , weakRandom(static_cast<unsigned>(randomNumber() * (std::numeric_limits<unsigned>::max() + 1.0)))
94 {
95 }
96
97 Destructor destructor;
98
99 size_t registerArraySize;
100
101 JSGlobalObject* next;
102 JSGlobalObject* prev;
103
104 Debugger* debugger;
105
106 ScopeChain globalScopeChain;
107 Register globalCallFrame[RegisterFile::CallFrameHeaderSize];
108
109 int recursion;
110
111 RegExpConstructor* regExpConstructor;
112 ErrorConstructor* errorConstructor;
113 NativeErrorConstructor* evalErrorConstructor;
114 NativeErrorConstructor* rangeErrorConstructor;
115 NativeErrorConstructor* referenceErrorConstructor;
116 NativeErrorConstructor* syntaxErrorConstructor;
117 NativeErrorConstructor* typeErrorConstructor;
118 NativeErrorConstructor* URIErrorConstructor;
119
120 GlobalEvalFunction* evalFunction;
121 NativeFunctionWrapper* callFunction;
122 NativeFunctionWrapper* applyFunction;
123
124 ObjectPrototype* objectPrototype;
125 FunctionPrototype* functionPrototype;
126 ArrayPrototype* arrayPrototype;
127 BooleanPrototype* booleanPrototype;
128 StringPrototype* stringPrototype;
129 NumberPrototype* numberPrototype;
130 DatePrototype* datePrototype;
131 RegExpPrototype* regExpPrototype;
132
133 JSObject* methodCallDummy;
134
135 RefPtr<Structure> argumentsStructure;
136 RefPtr<Structure> arrayStructure;
137 RefPtr<Structure> booleanObjectStructure;
138 RefPtr<Structure> callbackConstructorStructure;
139 RefPtr<Structure> callbackFunctionStructure;
140 RefPtr<Structure> callbackObjectStructure;
141 RefPtr<Structure> dateStructure;
142 RefPtr<Structure> emptyObjectStructure;
143 RefPtr<Structure> errorStructure;
144 RefPtr<Structure> functionStructure;
145 RefPtr<Structure> numberObjectStructure;
146 RefPtr<Structure> prototypeFunctionStructure;
147 RefPtr<Structure> regExpMatchesArrayStructure;
148 RefPtr<Structure> regExpStructure;
149 RefPtr<Structure> stringObjectStructure;
150
151 SymbolTable symbolTable;
152 unsigned profileGroup;
153
154 RefPtr<JSGlobalData> globalData;
155
156 HashSet<GlobalCodeBlock*> codeBlocks;
157 WeakRandom weakRandom;
158 };
159
160 public:
161 void* operator new(size_t, JSGlobalData*);
162
163 explicit JSGlobalObject()
164 : JSVariableObject(JSGlobalObject::createStructure(prototype: jsNull()), new JSGlobalObjectData(destroyJSGlobalObjectData))
165 {
166 init(thisValue: this);
167 }
168
169 protected:
170 JSGlobalObject(NonNullPassRefPtr<Structure> structure, JSGlobalObjectData* data, JSObject* thisValue)
171 : JSVariableObject(structure, data)
172 {
173 init(thisValue);
174 }
175
176 public:
177 virtual ~JSGlobalObject();
178
179 virtual void markChildren(MarkStack&);
180
181 virtual bool getOwnPropertySlot(ExecState*, const Identifier&, PropertySlot&);
182 virtual bool getOwnPropertyDescriptor(ExecState*, const Identifier&, PropertyDescriptor&);
183 virtual bool hasOwnPropertyForWrite(ExecState*, const Identifier&);
184 virtual void put(ExecState*, const Identifier&, JSValue, PutPropertySlot&);
185 virtual void putWithAttributes(ExecState*, const Identifier& propertyName, JSValue value, unsigned attributes);
186
187 virtual void defineGetter(ExecState*, const Identifier& propertyName, JSObject* getterFunc, unsigned attributes);
188 virtual void defineSetter(ExecState*, const Identifier& propertyName, JSObject* setterFunc, unsigned attributes);
189
190 // Linked list of all global objects that use the same JSGlobalData.
191 JSGlobalObject*& head() { return d()->globalData->head; }
192 JSGlobalObject* next() { return d()->next; }
193
194 // The following accessors return pristine values, even if a script
195 // replaces the global object's associated property.
196
197 RegExpConstructor* regExpConstructor() const { return d()->regExpConstructor; }
198
199 ErrorConstructor* errorConstructor() const { return d()->errorConstructor; }
200 NativeErrorConstructor* evalErrorConstructor() const { return d()->evalErrorConstructor; }
201 NativeErrorConstructor* rangeErrorConstructor() const { return d()->rangeErrorConstructor; }
202 NativeErrorConstructor* referenceErrorConstructor() const { return d()->referenceErrorConstructor; }
203 NativeErrorConstructor* syntaxErrorConstructor() const { return d()->syntaxErrorConstructor; }
204 NativeErrorConstructor* typeErrorConstructor() const { return d()->typeErrorConstructor; }
205 NativeErrorConstructor* URIErrorConstructor() const { return d()->URIErrorConstructor; }
206
207 GlobalEvalFunction* evalFunction() const { return d()->evalFunction; }
208
209 ObjectPrototype* objectPrototype() const { return d()->objectPrototype; }
210 FunctionPrototype* functionPrototype() const { return d()->functionPrototype; }
211 ArrayPrototype* arrayPrototype() const { return d()->arrayPrototype; }
212 BooleanPrototype* booleanPrototype() const { return d()->booleanPrototype; }
213 StringPrototype* stringPrototype() const { return d()->stringPrototype; }
214 NumberPrototype* numberPrototype() const { return d()->numberPrototype; }
215 DatePrototype* datePrototype() const { return d()->datePrototype; }
216 RegExpPrototype* regExpPrototype() const { return d()->regExpPrototype; }
217
218 JSObject* methodCallDummy() const { return d()->methodCallDummy; }
219
220 Structure* argumentsStructure() const { return d()->argumentsStructure.get(); }
221 Structure* arrayStructure() const { return d()->arrayStructure.get(); }
222 Structure* booleanObjectStructure() const { return d()->booleanObjectStructure.get(); }
223 Structure* callbackConstructorStructure() const { return d()->callbackConstructorStructure.get(); }
224 Structure* callbackFunctionStructure() const { return d()->callbackFunctionStructure.get(); }
225 Structure* callbackObjectStructure() const { return d()->callbackObjectStructure.get(); }
226 Structure* dateStructure() const { return d()->dateStructure.get(); }
227 Structure* emptyObjectStructure() const { return d()->emptyObjectStructure.get(); }
228 Structure* errorStructure() const { return d()->errorStructure.get(); }
229 Structure* functionStructure() const { return d()->functionStructure.get(); }
230 Structure* numberObjectStructure() const { return d()->numberObjectStructure.get(); }
231 Structure* prototypeFunctionStructure() const { return d()->prototypeFunctionStructure.get(); }
232 Structure* regExpMatchesArrayStructure() const { return d()->regExpMatchesArrayStructure.get(); }
233 Structure* regExpStructure() const { return d()->regExpStructure.get(); }
234 Structure* stringObjectStructure() const { return d()->stringObjectStructure.get(); }
235
236 void setProfileGroup(unsigned value) { d()->profileGroup = value; }
237 unsigned profileGroup() const { return d()->profileGroup; }
238
239 Debugger* debugger() const { return d()->debugger; }
240 void setDebugger(Debugger* debugger) { d()->debugger = debugger; }
241
242 virtual bool supportsProfiling() const { return false; }
243
244 int recursion() { return d()->recursion; }
245 void incRecursion() { ++d()->recursion; }
246 void decRecursion() { --d()->recursion; }
247
248 ScopeChain& globalScopeChain() { return d()->globalScopeChain; }
249
250 virtual bool isGlobalObject() const { return true; }
251
252 virtual ExecState* globalExec();
253
254 virtual bool shouldInterruptScript() const { return true; }
255
256 virtual bool allowsAccessFrom(const JSGlobalObject*) const { return true; }
257
258 virtual bool isDynamicScope() const;
259
260 HashSet<GlobalCodeBlock*>& codeBlocks() { return d()->codeBlocks; }
261
262 void copyGlobalsFrom(RegisterFile&);
263 void copyGlobalsTo(RegisterFile&);
264
265 void resetPrototype(JSValue prototype);
266
267 JSGlobalData* globalData() { return d()->globalData.get(); }
268 JSGlobalObjectData* d() const { return static_cast<JSGlobalObjectData*>(JSVariableObject::d); }
269
270 static PassRefPtr<Structure> createStructure(JSValue prototype)
271 {
272 return Structure::create(prototype, typeInfo: TypeInfo(ObjectType, StructureFlags));
273 }
274
275 double weakRandomNumber() { return d()->weakRandom.get(); }
276 protected:
277
278 static const unsigned StructureFlags = OverridesGetOwnPropertySlot | OverridesMarkChildren | OverridesGetPropertyNames | JSVariableObject::StructureFlags;
279
280 struct GlobalPropertyInfo {
281 GlobalPropertyInfo(const Identifier& i, JSValue v, unsigned a)
282 : identifier(i)
283 , value(v)
284 , attributes(a)
285 {
286 }
287
288 const Identifier identifier;
289 JSValue value;
290 unsigned attributes;
291 };
292 void addStaticGlobals(GlobalPropertyInfo*, int count);
293
294 private:
295 static void destroyJSGlobalObjectData(void*);
296
297 // FIXME: Fold reset into init.
298 void init(JSObject* thisValue);
299 void reset(JSValue prototype);
300
301 void setRegisters(Register* registers, Register* registerArray, size_t count);
302
303 void* operator new(size_t); // can only be allocated with JSGlobalData
304 };
305
306 JSGlobalObject* asGlobalObject(JSValue);
307
308 inline JSGlobalObject* asGlobalObject(JSValue value)
309 {
310 ASSERT(asObject(value)->isGlobalObject());
311 return static_cast<JSGlobalObject*>(asObject(value));
312 }
313
314 inline void JSGlobalObject::setRegisters(Register* registers, Register* registerArray, size_t count)
315 {
316 JSVariableObject::setRegisters(registers, registerArray);
317 d()->registerArraySize = count;
318 }
319
320 inline void JSGlobalObject::addStaticGlobals(GlobalPropertyInfo* globals, int count)
321 {
322 size_t oldSize = d()->registerArraySize;
323 size_t newSize = oldSize + count;
324 Register* registerArray = new Register[newSize];
325 if (d()->registerArray)
326 memcpy(dest: registerArray + count, src: d()->registerArray.get(), n: oldSize * sizeof(Register));
327 setRegisters(registers: registerArray + newSize, registerArray, count: newSize);
328
329 for (int i = 0, index = -static_cast<int>(oldSize) - 1; i < count; ++i, --index) {
330 GlobalPropertyInfo& global = globals[i];
331 ASSERT(global.attributes & DontDelete);
332 SymbolTableEntry newEntry(index, global.attributes);
333 symbolTable().add(key: global.identifier.ustring().rep(), mapped: newEntry);
334 registerAt(index) = global.value;
335 }
336 }
337
338 inline bool JSGlobalObject::getOwnPropertySlot(ExecState* exec, const Identifier& propertyName, PropertySlot& slot)
339 {
340 if (JSVariableObject::getOwnPropertySlot(exec, propertyName, slot))
341 return true;
342 return symbolTableGet(propertyName, slot);
343 }
344
345 inline bool JSGlobalObject::getOwnPropertyDescriptor(ExecState* exec, const Identifier& propertyName, PropertyDescriptor& descriptor)
346 {
347 if (symbolTableGet(propertyName, descriptor))
348 return true;
349 return JSVariableObject::getOwnPropertyDescriptor(exec, propertyName, descriptor);
350 }
351
352 inline bool JSGlobalObject::hasOwnPropertyForWrite(ExecState* exec, const Identifier& propertyName)
353 {
354 PropertySlot slot;
355 if (JSVariableObject::getOwnPropertySlot(exec, propertyName, slot))
356 return true;
357 bool slotIsWriteable;
358 return symbolTableGet(propertyName, slot, slotIsWriteable);
359 }
360
361 inline JSValue Structure::prototypeForLookup(ExecState* exec) const
362 {
363 if (typeInfo().type() == ObjectType)
364 return m_prototype;
365
366#if USE(JSVALUE32)
367 if (typeInfo().type() == StringType)
368 return exec->lexicalGlobalObject()->stringPrototype();
369
370 ASSERT(typeInfo().type() == NumberType);
371 return exec->lexicalGlobalObject()->numberPrototype();
372#else
373 ASSERT(typeInfo().type() == StringType);
374 return exec->lexicalGlobalObject()->stringPrototype();
375#endif
376 }
377
378 inline StructureChain* Structure::prototypeChain(ExecState* exec) const
379 {
380 // We cache our prototype chain so our clients can share it.
381 if (!isValid(exec, cachedPrototypeChain: m_cachedPrototypeChain.get())) {
382 JSValue prototype = prototypeForLookup(exec);
383 m_cachedPrototypeChain = StructureChain::create(head: prototype.isNull() ? 0 : asObject(value: prototype)->structure());
384 }
385 return m_cachedPrototypeChain.get();
386 }
387
388 inline bool Structure::isValid(ExecState* exec, StructureChain* cachedPrototypeChain) const
389 {
390 if (!cachedPrototypeChain)
391 return false;
392
393 JSValue prototype = prototypeForLookup(exec);
394 RefPtr<Structure>* cachedStructure = cachedPrototypeChain->head();
395 while(*cachedStructure && !prototype.isNull()) {
396 if (asObject(value: prototype)->structure() != *cachedStructure)
397 return false;
398 ++cachedStructure;
399 prototype = asObject(value: prototype)->prototype();
400 }
401 return prototype.isNull() && !*cachedStructure;
402 }
403
404 inline JSGlobalObject* ExecState::dynamicGlobalObject()
405 {
406 if (this == lexicalGlobalObject()->globalExec())
407 return lexicalGlobalObject();
408
409 // For any ExecState that's not a globalExec, the
410 // dynamic global object must be set since code is running
411 ASSERT(globalData().dynamicGlobalObject);
412 return globalData().dynamicGlobalObject;
413 }
414
415 inline JSObject* constructEmptyObject(ExecState* exec)
416 {
417 return new (exec) JSObject(exec->lexicalGlobalObject()->emptyObjectStructure());
418 }
419
420 inline JSArray* constructEmptyArray(ExecState* exec)
421 {
422 return new (exec) JSArray(exec->lexicalGlobalObject()->arrayStructure());
423 }
424
425 inline JSArray* constructEmptyArray(ExecState* exec, unsigned initialLength)
426 {
427 return new (exec) JSArray(exec->lexicalGlobalObject()->arrayStructure(), initialLength);
428 }
429
430 inline JSArray* constructArray(ExecState* exec, JSValue singleItemValue)
431 {
432 MarkedArgumentBuffer values;
433 values.append(v: singleItemValue);
434 return new (exec) JSArray(exec->lexicalGlobalObject()->arrayStructure(), values);
435 }
436
437 inline JSArray* constructArray(ExecState* exec, const ArgList& values)
438 {
439 return new (exec) JSArray(exec->lexicalGlobalObject()->arrayStructure(), values);
440 }
441
442 class DynamicGlobalObjectScope : public Noncopyable {
443 public:
444 DynamicGlobalObjectScope(CallFrame* callFrame, JSGlobalObject* dynamicGlobalObject)
445 : m_dynamicGlobalObjectSlot(callFrame->globalData().dynamicGlobalObject)
446 , m_savedDynamicGlobalObject(m_dynamicGlobalObjectSlot)
447 {
448 if (!m_dynamicGlobalObjectSlot) {
449 m_dynamicGlobalObjectSlot = dynamicGlobalObject;
450
451 // Reset the date cache between JS invocations to force the VM
452 // to observe time zone changes.
453 callFrame->globalData().resetDateCache();
454 }
455 }
456
457 ~DynamicGlobalObjectScope()
458 {
459 m_dynamicGlobalObjectSlot = m_savedDynamicGlobalObject;
460 }
461
462 private:
463 JSGlobalObject*& m_dynamicGlobalObjectSlot;
464 JSGlobalObject* m_savedDynamicGlobalObject;
465 };
466
467} // namespace JSC
468
469#endif // JSGlobalObject_h
470

source code of qtscript/src/3rdparty/javascriptcore/JavaScriptCore/runtime/JSGlobalObject.h