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 <wtf/Noncopyable.h> 27 #include "Structure.h" 28 #include "JSValue.h" 29 #include "JSImmediate.h" 30 #include "Collector.h" 31 32 namespace JSC { 33 34 class JSCell : public NoncopyableCustomAllocated { 35 friend class GetterSetter; 36 friend class Heap; 37 friend class JIT; 38 friend class JSNumberCell; 39 friend class JSObject; 40 friend class JSPropertyNameIterator; 41 friend class JSString; 42 friend class JSValue; 43 friend class JSAPIValueWrapper; 44 friend struct VPtrSet; 45 46 private: 47 explicit JSCell(Structure*); 48 virtual ~JSCell(); 49 50 public: 51 // Querying the type. 52 #if USE(JSVALUE32) 53 bool isNumber() const; 54 #endif 55 bool isString() const; 56 bool isObject() const; 57 virtual bool isGetterSetter() const; 58 virtual bool isObject(const ClassInfo*) const; isAPIValueWrapper()59 virtual bool isAPIValueWrapper() const { return false; } 60 61 Structure* structure() const; 62 63 // Extracting the value. 64 bool getString(UString&) const; 65 UString getString() const; // null string if not a string 66 JSObject* getObject(); // NULL if not an object 67 const JSObject* getObject() const; // NULL if not an object 68 69 virtual CallType getCallData(CallData&); 70 virtual ConstructType getConstructData(ConstructData&); 71 72 // Extracting integer values. 73 // FIXME: remove these methods, can check isNumberCell in JSValue && then call asNumberCell::*. 74 virtual bool getUInt32(uint32_t&) const; 75 76 // Basic conversions. 77 virtual JSValue toPrimitive(ExecState*, PreferredPrimitiveType) const = 0; 78 virtual bool getPrimitiveNumber(ExecState*, double& number, JSValue&) = 0; 79 virtual bool toBoolean(ExecState*) const = 0; 80 virtual double toNumber(ExecState*) const = 0; 81 virtual UString toString(ExecState*) const = 0; 82 virtual JSObject* toObject(ExecState*) const = 0; 83 84 // Garbage collection. 85 void* operator new(size_t, ExecState*); 86 void* operator new(size_t, JSGlobalData*); new(size_t,void * placementNewDestination)87 void* operator new(size_t, void* placementNewDestination) { return placementNewDestination; } 88 89 void markCellDirect(); 90 virtual void markChildren(MarkStack&); 91 bool marked() const; 92 93 // Object operations, with the toObject operation included. 94 virtual const ClassInfo* classInfo() const; 95 virtual void put(ExecState*, const Identifier& propertyName, JSValue, PutPropertySlot&); 96 virtual void put(ExecState*, unsigned propertyName, JSValue); 97 virtual bool deleteProperty(ExecState*, const Identifier& propertyName); 98 virtual bool deleteProperty(ExecState*, unsigned propertyName); 99 100 virtual JSObject* toThisObject(ExecState*) const; 101 virtual UString toThisString(ExecState*) const; 102 virtual JSString* toThisJSString(ExecState*); 103 virtual JSValue getJSNumber(); vptr()104 void* vptr() { return *reinterpret_cast<void**>(this); } 105 106 private: 107 // Base implementation; for non-object classes implements getPropertySlot. 108 bool fastGetOwnPropertySlot(ExecState*, const Identifier& propertyName, PropertySlot&); 109 virtual bool getOwnPropertySlot(ExecState*, const Identifier& propertyName, PropertySlot&); 110 virtual bool getOwnPropertySlot(ExecState*, unsigned propertyName, PropertySlot&); 111 112 Structure* m_structure; 113 }; 114 115 JSCell* asCell(JSValue); 116 asCell(JSValue value)117 inline JSCell* asCell(JSValue value) 118 { 119 return value.asCell(); 120 } 121 JSCell(Structure * structure)122 inline JSCell::JSCell(Structure* structure) 123 : m_structure(structure) 124 { 125 } 126 ~JSCell()127 inline JSCell::~JSCell() 128 { 129 } 130 131 #if USE(JSVALUE32) isNumber()132 inline bool JSCell::isNumber() const 133 { 134 return Heap::isNumber(const_cast<JSCell*>(this)); 135 } 136 #endif 137 isObject()138 inline bool JSCell::isObject() const 139 { 140 return m_structure->typeInfo().type() == ObjectType; 141 } 142 isString()143 inline bool JSCell::isString() const 144 { 145 return m_structure->typeInfo().type() == StringType; 146 } 147 structure()148 inline Structure* JSCell::structure() const 149 { 150 return m_structure; 151 } 152 marked()153 inline bool JSCell::marked() const 154 { 155 return Heap::isCellMarked(this); 156 } 157 markCellDirect()158 inline void JSCell::markCellDirect() 159 { 160 Heap::markCell(this); 161 } 162 markChildren(MarkStack &)163 inline void JSCell::markChildren(MarkStack&) 164 { 165 ASSERT(marked()); 166 } 167 new(size_t size,JSGlobalData * globalData)168 inline void* JSCell::operator new(size_t size, JSGlobalData* globalData) 169 { 170 #ifdef JAVASCRIPTCORE_BUILDING_ALL_IN_ONE_FILE 171 return globalData->heap.inlineAllocate(size); 172 #else 173 return globalData->heap.allocate(size); 174 #endif 175 } 176 177 // --- JSValue inlines ---------------------------- 178 isString()179 inline bool JSValue::isString() const 180 { 181 return isCell() && asCell()->isString(); 182 } 183 isGetterSetter()184 inline bool JSValue::isGetterSetter() const 185 { 186 return isCell() && asCell()->isGetterSetter(); 187 } 188 isObject()189 inline bool JSValue::isObject() const 190 { 191 return isCell() && asCell()->isObject(); 192 } 193 getString(UString & s)194 inline bool JSValue::getString(UString& s) const 195 { 196 return isCell() && asCell()->getString(s); 197 } 198 getString()199 inline UString JSValue::getString() const 200 { 201 return isCell() ? asCell()->getString() : UString(); 202 } 203 getObject()204 inline JSObject* JSValue::getObject() const 205 { 206 return isCell() ? asCell()->getObject() : 0; 207 } 208 getCallData(CallData & callData)209 inline CallType JSValue::getCallData(CallData& callData) 210 { 211 return isCell() ? asCell()->getCallData(callData) : CallTypeNone; 212 } 213 getConstructData(ConstructData & constructData)214 inline ConstructType JSValue::getConstructData(ConstructData& constructData) 215 { 216 return isCell() ? asCell()->getConstructData(constructData) : ConstructTypeNone; 217 } 218 getUInt32(uint32_t & v)219 ALWAYS_INLINE bool JSValue::getUInt32(uint32_t& v) const 220 { 221 if (isInt32()) { 222 int32_t i = asInt32(); 223 v = static_cast<uint32_t>(i); 224 return i >= 0; 225 } 226 if (isDouble()) { 227 double d = asDouble(); 228 v = static_cast<uint32_t>(d); 229 return v == d; 230 } 231 return false; 232 } 233 markDirect()234 inline void JSValue::markDirect() 235 { 236 ASSERT(!marked()); 237 asCell()->markCellDirect(); 238 } 239 markChildren(MarkStack & markStack)240 inline void JSValue::markChildren(MarkStack& markStack) 241 { 242 ASSERT(marked()); 243 asCell()->markChildren(markStack); 244 } 245 marked()246 inline bool JSValue::marked() const 247 { 248 return !isCell() || asCell()->marked(); 249 } 250 251 #if !USE(JSVALUE32_64) asCell()252 ALWAYS_INLINE JSCell* JSValue::asCell() const 253 { 254 ASSERT(isCell()); 255 return m_ptr; 256 } 257 #endif // !USE(JSVALUE32_64) 258 toPrimitive(ExecState * exec,PreferredPrimitiveType preferredType)259 inline JSValue JSValue::toPrimitive(ExecState* exec, PreferredPrimitiveType preferredType) const 260 { 261 return isCell() ? asCell()->toPrimitive(exec, preferredType) : asValue(); 262 } 263 getPrimitiveNumber(ExecState * exec,double & number,JSValue & value)264 inline bool JSValue::getPrimitiveNumber(ExecState* exec, double& number, JSValue& value) 265 { 266 if (isInt32()) { 267 number = asInt32(); 268 value = *this; 269 return true; 270 } 271 if (isDouble()) { 272 number = asDouble(); 273 value = *this; 274 return true; 275 } 276 if (isCell()) 277 return asCell()->getPrimitiveNumber(exec, number, value); 278 if (isTrue()) { 279 number = 1.0; 280 value = *this; 281 return true; 282 } 283 if (isFalse() || isNull()) { 284 number = 0.0; 285 value = *this; 286 return true; 287 } 288 ASSERT(isUndefined()); 289 number = nonInlineNaN(); 290 value = *this; 291 return true; 292 } 293 toBoolean(ExecState * exec)294 inline bool JSValue::toBoolean(ExecState* exec) const 295 { 296 if (isInt32()) 297 return asInt32() != 0; 298 if (isDouble()) 299 return asDouble() > 0.0 || asDouble() < 0.0; // false for NaN 300 if (isCell()) 301 return asCell()->toBoolean(exec); 302 return isTrue(); // false, null, and undefined all convert to false. 303 } 304 toNumber(ExecState * exec)305 ALWAYS_INLINE double JSValue::toNumber(ExecState* exec) const 306 { 307 if (isInt32()) 308 return asInt32(); 309 if (isDouble()) 310 return asDouble(); 311 if (isCell()) 312 return asCell()->toNumber(exec); 313 if (isTrue()) 314 return 1.0; 315 return isUndefined() ? nonInlineNaN() : 0; // null and false both convert to 0. 316 } 317 toString(ExecState * exec)318 inline UString JSValue::toString(ExecState* exec) const 319 { 320 if (isCell()) 321 return asCell()->toString(exec); 322 if (isInt32()) 323 return UString::from(asInt32()); 324 if (isDouble()) 325 return asDouble() == 0.0 ? "0" : UString::from(asDouble()); 326 if (isTrue()) 327 return "true"; 328 if (isFalse()) 329 return "false"; 330 if (isNull()) 331 return "null"; 332 ASSERT(isUndefined()); 333 return "undefined"; 334 } 335 needsThisConversion()336 inline bool JSValue::needsThisConversion() const 337 { 338 if (UNLIKELY(!isCell())) 339 return true; 340 return asCell()->structure()->typeInfo().needsThisConversion(); 341 } 342 toThisString(ExecState * exec)343 inline UString JSValue::toThisString(ExecState* exec) const 344 { 345 return isCell() ? asCell()->toThisString(exec) : toString(exec); 346 } 347 getJSNumber()348 inline JSValue JSValue::getJSNumber() 349 { 350 if (isInt32() || isDouble()) 351 return *this; 352 if (isCell()) 353 return asCell()->getJSNumber(); 354 return JSValue(); 355 } 356 hasChildren()357 inline bool JSValue::hasChildren() const 358 { 359 return asCell()->structure()->typeInfo().type() >= CompoundType; 360 } 361 362 toObject(ExecState * exec)363 inline JSObject* JSValue::toObject(ExecState* exec) const 364 { 365 return isCell() ? asCell()->toObject(exec) : toObjectSlowCase(exec); 366 } 367 toThisObject(ExecState * exec)368 inline JSObject* JSValue::toThisObject(ExecState* exec) const 369 { 370 return isCell() ? asCell()->toThisObject(exec) : toThisObjectSlowCase(exec); 371 } 372 append(JSCell * cell)373 ALWAYS_INLINE void MarkStack::append(JSCell* cell) 374 { 375 ASSERT(cell); 376 if (cell->marked()) 377 return; 378 cell->markCellDirect(); 379 if (cell->structure()->typeInfo().type() >= CompoundType) 380 m_values.append(cell); 381 } 382 drain()383 inline void MarkStack::drain() { 384 while (!m_markSets.isEmpty() || !m_values.isEmpty()) { 385 while ((!m_markSets.isEmpty()) && m_values.size() < 50) { 386 const MarkSet& current = m_markSets.removeLast(); 387 JSValue* ptr = current.m_values; 388 JSValue* end = current.m_end; 389 if (current.m_properties == NoNullValues) { 390 while (ptr != end) 391 append(*ptr++); 392 } else { 393 while (ptr != end) { 394 if (JSValue value = *ptr++) 395 append(value); 396 } 397 } 398 } 399 while (!m_values.isEmpty()) { 400 JSCell* current = m_values.removeLast(); 401 ASSERT(current->marked()); 402 current->markChildren(*this); 403 } 404 } 405 } 406 } // namespace JSC 407 408 #endif // JSCell_h 409