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 <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 JSGlobalObjectDataJSGlobalObjectData68 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 JSGlobalObject()161 explicit JSGlobalObject() 162 : JSVariableObject(JSGlobalObject::createStructure(jsNull()), new JSGlobalObjectData(destroyJSGlobalObjectData)) 163 { 164 init(this); 165 } 166 167 protected: JSGlobalObject(NonNullPassRefPtr<Structure> structure,JSGlobalObjectData * data,JSObject * thisValue)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. head()189 JSGlobalObject*& head() { return d()->globalData->head; } next()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 regExpConstructor()195 RegExpConstructor* regExpConstructor() const { return d()->regExpConstructor; } 196 errorConstructor()197 ErrorConstructor* errorConstructor() const { return d()->errorConstructor; } evalErrorConstructor()198 NativeErrorConstructor* evalErrorConstructor() const { return d()->evalErrorConstructor; } rangeErrorConstructor()199 NativeErrorConstructor* rangeErrorConstructor() const { return d()->rangeErrorConstructor; } referenceErrorConstructor()200 NativeErrorConstructor* referenceErrorConstructor() const { return d()->referenceErrorConstructor; } syntaxErrorConstructor()201 NativeErrorConstructor* syntaxErrorConstructor() const { return d()->syntaxErrorConstructor; } typeErrorConstructor()202 NativeErrorConstructor* typeErrorConstructor() const { return d()->typeErrorConstructor; } URIErrorConstructor()203 NativeErrorConstructor* URIErrorConstructor() const { return d()->URIErrorConstructor; } 204 evalFunction()205 GlobalEvalFunction* evalFunction() const { return d()->evalFunction; } 206 objectPrototype()207 ObjectPrototype* objectPrototype() const { return d()->objectPrototype; } functionPrototype()208 FunctionPrototype* functionPrototype() const { return d()->functionPrototype; } arrayPrototype()209 ArrayPrototype* arrayPrototype() const { return d()->arrayPrototype; } booleanPrototype()210 BooleanPrototype* booleanPrototype() const { return d()->booleanPrototype; } stringPrototype()211 StringPrototype* stringPrototype() const { return d()->stringPrototype; } numberPrototype()212 NumberPrototype* numberPrototype() const { return d()->numberPrototype; } datePrototype()213 DatePrototype* datePrototype() const { return d()->datePrototype; } regExpPrototype()214 RegExpPrototype* regExpPrototype() const { return d()->regExpPrototype; } 215 methodCallDummy()216 JSObject* methodCallDummy() const { return d()->methodCallDummy; } 217 argumentsStructure()218 Structure* argumentsStructure() const { return d()->argumentsStructure.get(); } arrayStructure()219 Structure* arrayStructure() const { return d()->arrayStructure.get(); } booleanObjectStructure()220 Structure* booleanObjectStructure() const { return d()->booleanObjectStructure.get(); } callbackConstructorStructure()221 Structure* callbackConstructorStructure() const { return d()->callbackConstructorStructure.get(); } callbackFunctionStructure()222 Structure* callbackFunctionStructure() const { return d()->callbackFunctionStructure.get(); } callbackObjectStructure()223 Structure* callbackObjectStructure() const { return d()->callbackObjectStructure.get(); } dateStructure()224 Structure* dateStructure() const { return d()->dateStructure.get(); } emptyObjectStructure()225 Structure* emptyObjectStructure() const { return d()->emptyObjectStructure.get(); } errorStructure()226 Structure* errorStructure() const { return d()->errorStructure.get(); } functionStructure()227 Structure* functionStructure() const { return d()->functionStructure.get(); } numberObjectStructure()228 Structure* numberObjectStructure() const { return d()->numberObjectStructure.get(); } prototypeFunctionStructure()229 Structure* prototypeFunctionStructure() const { return d()->prototypeFunctionStructure.get(); } regExpMatchesArrayStructure()230 Structure* regExpMatchesArrayStructure() const { return d()->regExpMatchesArrayStructure.get(); } regExpStructure()231 Structure* regExpStructure() const { return d()->regExpStructure.get(); } stringObjectStructure()232 Structure* stringObjectStructure() const { return d()->stringObjectStructure.get(); } 233 setProfileGroup(unsigned value)234 void setProfileGroup(unsigned value) { d()->profileGroup = value; } profileGroup()235 unsigned profileGroup() const { return d()->profileGroup; } 236 debugger()237 Debugger* debugger() const { return d()->debugger; } setDebugger(Debugger * debugger)238 void setDebugger(Debugger* debugger) { d()->debugger = debugger; } 239 supportsProfiling()240 virtual bool supportsProfiling() const { return false; } 241 recursion()242 int recursion() { return d()->recursion; } incRecursion()243 void incRecursion() { ++d()->recursion; } decRecursion()244 void decRecursion() { --d()->recursion; } 245 globalScopeChain()246 ScopeChain& globalScopeChain() { return d()->globalScopeChain; } 247 isGlobalObject()248 virtual bool isGlobalObject() const { return true; } 249 250 virtual ExecState* globalExec(); 251 shouldInterruptScript()252 virtual bool shouldInterruptScript() const { return true; } 253 allowsAccessFrom(const JSGlobalObject *)254 virtual bool allowsAccessFrom(const JSGlobalObject*) const { return true; } 255 256 virtual bool isDynamicScope() const; 257 codeBlocks()258 HashSet<GlobalCodeBlock*>& codeBlocks() { return d()->codeBlocks; } 259 260 void copyGlobalsFrom(RegisterFile&); 261 void copyGlobalsTo(RegisterFile&); 262 263 void resetPrototype(JSValue prototype); 264 globalData()265 JSGlobalData* globalData() { return d()->globalData.get(); } d()266 JSGlobalObjectData* d() const { return static_cast<JSGlobalObjectData*>(JSVariableObject::d); } 267 createStructure(JSValue prototype)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 { GlobalPropertyInfoGlobalPropertyInfo278 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 asGlobalObject(JSValue value)305 inline JSGlobalObject* asGlobalObject(JSValue value) 306 { 307 ASSERT(asObject(value)->isGlobalObject()); 308 return static_cast<JSGlobalObject*>(asObject(value)); 309 } 310 setRegisters(Register * registers,Register * registerArray,size_t count)311 inline void JSGlobalObject::setRegisters(Register* registers, Register* registerArray, size_t count) 312 { 313 JSVariableObject::setRegisters(registers, registerArray); 314 d()->registerArraySize = count; 315 } 316 addStaticGlobals(GlobalPropertyInfo * globals,int count)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 getOwnPropertySlot(ExecState * exec,const Identifier & propertyName,PropertySlot & slot)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 getOwnPropertyDescriptor(ExecState * exec,const Identifier & propertyName,PropertyDescriptor & descriptor)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 hasOwnPropertyForWrite(ExecState * exec,const Identifier & propertyName)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 prototypeForLookup(ExecState * exec)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 prototypeChain(ExecState * exec)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 isValid(ExecState * exec,StructureChain * cachedPrototypeChain)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 dynamicGlobalObject()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 constructEmptyObject(ExecState * exec)412 inline JSObject* constructEmptyObject(ExecState* exec) 413 { 414 return new (exec) JSObject(exec->lexicalGlobalObject()->emptyObjectStructure()); 415 } 416 constructEmptyObject(ExecState * exec,JSGlobalObject * globalObject)417 inline JSObject* constructEmptyObject(ExecState* exec, JSGlobalObject* globalObject) 418 { 419 return new (exec) JSObject(globalObject->emptyObjectStructure()); 420 } 421 constructEmptyArray(ExecState * exec)422 inline JSArray* constructEmptyArray(ExecState* exec) 423 { 424 return new (exec) JSArray(exec->lexicalGlobalObject()->arrayStructure()); 425 } 426 constructEmptyArray(ExecState * exec,JSGlobalObject * globalObject)427 inline JSArray* constructEmptyArray(ExecState* exec, JSGlobalObject* globalObject) 428 { 429 return new (exec) JSArray(globalObject->arrayStructure()); 430 } 431 constructEmptyArray(ExecState * exec,unsigned initialLength)432 inline JSArray* constructEmptyArray(ExecState* exec, unsigned initialLength) 433 { 434 return new (exec) JSArray(exec->lexicalGlobalObject()->arrayStructure(), initialLength); 435 } 436 constructArray(ExecState * exec,JSValue singleItemValue)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 constructArray(ExecState * exec,const ArgList & values)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: DynamicGlobalObjectScope(CallFrame * callFrame,JSGlobalObject * dynamicGlobalObject)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 ~DynamicGlobalObjectScope()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