Add support for private names
[WebKit-https.git] / Source / JavaScriptCore / runtime / JSGlobalObject.h
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 "JSGlobalThis.h"
28 #include "JSVariableObject.h"
29 #include "JSWeakObjectMapRefInternal.h"
30 #include "NumberPrototype.h"
31 #include "StringPrototype.h"
32 #include "StructureChain.h"
33 #include <wtf/HashSet.h>
34 #include <wtf/OwnPtr.h>
35 #include <wtf/RandomNumber.h>
36
37 namespace JSC {
38
39     class ArrayPrototype;
40     class BooleanPrototype;
41     class DatePrototype;
42     class Debugger;
43     class ErrorConstructor;
44     class FunctionPrototype;
45     class GetterSetter;
46     class GlobalCodeBlock;
47     class LLIntOffsetsExtractor;
48     class NativeErrorConstructor;
49     class ProgramCodeBlock;
50     class RegExpConstructor;
51     class RegExpPrototype;
52     class RegisterFile;
53
54     struct ActivationStackNode;
55     struct HashTable;
56
57     typedef Vector<ExecState*, 16> ExecStateStack;
58     
59     struct GlobalObjectMethodTable {
60         typedef bool (*AllowsAccessFromFunctionPtr)(const JSGlobalObject*, ExecState*);
61         AllowsAccessFromFunctionPtr allowsAccessFrom;
62
63         typedef bool (*SupportsProfilingFunctionPtr)(const JSGlobalObject*); 
64         SupportsProfilingFunctionPtr supportsProfiling;
65
66         typedef bool (*SupportsRichSourceInfoFunctionPtr)(const JSGlobalObject*);
67         SupportsRichSourceInfoFunctionPtr supportsRichSourceInfo;
68
69         typedef bool (*ShouldInterruptScriptFunctionPtr)(const JSGlobalObject*);
70         ShouldInterruptScriptFunctionPtr shouldInterruptScript;
71     };
72
73     class JSGlobalObject : public JSVariableObject {
74     private:
75         typedef HashSet<RefPtr<OpaqueJSWeakObjectMap> > WeakMapSet;
76
77         struct JSGlobalObjectRareData {
78             JSGlobalObjectRareData()
79                 : profileGroup(0)
80             {
81             }
82
83             WeakMapSet weakMaps;
84             unsigned profileGroup;
85         };
86
87     protected:
88
89         size_t m_registerArraySize;
90         Register m_globalCallFrame[RegisterFile::CallFrameHeaderSize];
91
92         WriteBarrier<ScopeChainNode> m_globalScopeChain;
93         WriteBarrier<JSObject> m_methodCallDummy;
94
95         WriteBarrier<RegExpConstructor> m_regExpConstructor;
96         WriteBarrier<ErrorConstructor> m_errorConstructor;
97         WriteBarrier<NativeErrorConstructor> m_evalErrorConstructor;
98         WriteBarrier<NativeErrorConstructor> m_rangeErrorConstructor;
99         WriteBarrier<NativeErrorConstructor> m_referenceErrorConstructor;
100         WriteBarrier<NativeErrorConstructor> m_syntaxErrorConstructor;
101         WriteBarrier<NativeErrorConstructor> m_typeErrorConstructor;
102         WriteBarrier<NativeErrorConstructor> m_URIErrorConstructor;
103
104         WriteBarrier<JSFunction> m_evalFunction;
105         WriteBarrier<JSFunction> m_callFunction;
106         WriteBarrier<JSFunction> m_applyFunction;
107         WriteBarrier<GetterSetter> m_throwTypeErrorGetterSetter;
108
109         WriteBarrier<ObjectPrototype> m_objectPrototype;
110         WriteBarrier<FunctionPrototype> m_functionPrototype;
111         WriteBarrier<ArrayPrototype> m_arrayPrototype;
112         WriteBarrier<BooleanPrototype> m_booleanPrototype;
113         WriteBarrier<StringPrototype> m_stringPrototype;
114         WriteBarrier<NumberPrototype> m_numberPrototype;
115         WriteBarrier<DatePrototype> m_datePrototype;
116         WriteBarrier<RegExpPrototype> m_regExpPrototype;
117
118         WriteBarrier<Structure> m_argumentsStructure;
119         WriteBarrier<Structure> m_arrayStructure;
120         WriteBarrier<Structure> m_booleanObjectStructure;
121         WriteBarrier<Structure> m_callbackConstructorStructure;
122         WriteBarrier<Structure> m_callbackFunctionStructure;
123         WriteBarrier<Structure> m_callbackObjectStructure;
124         WriteBarrier<Structure> m_dateStructure;
125         WriteBarrier<Structure> m_emptyObjectStructure;
126         WriteBarrier<Structure> m_nullPrototypeObjectStructure;
127         WriteBarrier<Structure> m_errorStructure;
128         WriteBarrier<Structure> m_functionStructure;
129         WriteBarrier<Structure> m_boundFunctionStructure;
130         WriteBarrier<Structure> m_namedFunctionStructure;
131         size_t m_functionNameOffset;
132         WriteBarrier<Structure> m_numberObjectStructure;
133         WriteBarrier<Structure> m_privateNameStructure;
134         WriteBarrier<Structure> m_regExpMatchesArrayStructure;
135         WriteBarrier<Structure> m_regExpStructure;
136         WriteBarrier<Structure> m_stringObjectStructure;
137         WriteBarrier<Structure> m_internalFunctionStructure;
138
139         Debugger* m_debugger;
140
141         OwnPtr<JSGlobalObjectRareData> m_rareData;
142
143         WeakRandom m_weakRandom;
144
145         SymbolTable m_symbolTable;
146
147         bool m_evalEnabled;
148
149         static JS_EXPORTDATA const GlobalObjectMethodTable s_globalObjectMethodTable;
150         const GlobalObjectMethodTable* m_globalObjectMethodTable;
151
152         void createRareDataIfNeeded()
153         {
154             if (m_rareData)
155                 return;
156             m_rareData = adoptPtr(new JSGlobalObjectRareData);
157             Heap::heap(this)->addFinalizer(this, clearRareData);
158         }
159         
160     public:
161         typedef JSVariableObject Base;
162
163         static JSGlobalObject* create(JSGlobalData& globalData, Structure* structure)
164         {
165             JSGlobalObject* globalObject = new (NotNull, allocateCell<JSGlobalObject>(globalData.heap)) JSGlobalObject(globalData, structure);
166             globalObject->finishCreation(globalData);
167             return globalObject;
168         }
169
170         static JS_EXPORTDATA const ClassInfo s_info;
171
172     protected:
173         explicit JSGlobalObject(JSGlobalData& globalData, Structure* structure, const GlobalObjectMethodTable* globalObjectMethodTable = 0)
174             : JSVariableObject(globalData, structure, &m_symbolTable, 0)
175             , m_registerArraySize(0)
176             , m_globalScopeChain()
177             , m_weakRandom(static_cast<unsigned>(randomNumber() * (std::numeric_limits<unsigned>::max() + 1.0)))
178             , m_evalEnabled(true)
179             , m_globalObjectMethodTable(globalObjectMethodTable ? globalObjectMethodTable : &s_globalObjectMethodTable)
180         {
181         }
182
183         void finishCreation(JSGlobalData& globalData)
184         {
185             Base::finishCreation(globalData);
186             structure()->setGlobalObject(globalData, this);
187             init(this);
188         }
189
190         void finishCreation(JSGlobalData& globalData, JSGlobalThis* thisValue)
191         {
192             Base::finishCreation(globalData);
193             structure()->setGlobalObject(globalData, this);
194             init(thisValue);
195         }
196
197     public:
198         JS_EXPORT_PRIVATE ~JSGlobalObject();
199         JS_EXPORT_PRIVATE static void destroy(JSCell*);
200
201         JS_EXPORT_PRIVATE static void visitChildren(JSCell*, SlotVisitor&);
202
203         JS_EXPORT_PRIVATE static bool getOwnPropertySlot(JSCell*, ExecState*, PropertyName, PropertySlot&);
204         JS_EXPORT_PRIVATE static bool getOwnPropertyDescriptor(JSObject*, ExecState*, PropertyName, PropertyDescriptor&);
205         bool hasOwnPropertyForWrite(ExecState*, PropertyName);
206         JS_EXPORT_PRIVATE static void put(JSCell*, ExecState*, PropertyName, JSValue, PutPropertySlot&);
207
208         JS_EXPORT_PRIVATE static void putDirectVirtual(JSObject*, ExecState*, PropertyName, JSValue, unsigned attributes);
209
210         JS_EXPORT_PRIVATE static void defineGetter(JSObject*, ExecState*, PropertyName, JSObject* getterFunc, unsigned attributes);
211         JS_EXPORT_PRIVATE static void defineSetter(JSObject*, ExecState*, PropertyName, JSObject* setterFunc, unsigned attributes);
212         JS_EXPORT_PRIVATE static bool defineOwnProperty(JSObject*, ExecState*, PropertyName, PropertyDescriptor&, bool shouldThrow);
213
214         // We use this in the code generator as we perform symbol table
215         // lookups prior to initializing the properties
216         bool symbolTableHasProperty(PropertyName);
217
218         // The following accessors return pristine values, even if a script 
219         // replaces the global object's associated property.
220
221         RegExpConstructor* regExpConstructor() const { return m_regExpConstructor.get(); }
222
223         ErrorConstructor* errorConstructor() const { return m_errorConstructor.get(); }
224         NativeErrorConstructor* evalErrorConstructor() const { return m_evalErrorConstructor.get(); }
225         NativeErrorConstructor* rangeErrorConstructor() const { return m_rangeErrorConstructor.get(); }
226         NativeErrorConstructor* referenceErrorConstructor() const { return m_referenceErrorConstructor.get(); }
227         NativeErrorConstructor* syntaxErrorConstructor() const { return m_syntaxErrorConstructor.get(); }
228         NativeErrorConstructor* typeErrorConstructor() const { return m_typeErrorConstructor.get(); }
229         NativeErrorConstructor* URIErrorConstructor() const { return m_URIErrorConstructor.get(); }
230
231         JSFunction* evalFunction() const { return m_evalFunction.get(); }
232         JSFunction* callFunction() const { return m_callFunction.get(); }
233         JSFunction* applyFunction() const { return m_applyFunction.get(); }
234         GetterSetter* throwTypeErrorGetterSetter(ExecState* exec)
235         {
236             if (!m_throwTypeErrorGetterSetter)
237                 createThrowTypeError(exec);
238             return m_throwTypeErrorGetterSetter.get();
239         }
240
241         ObjectPrototype* objectPrototype() const { return m_objectPrototype.get(); }
242         FunctionPrototype* functionPrototype() const { return m_functionPrototype.get(); }
243         ArrayPrototype* arrayPrototype() const { return m_arrayPrototype.get(); }
244         BooleanPrototype* booleanPrototype() const { return m_booleanPrototype.get(); }
245         StringPrototype* stringPrototype() const { return m_stringPrototype.get(); }
246         NumberPrototype* numberPrototype() const { return m_numberPrototype.get(); }
247         DatePrototype* datePrototype() const { return m_datePrototype.get(); }
248         RegExpPrototype* regExpPrototype() const { return m_regExpPrototype.get(); }
249
250         JSObject* methodCallDummy() const { return m_methodCallDummy.get(); }
251
252         Structure* argumentsStructure() const { return m_argumentsStructure.get(); }
253         Structure* arrayStructure() const { return m_arrayStructure.get(); }
254         Structure* booleanObjectStructure() const { return m_booleanObjectStructure.get(); }
255         Structure* callbackConstructorStructure() const { return m_callbackConstructorStructure.get(); }
256         Structure* callbackFunctionStructure() const { return m_callbackFunctionStructure.get(); }
257         Structure* callbackObjectStructure() const { return m_callbackObjectStructure.get(); }
258         Structure* dateStructure() const { return m_dateStructure.get(); }
259         Structure* emptyObjectStructure() const { return m_emptyObjectStructure.get(); }
260         Structure* nullPrototypeObjectStructure() const { return m_nullPrototypeObjectStructure.get(); }
261         Structure* errorStructure() const { return m_errorStructure.get(); }
262         Structure* functionStructure() const { return m_functionStructure.get(); }
263         Structure* boundFunctionStructure() const { return m_boundFunctionStructure.get(); }
264         Structure* namedFunctionStructure() const { return m_namedFunctionStructure.get(); }
265         size_t functionNameOffset() const { return m_functionNameOffset; }
266         Structure* numberObjectStructure() const { return m_numberObjectStructure.get(); }
267         Structure* privateNameStructure() const { return m_privateNameStructure.get(); }
268         Structure* internalFunctionStructure() const { return m_internalFunctionStructure.get(); }
269         Structure* regExpMatchesArrayStructure() const { return m_regExpMatchesArrayStructure.get(); }
270         Structure* regExpStructure() const { return m_regExpStructure.get(); }
271         Structure* stringObjectStructure() const { return m_stringObjectStructure.get(); }
272
273         void setProfileGroup(unsigned value) { createRareDataIfNeeded(); m_rareData->profileGroup = value; }
274         unsigned profileGroup() const
275         { 
276             if (!m_rareData)
277                 return 0;
278             return m_rareData->profileGroup;
279         }
280
281         Debugger* debugger() const { return m_debugger; }
282         void setDebugger(Debugger* debugger) { m_debugger = debugger; }
283
284         const GlobalObjectMethodTable* globalObjectMethodTable() const { return m_globalObjectMethodTable; }
285
286         static bool allowsAccessFrom(const JSGlobalObject*, ExecState*) { return true; }
287         static bool supportsProfiling(const JSGlobalObject*) { return false; }
288         static bool supportsRichSourceInfo(const JSGlobalObject*) { return true; }
289
290         ScopeChainNode* globalScopeChain() { return m_globalScopeChain.get(); }
291
292         JS_EXPORT_PRIVATE ExecState* globalExec();
293
294         static bool shouldInterruptScript(const JSGlobalObject*) { return true; }
295
296         bool isDynamicScope(bool& requiresDynamicChecks) const;
297
298         void setEvalEnabled(bool enabled) { m_evalEnabled = enabled; }
299         bool evalEnabled() { return m_evalEnabled; }
300
301         void resizeRegisters(size_t newSize);
302
303         void resetPrototype(JSGlobalData&, JSValue prototype);
304
305         JSGlobalData& globalData() const { return *Heap::heap(this)->globalData(); }
306
307         static Structure* createStructure(JSGlobalData& globalData, JSValue prototype)
308         {
309             return Structure::create(globalData, 0, prototype, TypeInfo(GlobalObjectType, StructureFlags), &s_info);
310         }
311
312         void registerWeakMap(OpaqueJSWeakObjectMap* map)
313         {
314             createRareDataIfNeeded();
315             m_rareData->weakMaps.add(map);
316         }
317
318         void unregisterWeakMap(OpaqueJSWeakObjectMap* map)
319         {
320             if (m_rareData)
321                 m_rareData->weakMaps.remove(map);
322         }
323
324         double weakRandomNumber() { return m_weakRandom.get(); }
325     protected:
326
327         static const unsigned StructureFlags = OverridesGetOwnPropertySlot | OverridesVisitChildren | OverridesGetPropertyNames | JSVariableObject::StructureFlags;
328
329         struct GlobalPropertyInfo {
330             GlobalPropertyInfo(const Identifier& i, JSValue v, unsigned a)
331                 : identifier(i)
332                 , value(v)
333                 , attributes(a)
334             {
335             }
336
337             const Identifier identifier;
338             JSValue value;
339             unsigned attributes;
340         };
341         JS_EXPORT_PRIVATE void addStaticGlobals(GlobalPropertyInfo*, int count);
342
343     private:
344         friend class LLIntOffsetsExtractor;
345         
346         // FIXME: Fold reset into init.
347         JS_EXPORT_PRIVATE void init(JSObject* thisValue);
348         void reset(JSValue prototype);
349
350         void createThrowTypeError(ExecState*);
351
352         void setRegisters(WriteBarrier<Unknown>* registers, PassOwnArrayPtr<WriteBarrier<Unknown> > registerArray, size_t count);
353         JS_EXPORT_PRIVATE static void clearRareData(JSCell*);
354     };
355
356     JSGlobalObject* asGlobalObject(JSValue);
357
358     inline JSGlobalObject* asGlobalObject(JSValue value)
359     {
360         ASSERT(asObject(value)->isGlobalObject());
361         return jsCast<JSGlobalObject*>(asObject(value));
362     }
363
364     inline void JSGlobalObject::setRegisters(WriteBarrier<Unknown>* registers, PassOwnArrayPtr<WriteBarrier<Unknown> > registerArray, size_t count)
365     {
366         JSVariableObject::setRegisters(registers, registerArray);
367         m_registerArraySize = count;
368     }
369
370     inline bool JSGlobalObject::hasOwnPropertyForWrite(ExecState* exec, PropertyName propertyName)
371     {
372         PropertySlot slot;
373         if (JSVariableObject::getOwnPropertySlot(this, exec, propertyName, slot))
374             return true;
375         bool slotIsWriteable;
376         return symbolTableGet(propertyName, slot, slotIsWriteable);
377     }
378
379     inline bool JSGlobalObject::symbolTableHasProperty(PropertyName propertyName)
380     {
381         SymbolTableEntry entry = symbolTable().inlineGet(propertyName.publicName());
382         return !entry.isNull();
383     }
384
385     inline JSValue Structure::prototypeForLookup(ExecState* exec) const
386     {
387         if (isObject())
388             return m_prototype.get();
389
390         ASSERT(typeInfo().type() == StringType);
391         return exec->lexicalGlobalObject()->stringPrototype();
392     }
393
394     inline StructureChain* Structure::prototypeChain(ExecState* exec) const
395     {
396         // We cache our prototype chain so our clients can share it.
397         if (!isValid(exec, m_cachedPrototypeChain.get())) {
398             JSValue prototype = prototypeForLookup(exec);
399             m_cachedPrototypeChain.set(exec->globalData(), this, StructureChain::create(exec->globalData(), prototype.isNull() ? 0 : asObject(prototype)->structure()));
400         }
401         return m_cachedPrototypeChain.get();
402     }
403
404     inline bool Structure::isValid(ExecState* exec, StructureChain* cachedPrototypeChain) const
405     {
406         if (!cachedPrototypeChain)
407             return false;
408
409         JSValue prototype = prototypeForLookup(exec);
410         WriteBarrier<Structure>* cachedStructure = cachedPrototypeChain->head();
411         while(*cachedStructure && !prototype.isNull()) {
412             if (asObject(prototype)->structure() != cachedStructure->get())
413                 return false;
414             ++cachedStructure;
415             prototype = asObject(prototype)->prototype();
416         }
417         return prototype.isNull() && !*cachedStructure;
418     }
419
420     inline JSGlobalObject* ExecState::dynamicGlobalObject()
421     {
422         if (this == lexicalGlobalObject()->globalExec())
423             return lexicalGlobalObject();
424
425         // For any ExecState that's not a globalExec, the 
426         // dynamic global object must be set since code is running
427         ASSERT(globalData().dynamicGlobalObject);
428         return globalData().dynamicGlobalObject;
429     }
430
431     inline JSObject* constructEmptyObject(ExecState* exec, JSGlobalObject* globalObject)
432     {
433         return constructEmptyObject(exec, globalObject->emptyObjectStructure());
434     }
435
436     inline JSObject* constructEmptyObject(ExecState* exec)
437     {
438         return constructEmptyObject(exec, exec->lexicalGlobalObject());
439     }
440
441     inline JSArray* constructEmptyArray(ExecState* exec, JSGlobalObject* globalObject, unsigned initialLength = 0)
442     {
443         return JSArray::create(exec->globalData(), globalObject->arrayStructure(), initialLength);
444     }
445
446     inline JSArray* constructEmptyArray(ExecState* exec, unsigned initialLength = 0)
447     {
448         return constructEmptyArray(exec, exec->lexicalGlobalObject(), initialLength);
449     }
450
451     inline JSArray* constructArray(ExecState* exec, JSGlobalObject* globalObject, const ArgList& values)
452     {
453         JSGlobalData& globalData = exec->globalData();
454         unsigned length = values.size();
455         JSArray* array = JSArray::tryCreateUninitialized(globalData, globalObject->arrayStructure(), length);
456
457         // FIXME: we should probably throw an out of memory error here, but
458         // when making this change we should check that all clients of this
459         // function will correctly handle an exception being thrown from here.
460         if (!array)
461             CRASH();
462
463         for (unsigned i = 0; i < length; ++i)
464             array->initializeIndex(globalData, i, values.at(i));
465         array->completeInitialization(length);
466         return array;
467     }
468
469     inline JSArray* constructArray(ExecState* exec, const ArgList& values)
470     {
471         return constructArray(exec, exec->lexicalGlobalObject(), values);
472     }
473
474     inline JSArray* constructArray(ExecState* exec, JSGlobalObject* globalObject, const JSValue* values, unsigned length)
475     {
476         JSGlobalData& globalData = exec->globalData();
477         JSArray* array = JSArray::tryCreateUninitialized(globalData, globalObject->arrayStructure(), length);
478
479         // FIXME: we should probably throw an out of memory error here, but
480         // when making this change we should check that all clients of this
481         // function will correctly handle an exception being thrown from here.
482         if (!array)
483             CRASH();
484
485         for (unsigned i = 0; i < length; ++i)
486             array->initializeIndex(globalData, i, values[i]);
487         array->completeInitialization(length);
488         return array;
489     }
490
491     inline JSArray* constructArray(ExecState* exec, const JSValue* values, unsigned length)
492     {
493         return constructArray(exec, exec->lexicalGlobalObject(), values, length);
494     }
495
496     class DynamicGlobalObjectScope {
497         WTF_MAKE_NONCOPYABLE(DynamicGlobalObjectScope);
498     public:
499         JS_EXPORT_PRIVATE DynamicGlobalObjectScope(JSGlobalData&, JSGlobalObject*);
500
501         ~DynamicGlobalObjectScope()
502         {
503             m_dynamicGlobalObjectSlot = m_savedDynamicGlobalObject;
504         }
505
506     private:
507         JSGlobalObject*& m_dynamicGlobalObjectSlot;
508         JSGlobalObject* m_savedDynamicGlobalObject;
509     };
510
511     inline bool JSGlobalObject::isDynamicScope(bool&) const
512     {
513         return true;
514     }
515
516 } // namespace JSC
517
518 #endif // JSGlobalObject_h