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 "JSGlobalData.h" 26 #include "JSVariableObject.h" 27 #include "NativeFunctionWrapper.h" 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; 44 class PrototypeFunction; 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 { JSGlobalObjectDataJSGlobalObjectData59 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) 72 , callFunction(0) 73 , applyFunction(0) 74 , objectPrototype(0) 75 , functionPrototype(0) 76 , arrayPrototype(0) 77 , booleanPrototype(0) 78 , stringPrototype(0) 79 , numberPrototype(0) 80 , datePrototype(0) 81 , regExpPrototype(0) 82 , methodCallDummy(0) 83 { 84 } 85 ~JSGlobalObjectDataJSGlobalObjectData86 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; 112 NativeFunctionWrapper* callFunction; 113 NativeFunctionWrapper* applyFunction; 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 124 JSObject* methodCallDummy; 125 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 JSGlobalObject()153 explicit JSGlobalObject() 154 : JSVariableObject(JSGlobalObject::createStructure(jsNull()), new JSGlobalObjectData) 155 { 156 init(this); 157 } 158 159 protected: JSGlobalObject(PassRefPtr<Structure> structure,JSGlobalObjectData * data,JSObject * thisValue)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 markChildren(MarkStack&); 170 171 virtual bool getOwnPropertySlot(ExecState*, const Identifier&, PropertySlot&); 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); 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. head()180 JSGlobalObject*& head() { return d()->globalData->head; } next()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 regExpConstructor()186 RegExpConstructor* regExpConstructor() const { return d()->regExpConstructor; } 187 errorConstructor()188 ErrorConstructor* errorConstructor() const { return d()->errorConstructor; } evalErrorConstructor()189 NativeErrorConstructor* evalErrorConstructor() const { return d()->evalErrorConstructor; } rangeErrorConstructor()190 NativeErrorConstructor* rangeErrorConstructor() const { return d()->rangeErrorConstructor; } referenceErrorConstructor()191 NativeErrorConstructor* referenceErrorConstructor() const { return d()->referenceErrorConstructor; } syntaxErrorConstructor()192 NativeErrorConstructor* syntaxErrorConstructor() const { return d()->syntaxErrorConstructor; } typeErrorConstructor()193 NativeErrorConstructor* typeErrorConstructor() const { return d()->typeErrorConstructor; } URIErrorConstructor()194 NativeErrorConstructor* URIErrorConstructor() const { return d()->URIErrorConstructor; } 195 evalFunction()196 GlobalEvalFunction* evalFunction() const { return d()->evalFunction; } 197 objectPrototype()198 ObjectPrototype* objectPrototype() const { return d()->objectPrototype; } functionPrototype()199 FunctionPrototype* functionPrototype() const { return d()->functionPrototype; } arrayPrototype()200 ArrayPrototype* arrayPrototype() const { return d()->arrayPrototype; } booleanPrototype()201 BooleanPrototype* booleanPrototype() const { return d()->booleanPrototype; } stringPrototype()202 StringPrototype* stringPrototype() const { return d()->stringPrototype; } numberPrototype()203 NumberPrototype* numberPrototype() const { return d()->numberPrototype; } datePrototype()204 DatePrototype* datePrototype() const { return d()->datePrototype; } regExpPrototype()205 RegExpPrototype* regExpPrototype() const { return d()->regExpPrototype; } 206 methodCallDummy()207 JSObject* methodCallDummy() const { return d()->methodCallDummy; } 208 argumentsStructure()209 Structure* argumentsStructure() const { return d()->argumentsStructure.get(); } arrayStructure()210 Structure* arrayStructure() const { return d()->arrayStructure.get(); } booleanObjectStructure()211 Structure* booleanObjectStructure() const { return d()->booleanObjectStructure.get(); } callbackConstructorStructure()212 Structure* callbackConstructorStructure() const { return d()->callbackConstructorStructure.get(); } callbackFunctionStructure()213 Structure* callbackFunctionStructure() const { return d()->callbackFunctionStructure.get(); } callbackObjectStructure()214 Structure* callbackObjectStructure() const { return d()->callbackObjectStructure.get(); } dateStructure()215 Structure* dateStructure() const { return d()->dateStructure.get(); } emptyObjectStructure()216 Structure* emptyObjectStructure() const { return d()->emptyObjectStructure.get(); } errorStructure()217 Structure* errorStructure() const { return d()->errorStructure.get(); } functionStructure()218 Structure* functionStructure() const { return d()->functionStructure.get(); } numberObjectStructure()219 Structure* numberObjectStructure() const { return d()->numberObjectStructure.get(); } prototypeFunctionStructure()220 Structure* prototypeFunctionStructure() const { return d()->prototypeFunctionStructure.get(); } regExpMatchesArrayStructure()221 Structure* regExpMatchesArrayStructure() const { return d()->regExpMatchesArrayStructure.get(); } regExpStructure()222 Structure* regExpStructure() const { return d()->regExpStructure.get(); } stringObjectStructure()223 Structure* stringObjectStructure() const { return d()->stringObjectStructure.get(); } 224 setProfileGroup(unsigned value)225 void setProfileGroup(unsigned value) { d()->profileGroup = value; } profileGroup()226 unsigned profileGroup() const { return d()->profileGroup; } 227 debugger()228 Debugger* debugger() const { return d()->debugger; } setDebugger(Debugger * debugger)229 void setDebugger(Debugger* debugger) { d()->debugger = debugger; } 230 supportsProfiling()231 virtual bool supportsProfiling() const { return false; } 232 recursion()233 int recursion() { return d()->recursion; } incRecursion()234 void incRecursion() { ++d()->recursion; } decRecursion()235 void decRecursion() { --d()->recursion; } 236 globalScopeChain()237 ScopeChain& globalScopeChain() { return d()->globalScopeChain; } 238 isGlobalObject()239 virtual bool isGlobalObject() const { return true; } 240 241 virtual ExecState* globalExec(); 242 shouldInterruptScript()243 virtual bool shouldInterruptScript() const { return true; } 244 allowsAccessFrom(const JSGlobalObject *)245 virtual bool allowsAccessFrom(const JSGlobalObject*) const { return true; } 246 247 virtual bool isDynamicScope() const; 248 codeBlocks()249 HashSet<ProgramCodeBlock*>& codeBlocks() { return d()->codeBlocks; } 250 251 void copyGlobalsFrom(RegisterFile&); 252 void copyGlobalsTo(RegisterFile&); 253 254 void resetPrototype(JSValue prototype); 255 globalData()256 JSGlobalData* globalData() { return d()->globalData.get(); } d()257 JSGlobalObjectData* d() const { return static_cast<JSGlobalObjectData*>(JSVariableObject::d); } 258 createStructure(JSValue prototype)259 static PassRefPtr<Structure> createStructure(JSValue prototype) 260 { 261 return Structure::create(prototype, TypeInfo(ObjectType)); 262 } 263 264 protected: 265 struct GlobalPropertyInfo { GlobalPropertyInfoGlobalPropertyInfo266 GlobalPropertyInfo(const Identifier& i, JSValue v, unsigned a) 267 : identifier(i) 268 , value(v) 269 , attributes(a) 270 { 271 } 272 273 const Identifier identifier; 274 JSValue value; 275 unsigned attributes; 276 }; 277 void addStaticGlobals(GlobalPropertyInfo*, int count); 278 279 private: 280 // FIXME: Fold reset into init. 281 void init(JSObject* thisValue); 282 void reset(JSValue prototype); 283 284 void setRegisters(Register* registers, Register* registerArray, size_t count); 285 286 void* operator new(size_t); // can only be allocated with JSGlobalData 287 }; 288 289 JSGlobalObject* asGlobalObject(JSValue); 290 asGlobalObject(JSValue value)291 inline JSGlobalObject* asGlobalObject(JSValue value) 292 { 293 ASSERT(asObject(value)->isGlobalObject()); 294 return static_cast<JSGlobalObject*>(asObject(value)); 295 } 296 setRegisters(Register * registers,Register * registerArray,size_t count)297 inline void JSGlobalObject::setRegisters(Register* registers, Register* registerArray, size_t count) 298 { 299 JSVariableObject::setRegisters(registers, registerArray); 300 d()->registerArraySize = count; 301 } 302 addStaticGlobals(GlobalPropertyInfo * globals,int count)303 inline void JSGlobalObject::addStaticGlobals(GlobalPropertyInfo* globals, int count) 304 { 305 size_t oldSize = d()->registerArraySize; 306 size_t newSize = oldSize + count; 307 Register* registerArray = new Register[newSize]; 308 if (d()->registerArray) 309 memcpy(registerArray + count, d()->registerArray.get(), oldSize * sizeof(Register)); 310 setRegisters(registerArray + newSize, registerArray, newSize); 311 312 for (int i = 0, index = -static_cast<int>(oldSize) - 1; i < count; ++i, --index) { 313 GlobalPropertyInfo& global = globals[i]; 314 ASSERT(global.attributes & DontDelete); 315 SymbolTableEntry newEntry(index, global.attributes); 316 symbolTable().add(global.identifier.ustring().rep(), newEntry); 317 registerAt(index) = global.value; 318 } 319 } 320 getOwnPropertySlot(ExecState * exec,const Identifier & propertyName,PropertySlot & slot)321 inline bool JSGlobalObject::getOwnPropertySlot(ExecState* exec, const Identifier& propertyName, PropertySlot& slot) 322 { 323 if (JSVariableObject::getOwnPropertySlot(exec, propertyName, slot)) 324 return true; 325 return symbolTableGet(propertyName, slot); 326 } 327 hasOwnPropertyForWrite(ExecState * exec,const Identifier & propertyName)328 inline bool JSGlobalObject::hasOwnPropertyForWrite(ExecState* exec, const Identifier& propertyName) 329 { 330 PropertySlot slot; 331 if (JSVariableObject::getOwnPropertySlot(exec, propertyName, slot)) 332 return true; 333 bool slotIsWriteable; 334 return symbolTableGet(propertyName, slot, slotIsWriteable); 335 } 336 globalObject()337 inline JSGlobalObject* ScopeChainNode::globalObject() const 338 { 339 const ScopeChainNode* n = this; 340 while (n->next) 341 n = n->next; 342 return asGlobalObject(n->object); 343 } 344 prototypeForLookup(ExecState * exec)345 inline JSValue Structure::prototypeForLookup(ExecState* exec) const 346 { 347 if (typeInfo().type() == ObjectType) 348 return m_prototype; 349 350 #if USE(JSVALUE32) 351 if (typeInfo().type() == StringType) 352 return exec->lexicalGlobalObject()->stringPrototype(); 353 354 ASSERT(typeInfo().type() == NumberType); 355 return exec->lexicalGlobalObject()->numberPrototype(); 356 #else 357 ASSERT(typeInfo().type() == StringType); 358 return exec->lexicalGlobalObject()->stringPrototype(); 359 #endif 360 } 361 prototypeChain(ExecState * exec)362 inline StructureChain* Structure::prototypeChain(ExecState* exec) const 363 { 364 // We cache our prototype chain so our clients can share it. 365 if (!isValid(exec, m_cachedPrototypeChain.get())) { 366 JSValue prototype = prototypeForLookup(exec); 367 m_cachedPrototypeChain = StructureChain::create(prototype.isNull() ? 0 : asObject(prototype)->structure()); 368 } 369 return m_cachedPrototypeChain.get(); 370 } 371 isValid(ExecState * exec,StructureChain * cachedPrototypeChain)372 inline bool Structure::isValid(ExecState* exec, StructureChain* cachedPrototypeChain) const 373 { 374 if (!cachedPrototypeChain) 375 return false; 376 377 JSValue prototype = prototypeForLookup(exec); 378 RefPtr<Structure>* cachedStructure = cachedPrototypeChain->head(); 379 while(*cachedStructure && !prototype.isNull()) { 380 if (asObject(prototype)->structure() != *cachedStructure) 381 return false; 382 ++cachedStructure; 383 prototype = asObject(prototype)->prototype(); 384 } 385 return prototype.isNull() && !*cachedStructure; 386 } 387 dynamicGlobalObject()388 inline JSGlobalObject* ExecState::dynamicGlobalObject() 389 { 390 if (this == lexicalGlobalObject()->globalExec()) 391 return lexicalGlobalObject(); 392 393 // For any ExecState that's not a globalExec, the 394 // dynamic global object must be set since code is running 395 ASSERT(globalData().dynamicGlobalObject); 396 return globalData().dynamicGlobalObject; 397 } 398 399 class DynamicGlobalObjectScope : public Noncopyable { 400 public: DynamicGlobalObjectScope(CallFrame * callFrame,JSGlobalObject * dynamicGlobalObject)401 DynamicGlobalObjectScope(CallFrame* callFrame, JSGlobalObject* dynamicGlobalObject) 402 : m_dynamicGlobalObjectSlot(callFrame->globalData().dynamicGlobalObject) 403 , m_savedDynamicGlobalObject(m_dynamicGlobalObjectSlot) 404 { 405 m_dynamicGlobalObjectSlot = dynamicGlobalObject; 406 } 407 ~DynamicGlobalObjectScope()408 ~DynamicGlobalObjectScope() 409 { 410 m_dynamicGlobalObjectSlot = m_savedDynamicGlobalObject; 411 } 412 413 private: 414 JSGlobalObject*& m_dynamicGlobalObjectSlot; 415 JSGlobalObject* m_savedDynamicGlobalObject; 416 }; 417 418 } // namespace JSC 419 420 #endif // JSGlobalObject_h 421