1 /* 2 * Copyright (C) 1999-2001 Harri Porten (porten@kde.org) 3 * Copyright (C) 2001 Peter Kelly (pmk@post.com) 4 * Copyright (C) 2003, 2004, 2005, 2007, 2008, 2009 Apple Inc. All rights reserved. 5 * 6 * This library is free software; you can redistribute it and/or 7 * modify it under the terms of the GNU Library General Public 8 * License as published by the Free Software Foundation; either 9 * version 2 of the License, or (at your option) any later version. 10 * 11 * This library is distributed in the hope that it will be useful, 12 * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 14 * Library General Public License for more details. 15 * 16 * You should have received a copy of the GNU Library General Public License 17 * along with this library; see the file COPYING.LIB. If not, write to 18 * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, 19 * Boston, MA 02110-1301, USA. 20 * 21 */ 22 23 #ifndef JSCell_h 24 #define JSCell_h 25 26 #include "CallData.h" 27 #include "CallFrame.h" 28 #include "ConstructData.h" 29 #include "Heap.h" 30 #include "JSLock.h" 31 #include "JSValueInlineMethods.h" 32 #include "MarkStack.h" 33 #include <wtf/Noncopyable.h> 34 35 namespace JSC { 36 37 class JSGlobalObject; 38 class Structure; 39 40 #if COMPILER(MSVC) 41 // If WTF_MAKE_NONCOPYABLE is applied to JSCell we end up with a bunch of 42 // undefined references to the JSCell copy constructor and assignment operator 43 // when linking JavaScriptCore. 44 class MSVCBugWorkaround { 45 WTF_MAKE_NONCOPYABLE(MSVCBugWorkaround); 46 47 protected: MSVCBugWorkaround()48 MSVCBugWorkaround() { } ~MSVCBugWorkaround()49 ~MSVCBugWorkaround() { } 50 }; 51 52 class JSCell : MSVCBugWorkaround { 53 #else 54 class JSCell { 55 WTF_MAKE_NONCOPYABLE(JSCell); 56 #endif 57 58 friend class ExecutableBase; 59 friend class GetterSetter; 60 friend class Heap; 61 friend class JSObject; 62 friend class JSPropertyNameIterator; 63 friend class JSString; 64 friend class JSValue; 65 friend class JSAPIValueWrapper; 66 friend class JSZombie; 67 friend class JSGlobalData; 68 friend class MarkedSpace; 69 friend class MarkedBlock; 70 friend class ScopeChainNode; 71 friend class Structure; 72 friend class StructureChain; 73 74 protected: 75 enum VPtrStealingHackType { VPtrStealingHack }; 76 77 private: JSCell(VPtrStealingHackType)78 explicit JSCell(VPtrStealingHackType) { } 79 JSCell(JSGlobalData&, Structure*); 80 virtual ~JSCell(); 81 82 public: 83 static Structure* createDummyStructure(JSGlobalData&); 84 85 // Querying the type. 86 bool isString() const; 87 bool isObject() const; 88 virtual bool isGetterSetter() const; 89 bool inherits(const ClassInfo*) const; isAPIValueWrapper()90 virtual bool isAPIValueWrapper() const { return false; } isPropertyNameIterator()91 virtual bool isPropertyNameIterator() const { return false; } 92 93 Structure* structure() const; 94 95 // Extracting the value. 96 bool getString(ExecState* exec, UString&) const; 97 UString getString(ExecState* exec) const; // null string if not a string 98 JSObject* getObject(); // NULL if not an object 99 const JSObject* getObject() const; // NULL if not an object 100 101 virtual CallType getCallData(CallData&); 102 virtual ConstructType getConstructData(ConstructData&); 103 104 // Extracting integer values. 105 // FIXME: remove these methods, can check isNumberCell in JSValue && then call asNumberCell::*. 106 virtual bool getUInt32(uint32_t&) const; 107 108 // Basic conversions. 109 virtual JSValue toPrimitive(ExecState*, PreferredPrimitiveType) const; 110 virtual bool getPrimitiveNumber(ExecState*, double& number, JSValue&); 111 virtual bool toBoolean(ExecState*) const; 112 virtual double toNumber(ExecState*) const; 113 virtual UString toString(ExecState*) const; 114 virtual JSObject* toObject(ExecState*, JSGlobalObject*) const; 115 116 // Garbage collection. 117 void* operator new(size_t, ExecState*); 118 void* operator new(size_t, JSGlobalData*); new(size_t,void * placementNewDestination)119 void* operator new(size_t, void* placementNewDestination) { return placementNewDestination; } 120 121 virtual void markChildren(MarkStack&); 122 #if ENABLE(JSC_ZOMBIES) isZombie()123 virtual bool isZombie() const { return false; } 124 #endif 125 126 // Object operations, with the toObject operation included. 127 const ClassInfo* classInfo() const; 128 virtual void put(ExecState*, const Identifier& propertyName, JSValue, PutPropertySlot&); 129 virtual void put(ExecState*, unsigned propertyName, JSValue); 130 virtual bool deleteProperty(ExecState*, const Identifier& propertyName); 131 virtual bool deleteProperty(ExecState*, unsigned propertyName); 132 133 virtual JSObject* toThisObject(ExecState*) const; 134 virtual JSValue getJSNumber(); vptr()135 void* vptr() { return *reinterpret_cast<void**>(this); } setVPtr(void * vptr)136 void setVPtr(void* vptr) { *reinterpret_cast<void**>(this) = vptr; } 137 138 // FIXME: Rename getOwnPropertySlot to virtualGetOwnPropertySlot, and 139 // fastGetOwnPropertySlot to getOwnPropertySlot. Callers should always 140 // call this function, not its slower virtual counterpart. (For integer 141 // property names, we want a similar interface with appropriate optimizations.) 142 bool fastGetOwnPropertySlot(ExecState*, const Identifier& propertyName, PropertySlot&); 143 structureOffset()144 static ptrdiff_t structureOffset() 145 { 146 return OBJECT_OFFSETOF(JSCell, m_structure); 147 } 148 addressOfStructure()149 const void* addressOfStructure() const 150 { 151 return &m_structure; 152 } 153 154 protected: 155 static const unsigned AnonymousSlotCount = 0; 156 157 private: 158 // Base implementation; for non-object classes implements getPropertySlot. 159 virtual bool getOwnPropertySlot(ExecState*, const Identifier& propertyName, PropertySlot&); 160 virtual bool getOwnPropertySlot(ExecState*, unsigned propertyName, PropertySlot&); 161 162 WriteBarrier<Structure> m_structure; 163 }; 164 JSCell(JSGlobalData & globalData,Structure * structure)165 inline JSCell::JSCell(JSGlobalData& globalData, Structure* structure) 166 : m_structure(globalData, this, structure) 167 { 168 // Very first set of allocations won't have a real structure. 169 ASSERT(m_structure || !globalData.dummyMarkableCellStructure); 170 } 171 ~JSCell()172 inline JSCell::~JSCell() 173 { 174 } 175 structure()176 inline Structure* JSCell::structure() const 177 { 178 return m_structure.get(); 179 } 180 markChildren(MarkStack & markStack)181 inline void JSCell::markChildren(MarkStack& markStack) 182 { 183 markStack.append(&m_structure); 184 } 185 186 // --- JSValue inlines ---------------------------- 187 isString()188 inline bool JSValue::isString() const 189 { 190 return isCell() && asCell()->isString(); 191 } 192 isGetterSetter()193 inline bool JSValue::isGetterSetter() const 194 { 195 return isCell() && asCell()->isGetterSetter(); 196 } 197 isObject()198 inline bool JSValue::isObject() const 199 { 200 return isCell() && asCell()->isObject(); 201 } 202 getString(ExecState * exec,UString & s)203 inline bool JSValue::getString(ExecState* exec, UString& s) const 204 { 205 return isCell() && asCell()->getString(exec, s); 206 } 207 getString(ExecState * exec)208 inline UString JSValue::getString(ExecState* exec) const 209 { 210 return isCell() ? asCell()->getString(exec) : UString(); 211 } 212 getString(ExecState * exec)213 template <typename Base> UString HandleConverter<Base, Unknown>::getString(ExecState* exec) const 214 { 215 return jsValue().getString(exec); 216 } 217 getObject()218 inline JSObject* JSValue::getObject() const 219 { 220 return isCell() ? asCell()->getObject() : 0; 221 } 222 getCallData(JSValue value,CallData & callData)223 inline CallType getCallData(JSValue value, CallData& callData) 224 { 225 CallType result = value.isCell() ? value.asCell()->getCallData(callData) : CallTypeNone; 226 ASSERT(result == CallTypeNone || value.isValidCallee()); 227 return result; 228 } 229 getConstructData(JSValue value,ConstructData & constructData)230 inline ConstructType getConstructData(JSValue value, ConstructData& constructData) 231 { 232 ConstructType result = value.isCell() ? value.asCell()->getConstructData(constructData) : ConstructTypeNone; 233 ASSERT(result == ConstructTypeNone || value.isValidCallee()); 234 return result; 235 } 236 getUInt32(uint32_t & v)237 ALWAYS_INLINE bool JSValue::getUInt32(uint32_t& v) const 238 { 239 if (isInt32()) { 240 int32_t i = asInt32(); 241 v = static_cast<uint32_t>(i); 242 return i >= 0; 243 } 244 if (isDouble()) { 245 double d = asDouble(); 246 v = static_cast<uint32_t>(d); 247 return v == d; 248 } 249 return false; 250 } 251 toPrimitive(ExecState * exec,PreferredPrimitiveType preferredType)252 inline JSValue JSValue::toPrimitive(ExecState* exec, PreferredPrimitiveType preferredType) const 253 { 254 return isCell() ? asCell()->toPrimitive(exec, preferredType) : asValue(); 255 } 256 getPrimitiveNumber(ExecState * exec,double & number,JSValue & value)257 inline bool JSValue::getPrimitiveNumber(ExecState* exec, double& number, JSValue& value) 258 { 259 if (isInt32()) { 260 number = asInt32(); 261 value = *this; 262 return true; 263 } 264 if (isDouble()) { 265 number = asDouble(); 266 value = *this; 267 return true; 268 } 269 if (isCell()) 270 return asCell()->getPrimitiveNumber(exec, number, value); 271 if (isTrue()) { 272 number = 1.0; 273 value = *this; 274 return true; 275 } 276 if (isFalse() || isNull()) { 277 number = 0.0; 278 value = *this; 279 return true; 280 } 281 ASSERT(isUndefined()); 282 number = nonInlineNaN(); 283 value = *this; 284 return true; 285 } 286 toBoolean(ExecState * exec)287 inline bool JSValue::toBoolean(ExecState* exec) const 288 { 289 if (isInt32()) 290 return asInt32() != 0; 291 if (isDouble()) 292 return asDouble() > 0.0 || asDouble() < 0.0; // false for NaN 293 if (isCell()) 294 return asCell()->toBoolean(exec); 295 return isTrue(); // false, null, and undefined all convert to false. 296 } 297 toNumber(ExecState * exec)298 ALWAYS_INLINE double JSValue::toNumber(ExecState* exec) const 299 { 300 if (isInt32()) 301 return asInt32(); 302 if (isDouble()) 303 return asDouble(); 304 if (isCell()) 305 return asCell()->toNumber(exec); 306 if (isTrue()) 307 return 1.0; 308 return isUndefined() ? nonInlineNaN() : 0; // null and false both convert to 0. 309 } 310 getJSNumber()311 inline JSValue JSValue::getJSNumber() 312 { 313 if (isInt32() || isDouble()) 314 return *this; 315 if (isCell()) 316 return asCell()->getJSNumber(); 317 return JSValue(); 318 } 319 toObject(ExecState * exec)320 inline JSObject* JSValue::toObject(ExecState* exec) const 321 { 322 return isCell() ? asCell()->toObject(exec, exec->lexicalGlobalObject()) : toObjectSlowCase(exec, exec->lexicalGlobalObject()); 323 } 324 toObject(ExecState * exec,JSGlobalObject * globalObject)325 inline JSObject* JSValue::toObject(ExecState* exec, JSGlobalObject* globalObject) const 326 { 327 return isCell() ? asCell()->toObject(exec, globalObject) : toObjectSlowCase(exec, globalObject); 328 } 329 toThisObject(ExecState * exec)330 inline JSObject* JSValue::toThisObject(ExecState* exec) const 331 { 332 return isCell() ? asCell()->toThisObject(exec) : toThisObjectSlowCase(exec); 333 } 334 heap(JSValue v)335 inline Heap* Heap::heap(JSValue v) 336 { 337 if (!v.isCell()) 338 return 0; 339 return heap(v.asCell()); 340 } 341 heap(JSCell * c)342 inline Heap* Heap::heap(JSCell* c) 343 { 344 return MarkedSpace::heap(c); 345 } 346 347 #if ENABLE(JSC_ZOMBIES) isZombie()348 inline bool JSValue::isZombie() const 349 { 350 return isCell() && asCell() > (JSCell*)0x1ffffffffL && asCell()->isZombie(); 351 } 352 #endif 353 allocate()354 inline void* MarkedBlock::allocate() 355 { 356 while (m_nextAtom < m_endAtom) { 357 if (!m_marks.testAndSet(m_nextAtom)) { 358 JSCell* cell = reinterpret_cast<JSCell*>(&atoms()[m_nextAtom]); 359 m_nextAtom += m_atomsPerCell; 360 cell->~JSCell(); 361 return cell; 362 } 363 m_nextAtom += m_atomsPerCell; 364 } 365 366 return 0; 367 } 368 sizeClassFor(size_t bytes)369 inline MarkedSpace::SizeClass& MarkedSpace::sizeClassFor(size_t bytes) 370 { 371 ASSERT(bytes && bytes < maxCellSize); 372 if (bytes < preciseCutoff) 373 return m_preciseSizeClasses[(bytes - 1) / preciseStep]; 374 return m_impreciseSizeClasses[(bytes - 1) / impreciseStep]; 375 } 376 allocate(size_t bytes)377 inline void* MarkedSpace::allocate(size_t bytes) 378 { 379 SizeClass& sizeClass = sizeClassFor(bytes); 380 return allocateFromSizeClass(sizeClass); 381 } 382 allocate(size_t bytes)383 inline void* Heap::allocate(size_t bytes) 384 { 385 ASSERT(globalData()->identifierTable == wtfThreadData().currentIdentifierTable()); 386 ASSERT(JSLock::lockCount() > 0); 387 ASSERT(JSLock::currentThreadIsHoldingLock()); 388 ASSERT(bytes <= MarkedSpace::maxCellSize); 389 ASSERT(m_operationInProgress == NoOperation); 390 391 m_operationInProgress = Allocation; 392 void* result = m_markedSpace.allocate(bytes); 393 m_operationInProgress = NoOperation; 394 if (result) 395 return result; 396 397 return allocateSlowCase(bytes); 398 } 399 new(size_t size,JSGlobalData * globalData)400 inline void* JSCell::operator new(size_t size, JSGlobalData* globalData) 401 { 402 return globalData->heap.allocate(size); 403 } 404 new(size_t size,ExecState * exec)405 inline void* JSCell::operator new(size_t size, ExecState* exec) 406 { 407 return exec->heap()->allocate(size); 408 } 409 410 } // namespace JSC 411 412 #endif // JSCell_h 413