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