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