JSObject.cpp 16.3 KB
Newer Older
1
/*
2 3
 *  Copyright (C) 1999-2001 Harri Porten (porten@kde.org)
 *  Copyright (C) 2001 Peter Kelly (pmk@post.com)
darin@apple.com's avatar
darin@apple.com committed
4
 *  Copyright (C) 2003, 2004, 2005, 2006, 2008 Apple Inc. All rights reserved.
5
 *  Copyright (C) 2007 Eric Seidel (eric@webkit.org)
6 7 8 9 10 11 12 13 14 15 16 17 18
 *
 *  This library is free software; you can redistribute it and/or
 *  modify it under the terms of the GNU Library General Public
 *  License as published by the Free Software Foundation; either
 *  version 2 of the License, or (at your option) any later version.
 *
 *  This library is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 *  Library General Public License for more details.
 *
 *  You should have received a copy of the GNU Library General Public License
 *  along with this library; see the file COPYING.LIB.  If not, write to
mjs's avatar
mjs committed
19
 *  the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
20
 *  Boston, MA 02110-1301, USA.
21
 *
22 23
 */

mjs's avatar
mjs committed
24
#include "config.h"
darin@apple.com's avatar
darin@apple.com committed
25
#include "JSObject.h"
darin's avatar
darin committed
26

27
#include "DatePrototype.h"
28
#include "ErrorConstructor.h"
weinig@apple.com's avatar
weinig@apple.com committed
29
#include "GetterSetter.h"
30
#include "JSGlobalObject.h"
31
#include "NativeErrorConstructor.h"
32 33
#include "ObjectPrototype.h"
#include "PropertyNameArray.h"
34
#include "lookup.h"
darin's avatar
darin committed
35 36
#include "nodes.h"
#include "operations.h"
37
#include <math.h>
38
#include <profiler/Profiler.h>
ggaren's avatar
ggaren committed
39
#include <wtf/Assertions.h>
40

ggaren@apple.com's avatar
ggaren@apple.com committed
41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60
#define JSOBJECT_MARK_TRACING 0

#if JSOBJECT_MARK_TRACING

#define JSOBJECT_MARK_BEGIN() \
    static int markStackDepth = 0; \
    for (int i = 0; i < markStackDepth; i++) \
        putchar('-'); \
    printf("%s (%p)\n", className().UTF8String().c_str(), this); \
    markStackDepth++; \

#define JSOBJECT_MARK_END() \
    markStackDepth--;

#else // JSOBJECT_MARK_TRACING

#define JSOBJECT_MARK_BEGIN()
#define JSOBJECT_MARK_END()

#endif // JSOBJECT_MARK_TRACING
61

62
namespace JSC {
63

ggaren@apple.com's avatar
ggaren@apple.com committed
64 65
ASSERT_CLASS_FITS_IN_CELL(JSObject);

66
void JSObject::mark()
67
{
ggaren@apple.com's avatar
ggaren@apple.com committed
68
    JSOBJECT_MARK_BEGIN();
69

ggaren@apple.com's avatar
ggaren@apple.com committed
70
    JSCell::mark();
weinig@apple.com's avatar
weinig@apple.com committed
71
    m_structureID->mark();
weinig@apple.com's avatar
weinig@apple.com committed
72

73 74 75 76 77
    unsigned storageSize = m_structureID->propertyMap().storageSize();
    for (unsigned i = 0; i < storageSize; ++i) {
        JSValue* v = m_propertyStorage[i];
        if (!v->marked())
            v->mark();
weinig@apple.com's avatar
weinig@apple.com committed
78
    }
weinig@apple.com's avatar
weinig@apple.com committed
79

ggaren@apple.com's avatar
ggaren@apple.com committed
80
    JSOBJECT_MARK_END();
81 82
}

darin's avatar
darin committed
83
UString JSObject::className() const
84
{
weinig@apple.com's avatar
weinig@apple.com committed
85 86 87 88
    const ClassInfo* info = classInfo();
    if (info)
        return info->className;
    return "Object";
89 90
}

weinig@apple.com's avatar
weinig@apple.com committed
91
bool JSObject::getOwnPropertySlot(ExecState* exec, unsigned propertyName, PropertySlot& slot)
mjs's avatar
mjs committed
92
{
weinig@apple.com's avatar
weinig@apple.com committed
93
    return getOwnPropertySlot(exec, Identifier::from(exec, propertyName), slot);
mjs's avatar
mjs committed
94 95
}

weinig@apple.com's avatar
weinig@apple.com committed
96
static void throwSetterError(ExecState* exec)
mjs's avatar
mjs committed
97
{
weinig@apple.com's avatar
weinig@apple.com committed
98
    throwError(exec, TypeError, "setting a property that has only a getter");
mjs's avatar
mjs committed
99 100
}

101
// ECMA 8.6.2.2
weinig@apple.com's avatar
weinig@apple.com committed
102
void JSObject::put(ExecState* exec, const Identifier& propertyName, JSValue* value, PutPropertySlot& slot)
103
{
weinig@apple.com's avatar
weinig@apple.com committed
104 105 106 107 108 109 110
    ASSERT(value);
    ASSERT(!Heap::heap(value) || Heap::heap(value) == Heap::heap(this));

    if (propertyName == exec->propertyNames().underscoreProto) {
        JSObject* proto = value->getObject();

        // Setting __proto__ to a non-object, non-null value is silently ignored to match Mozilla.
ggaren@apple.com's avatar
ggaren@apple.com committed
111
        if (!proto && !value->isNull())
weinig@apple.com's avatar
weinig@apple.com committed
112 113 114 115 116 117 118 119 120 121 122
            return;
        
        while (proto) {
            if (proto == this) {
                throwError(exec, GeneralError, "cyclic __proto__ value");
                return;
            }
            proto = proto->prototype() ? proto->prototype()->getObject() : 0;
        }
        
        setPrototype(value);
123
        return;
124
    }
weinig@apple.com's avatar
weinig@apple.com committed
125 126 127
    
    // Check if there are any setters or getters in the prototype chain
    JSValue* prototype;
weinig@apple.com's avatar
weinig@apple.com committed
128
    for (JSObject* obj = this; !obj->structureID()->propertyMap().hasGetterSetterProperties(); obj = static_cast<JSObject*>(prototype)) {
weinig@apple.com's avatar
weinig@apple.com committed
129
        prototype = obj->prototype();
ggaren@apple.com's avatar
ggaren@apple.com committed
130
        if (prototype->isNull()) {
weinig@apple.com's avatar
weinig@apple.com committed
131
            putDirect(propertyName, value, 0, true, slot);
weinig@apple.com's avatar
weinig@apple.com committed
132
            return;
133
        }
134
    }
weinig@apple.com's avatar
weinig@apple.com committed
135 136
    
    unsigned attributes;
137
    if ((m_structureID->propertyMap().getOffset(propertyName, attributes) != WTF::notFound) && attributes & ReadOnly)
weinig@apple.com's avatar
weinig@apple.com committed
138
        return;
darin@apple.com's avatar
darin@apple.com committed
139

weinig@apple.com's avatar
weinig@apple.com committed
140
    for (JSObject* obj = this; ; obj = static_cast<JSObject*>(prototype)) {
141
        if (JSValue* gs = obj->getDirect(propertyName)) {
weinig@apple.com's avatar
weinig@apple.com committed
142
            if (gs->isGetterSetter()) {
weinig@apple.com's avatar
weinig@apple.com committed
143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160
                JSObject* setterFunc = static_cast<GetterSetter*>(gs)->setter();        
                if (!setterFunc) {
                    throwSetterError(exec);
                    return;
                }
                
                CallData callData;
                CallType callType = setterFunc->getCallData(callData);
                ArgList args;
                args.append(value);
                call(exec, setterFunc, callType, callData, this, args);
                return;
            }

            // If there's an existing property on the object or one of its 
            // prototypes it should be replaced, so break here.
            break;
        }
darin@apple.com's avatar
darin@apple.com committed
161

weinig@apple.com's avatar
weinig@apple.com committed
162
        prototype = obj->prototype();
ggaren@apple.com's avatar
ggaren@apple.com committed
163
        if (prototype->isNull())
weinig@apple.com's avatar
weinig@apple.com committed
164 165
            break;
    }
weinig@apple.com's avatar
weinig@apple.com committed
166 167 168

    putDirect(propertyName, value, 0, true, slot);
    return;
darin's avatar
darin committed
169 170
}

darin@apple.com's avatar
darin@apple.com committed
171
void JSObject::put(ExecState* exec, unsigned propertyName, JSValue* value)
172
{
weinig@apple.com's avatar
weinig@apple.com committed
173 174
    PutPropertySlot slot;
    put(exec, Identifier::from(exec, propertyName), value, slot);
175 176
}

weinig@apple.com's avatar
weinig@apple.com committed
177 178 179 180 181 182 183
void JSObject::putWithAttributes(ExecState*, const Identifier& propertyName, JSValue* value, unsigned attributes)
{
    putDirect(propertyName, value, attributes);
}

void JSObject::putWithAttributes(ExecState* exec, unsigned propertyName, JSValue* value, unsigned attributes)
{
ap@webkit.org's avatar
ap@webkit.org committed
184
    putWithAttributes(exec, Identifier::from(exec, propertyName), value, attributes);
weinig@apple.com's avatar
weinig@apple.com committed
185 186
}

weinig@apple.com's avatar
weinig@apple.com committed
187
bool JSObject::hasProperty(ExecState* exec, const Identifier& propertyName) const
mjs's avatar
mjs committed
188
{
weinig@apple.com's avatar
weinig@apple.com committed
189 190
    PropertySlot slot;
    return const_cast<JSObject*>(this)->getPropertySlot(exec, propertyName, slot);
mjs's avatar
mjs committed
191 192
}

weinig@apple.com's avatar
weinig@apple.com committed
193
bool JSObject::hasProperty(ExecState* exec, unsigned propertyName) const
mjs's avatar
mjs committed
194
{
weinig@apple.com's avatar
weinig@apple.com committed
195 196
    PropertySlot slot;
    return const_cast<JSObject*>(this)->getPropertySlot(exec, propertyName, slot);
mjs's avatar
mjs committed
197 198
}

199
// ECMA 8.6.2.5
weinig@apple.com's avatar
weinig@apple.com committed
200 201 202
bool JSObject::deleteProperty(ExecState* exec, const Identifier& propertyName)
{
    unsigned attributes;
203
    if (m_structureID->propertyMap().getOffset(propertyName, attributes) != WTF::notFound) {
weinig@apple.com's avatar
weinig@apple.com committed
204 205
        if ((attributes & DontDelete))
            return false;
weinig@apple.com's avatar
weinig@apple.com committed
206
        removeDirect(propertyName);
weinig@apple.com's avatar
weinig@apple.com committed
207 208
        return true;
    }
weinig@apple.com's avatar
weinig@apple.com committed
209

weinig@apple.com's avatar
weinig@apple.com committed
210 211
    // Look in the static hashtable of properties
    const HashEntry* entry = findPropertyHashEntry(exec, propertyName);
weinig@apple.com's avatar
weinig@apple.com committed
212
    if (entry && entry->attributes() & DontDelete)
weinig@apple.com's avatar
weinig@apple.com committed
213
        return false; // this builtin property can't be deleted
214

weinig@apple.com's avatar
weinig@apple.com committed
215 216
    // FIXME: Should the code here actually do some deletion?
    return true;
217 218
}

ggaren@apple.com's avatar
ggaren@apple.com committed
219 220 221 222 223 224
bool JSObject::hasOwnProperty(ExecState* exec, const Identifier& propertyName) const
{
    PropertySlot slot;
    return const_cast<JSObject*>(this)->getOwnPropertySlot(exec, propertyName, slot);
}

weinig@apple.com's avatar
weinig@apple.com committed
225
bool JSObject::deleteProperty(ExecState* exec, unsigned propertyName)
darin's avatar
darin committed
226
{
weinig@apple.com's avatar
weinig@apple.com committed
227
    return deleteProperty(exec, Identifier::from(exec, propertyName));
darin's avatar
darin committed
228 229
}

darin@apple.com's avatar
darin@apple.com committed
230 231 232 233 234 235
static ALWAYS_INLINE JSValue* callDefaultValueFunction(ExecState* exec, const JSObject* object, const Identifier& propertyName)
{
    JSValue* function = object->get(exec, propertyName);
    CallData callData;
    CallType callType = function->getCallData(callData);
    if (callType == CallTypeNone)
236 237 238 239 240 241 242
        return exec->exception();

    // Prevent "toString" and "valueOf" from observing execution if an exception
    // is pending.
    if (exec->hadException())
        return exec->exception();

darin@apple.com's avatar
darin@apple.com committed
243
    JSValue* result = call(exec, function, callType, callData, const_cast<JSObject*>(object), exec->emptyList());
darin@apple.com's avatar
darin@apple.com committed
244
    ASSERT(!result->isGetterSetter());
darin@apple.com's avatar
darin@apple.com committed
245 246 247 248 249
    if (exec->hadException())
        return exec->exception();
    if (result->isObject())
        return 0;
    return result;
eseidel's avatar
eseidel committed
250
}
251

252
bool JSObject::getPrimitiveNumber(ExecState* exec, double& number, JSValue*& result)
mjs's avatar
mjs committed
253
{
darin@apple.com's avatar
darin@apple.com committed
254
    result = defaultValue(exec, PreferNumber);
mjs's avatar
mjs committed
255 256 257 258
    number = result->toNumber(exec);
    return !result->isString();
}

eseidel's avatar
eseidel committed
259
// ECMA 8.6.2.6
darin@apple.com's avatar
darin@apple.com committed
260
JSValue* JSObject::defaultValue(ExecState* exec, PreferredPrimitiveType hint) const
eseidel's avatar
eseidel committed
261
{
darin@apple.com's avatar
darin@apple.com committed
262
    // Must call toString first for Date objects.
weinig@apple.com's avatar
weinig@apple.com committed
263
    if ((hint == PreferString) || (hint != PreferNumber && prototype() == exec->lexicalGlobalObject()->datePrototype())) {
darin@apple.com's avatar
darin@apple.com committed
264 265 266 267 268 269 270 271 272 273
        if (JSValue* value = callDefaultValueFunction(exec, this, exec->propertyNames().toString))
            return value;
        if (JSValue* value = callDefaultValueFunction(exec, this, exec->propertyNames().valueOf))
            return value;
    } else {
        if (JSValue* value = callDefaultValueFunction(exec, this, exec->propertyNames().valueOf))
            return value;
        if (JSValue* value = callDefaultValueFunction(exec, this, exec->propertyNames().toString))
            return value;
    }
274

darin@apple.com's avatar
darin@apple.com committed
275
    ASSERT(!exec->hadException());
ggaren's avatar
ggaren committed
276

darin@apple.com's avatar
darin@apple.com committed
277
    return throwError(exec, TypeError, "No default value");
278 279
}

ap@webkit.org's avatar
ap@webkit.org committed
280
const HashEntry* JSObject::findPropertyHashEntry(ExecState* exec, const Identifier& propertyName) const
281
{
darin@apple.com's avatar
darin@apple.com committed
282
    for (const ClassInfo* info = classInfo(); info; info = info->parentClass) {
ap@webkit.org's avatar
ap@webkit.org committed
283
        if (const HashTable* propHashTable = info->propHashTable(exec)) {
weinig@apple.com's avatar
weinig@apple.com committed
284 285
            if (const HashEntry* entry = propHashTable->entry(exec, propertyName))
                return entry;
darin@apple.com's avatar
darin@apple.com committed
286
        }
287
    }
darin@apple.com's avatar
darin@apple.com committed
288
    return 0;
289 290
}

weinig@apple.com's avatar
weinig@apple.com committed
291
void JSObject::defineGetter(ExecState* exec, const Identifier& propertyName, JSObject* getterFunction)
292
{
weinig@apple.com's avatar
weinig@apple.com committed
293
    JSValue* object = getDirect(propertyName);
weinig@apple.com's avatar
weinig@apple.com committed
294 295 296 297 298
    if (object && object->isGetterSetter()) {
        ASSERT(m_structureID->propertyMap().hasGetterSetterProperties());
        GetterSetter* getterSetter = static_cast<GetterSetter*>(object);
        getterSetter->setGetter(getterFunction);
        return;
weinig@apple.com's avatar
weinig@apple.com committed
299 300
    }

weinig@apple.com's avatar
weinig@apple.com committed
301 302 303 304
    PutPropertySlot slot;
    GetterSetter* getterSetter = new (exec) GetterSetter;
    putDirect(propertyName, getterSetter, None, true, slot);

weinig@apple.com's avatar
weinig@apple.com committed
305 306 307 308 309 310 311 312
    // putDirect will change our StructureID if we add a new property. For
    // getters and setters, though, we also need to change our StructureID
    // if we override an existing non-getter or non-setter.
    if (slot.type() != PutPropertySlot::NewProperty) {
        if (!m_structureID->isDictionary()) {
            RefPtr<StructureID> structureID = StructureID::getterSetterTransition(m_structureID);
            setStructureID(structureID.release());
        }
313
    }
weinig@apple.com's avatar
weinig@apple.com committed
314

weinig@apple.com's avatar
weinig@apple.com committed
315
    m_structureID->propertyMap().setHasGetterSetterProperties(true);
weinig@apple.com's avatar
weinig@apple.com committed
316
    getterSetter->setGetter(getterFunction);
317 318
}

weinig@apple.com's avatar
weinig@apple.com committed
319
void JSObject::defineSetter(ExecState* exec, const Identifier& propertyName, JSObject* setterFunction)
320
{
weinig@apple.com's avatar
weinig@apple.com committed
321
    JSValue* object = getDirect(propertyName);
weinig@apple.com's avatar
weinig@apple.com committed
322 323 324 325 326
    if (object && object->isGetterSetter()) {
        ASSERT(m_structureID->propertyMap().hasGetterSetterProperties());
        GetterSetter* getterSetter = static_cast<GetterSetter*>(object);
        getterSetter->setSetter(setterFunction);
        return;
327
    }
weinig@apple.com's avatar
weinig@apple.com committed
328

weinig@apple.com's avatar
weinig@apple.com committed
329 330 331 332
    PutPropertySlot slot;
    GetterSetter* getterSetter = new (exec) GetterSetter;
    putDirect(propertyName, getterSetter, None, true, slot);

weinig@apple.com's avatar
weinig@apple.com committed
333 334 335 336 337 338 339 340 341 342
    // putDirect will change our StructureID if we add a new property. For
    // getters and setters, though, we also need to change our StructureID
    // if we override an existing non-getter or non-setter.
    if (slot.type() != PutPropertySlot::NewProperty) {
        if (!m_structureID->isDictionary()) {
            RefPtr<StructureID> structureID = StructureID::getterSetterTransition(m_structureID);
            setStructureID(structureID.release());
        }
    }

weinig@apple.com's avatar
weinig@apple.com committed
343
    m_structureID->propertyMap().setHasGetterSetterProperties(true);
weinig@apple.com's avatar
weinig@apple.com committed
344
    getterSetter->setSetter(setterFunction);
345 346
}

weinig@apple.com's avatar
weinig@apple.com committed
347 348
JSValue* JSObject::lookupGetter(ExecState*, const Identifier& propertyName)
{
weinig@apple.com's avatar
weinig@apple.com committed
349
    JSObject* object = this;
weinig@apple.com's avatar
weinig@apple.com committed
350
    while (true) {
weinig@apple.com's avatar
weinig@apple.com committed
351 352
        JSValue* value = object->getDirect(propertyName);
        if (value) {
darin@apple.com's avatar
darin@apple.com committed
353
            if (!value->isGetterSetter())
weinig@apple.com's avatar
weinig@apple.com committed
354
                return jsUndefined();
weinig@apple.com's avatar
weinig@apple.com committed
355 356
            JSObject* functionObject = static_cast<GetterSetter*>(value)->getter();
            if (!functionObject)
weinig@apple.com's avatar
weinig@apple.com committed
357
                return jsUndefined();
weinig@apple.com's avatar
weinig@apple.com committed
358
            return functionObject;
weinig@apple.com's avatar
weinig@apple.com committed
359 360
        }

weinig@apple.com's avatar
weinig@apple.com committed
361
        if (!object->prototype() || !object->prototype()->isObject())
weinig@apple.com's avatar
weinig@apple.com committed
362
            return jsUndefined();
weinig@apple.com's avatar
weinig@apple.com committed
363
        object = static_cast<JSObject*>(object->prototype());
weinig@apple.com's avatar
weinig@apple.com committed
364 365 366 367 368
    }
}

JSValue* JSObject::lookupSetter(ExecState*, const Identifier& propertyName)
{
weinig@apple.com's avatar
weinig@apple.com committed
369
    JSObject* object = this;
weinig@apple.com's avatar
weinig@apple.com committed
370
    while (true) {
weinig@apple.com's avatar
weinig@apple.com committed
371 372
        JSValue* value = object->getDirect(propertyName);
        if (value) {
darin@apple.com's avatar
darin@apple.com committed
373
            if (!value->isGetterSetter())
weinig@apple.com's avatar
weinig@apple.com committed
374
                return jsUndefined();
weinig@apple.com's avatar
weinig@apple.com committed
375 376
            JSObject* functionObject = static_cast<GetterSetter*>(value)->setter();
            if (!functionObject)
weinig@apple.com's avatar
weinig@apple.com committed
377
                return jsUndefined();
weinig@apple.com's avatar
weinig@apple.com committed
378
            return functionObject;
weinig@apple.com's avatar
weinig@apple.com committed
379 380
        }

weinig@apple.com's avatar
weinig@apple.com committed
381
        if (!object->prototype() || !object->prototype()->isObject())
weinig@apple.com's avatar
weinig@apple.com committed
382
            return jsUndefined();
weinig@apple.com's avatar
weinig@apple.com committed
383
        object = static_cast<JSObject*>(object->prototype());
weinig@apple.com's avatar
weinig@apple.com committed
384 385 386
    }
}

387
bool JSObject::hasInstance(ExecState* exec, JSValue* value, JSValue* proto)
388
{
ggaren's avatar
ggaren committed
389
    if (!proto->isObject()) {
darin@apple.com's avatar
darin@apple.com committed
390
        throwError(exec, TypeError, "instanceof called on an object with an invalid prototype property.");
ggaren's avatar
ggaren committed
391 392
        return false;
    }
weinig@apple.com's avatar
weinig@apple.com committed
393

ggaren's avatar
ggaren committed
394 395
    if (!value->isObject())
        return false;
weinig@apple.com's avatar
weinig@apple.com committed
396 397 398 399

    JSObject* object = static_cast<JSObject*>(value);
    while ((object = object->prototype()->getObject())) {
        if (object == proto)
ggaren's avatar
ggaren committed
400 401 402
            return true;
    }
    return false;
403 404
}

ap@webkit.org's avatar
ap@webkit.org committed
405
bool JSObject::propertyIsEnumerable(ExecState* exec, const Identifier& propertyName) const
406
{
weinig@apple.com's avatar
weinig@apple.com committed
407 408 409
    unsigned attributes;
    if (!getPropertyAttributes(exec, propertyName, attributes))
        return false;
410 411 412
    return !(attributes & DontEnum);
}

ap@webkit.org's avatar
ap@webkit.org committed
413
bool JSObject::getPropertyAttributes(ExecState* exec, const Identifier& propertyName, unsigned& attributes) const
414
{
415
    if (m_structureID->propertyMap().getOffset(propertyName, attributes) != WTF::notFound)
weinig@apple.com's avatar
weinig@apple.com committed
416
        return true;
417
    
weinig@apple.com's avatar
weinig@apple.com committed
418 419 420
    // Look in the static hashtable of properties
    const HashEntry* entry = findPropertyHashEntry(exec, propertyName);
    if (entry) {
weinig@apple.com's avatar
weinig@apple.com committed
421
        attributes = entry->attributes();
weinig@apple.com's avatar
weinig@apple.com committed
422 423
        return true;
    }
424
    
weinig@apple.com's avatar
weinig@apple.com committed
425
    return false;
426 427
}

mjs's avatar
mjs committed
428
void JSObject::getPropertyNames(ExecState* exec, PropertyNameArray& propertyNames)
429
{
430
    m_structureID->getEnumerablePropertyNames(exec, propertyNames, this);
431 432
}

mjs@apple.com's avatar
mjs@apple.com committed
433 434 435 436 437
bool JSObject::toBoolean(ExecState*) const
{
    return true;
}

weinig@apple.com's avatar
weinig@apple.com committed
438
double JSObject::toNumber(ExecState* exec) const
439
{
darin@apple.com's avatar
darin@apple.com committed
440
    JSValue* primitive = toPrimitive(exec, PreferNumber);
weinig@apple.com's avatar
weinig@apple.com committed
441 442 443
    if (exec->hadException()) // should be picked up soon in nodes.cpp
        return 0.0;
    return primitive->toNumber(exec);
444 445
}

446
UString JSObject::toString(ExecState* exec) const
447
{
darin@apple.com's avatar
darin@apple.com committed
448
    JSValue* primitive = toPrimitive(exec, PreferString);
449 450 451
    if (exec->hadException())
        return "";
    return primitive->toString(exec);
452 453
}

weinig@apple.com's avatar
weinig@apple.com committed
454
JSObject* JSObject::toObject(ExecState*) const
455
{
weinig@apple.com's avatar
weinig@apple.com committed
456
    return const_cast<JSObject*>(this);
457 458
}

weinig@apple.com's avatar
weinig@apple.com committed
459 460 461 462 463 464 465 466 467 468
JSObject* JSObject::toThisObject(ExecState*) const
{
    return const_cast<JSObject*>(this);
}

JSGlobalObject* JSObject::toGlobalObject(ExecState*) const
{
    return 0;
}

weinig@apple.com's avatar
weinig@apple.com committed
469
void JSObject::removeDirect(const Identifier& propertyName)
ggaren's avatar
ggaren committed
470
{
weinig@apple.com's avatar
weinig@apple.com committed
471 472
    if (m_structureID->isDictionary()) {
        m_structureID->propertyMap().remove(propertyName, m_propertyStorage);
473
        m_structureID->clearEnumerationCache();
weinig@apple.com's avatar
weinig@apple.com committed
474
        return;
weinig@apple.com's avatar
weinig@apple.com committed
475
    }
weinig@apple.com's avatar
weinig@apple.com committed
476 477 478 479

    RefPtr<StructureID> structureID = StructureID::toDictionaryTransition(m_structureID);
    structureID->propertyMap().remove(propertyName, m_propertyStorage);
    setStructureID(structureID.release());
ggaren's avatar
ggaren committed
480 481
}

ggaren@apple.com's avatar
ggaren@apple.com committed
482
void JSObject::putDirectFunction(ExecState* exec, InternalFunction* function, unsigned attr)
mjs's avatar
mjs committed
483
{
darin@apple.com's avatar
darin@apple.com committed
484
    putDirect(Identifier(exec, function->name(&exec->globalData())), function, attr);
mjs's avatar
mjs committed
485 486
}

487
NEVER_INLINE void JSObject::fillGetterPropertySlot(PropertySlot& slot, JSValue** location)
mjs's avatar
mjs committed
488
{
weinig@apple.com's avatar
weinig@apple.com committed
489 490
    if (JSObject* getterFunction = static_cast<GetterSetter*>(*location)->getter())
        slot.setGetterSlot(getterFunction);
mjs's avatar
mjs committed
491
    else
darin@apple.com's avatar
darin@apple.com committed
492
        slot.setUndefined();
mjs's avatar
mjs committed
493 494
}

ggaren@apple.com's avatar
ggaren@apple.com committed
495
StructureID* JSObject::createInheritorID()
weinig@apple.com's avatar
weinig@apple.com committed
496
{
mjs@apple.com's avatar
mjs@apple.com committed
497
    m_inheritorID = JSObject::createStructureID(this);
ggaren@apple.com's avatar
ggaren@apple.com committed
498
    return m_inheritorID.get();
weinig@apple.com's avatar
weinig@apple.com committed
499 500
}

501 502 503 504 505 506 507 508 509
void JSObject::allocatePropertyStorage(size_t oldSize, size_t newSize)
{
    JSValue** oldPropertStorage = m_propertyStorage;
    m_propertyStorage = new JSValue*[newSize];

    for (unsigned i = 0; i < oldSize; ++i)
        m_propertyStorage[i] = oldPropertStorage[i];

    if (oldPropertStorage != m_inlineStorage)
510
        delete [] oldPropertStorage;
511 512
}

darin@apple.com's avatar
darin@apple.com committed
513 514
JSObject* constructEmptyObject(ExecState* exec)
{
darin@apple.com's avatar
darin@apple.com committed
515
    return new (exec) JSObject(exec->lexicalGlobalObject()->emptyObjectStructure());
darin@apple.com's avatar
darin@apple.com committed
516 517
}

518
} // namespace JSC