Reviewed by Sam.
[WebKit-https.git] / JavaScriptCore / kjs / JSObject.h
1 // -*- c-basic-offset: 2 -*-
2 /*
3  *  Copyright (C) 1999-2001 Harri Porten (porten@kde.org)
4  *  Copyright (C) 2001 Peter Kelly (pmk@post.com)
5  *  Copyright (C) 2003, 2004, 2005, 2006, 2007, 2008 Apple Inc. All rights reserved.
6  *
7  *  This library is free software; you can redistribute it and/or
8  *  modify it under the terms of the GNU Library General Public
9  *  License as published by the Free Software Foundation; either
10  *  version 2 of the License, or (at your option) any later version.
11  *
12  *  This library is distributed in the hope that it will be useful,
13  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
14  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
15  *  Library General Public License for more details.
16  *
17  *  You should have received a copy of the GNU Library General Public License
18  *  along with this library; see the file COPYING.LIB.  If not, write to
19  *  the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
20  *  Boston, MA 02110-1301, USA.
21  *
22  */
23
24 #ifndef KJS_OBJECT_H
25 #define KJS_OBJECT_H
26
27 #include "CommonIdentifiers.h"
28 #include "ExecState.h"
29 #include "JSType.h"
30 #include "list.h"
31 #include "PropertyMap.h"
32 #include "PropertySlot.h"
33 #include "ScopeChain.h"
34
35 namespace KJS {
36
37   class InternalFunction;
38   class PropertyNameArray;
39
40   struct HashEntry;
41   struct HashTable;
42
43   // ECMA 262-3 8.6.1
44   // Property attributes
45   enum Attribute { None         = 0,
46                    ReadOnly     = 1 << 1, // property can be only read, not written
47                    DontEnum     = 1 << 2, // property doesn't appear in (for .. in ..)
48                    DontDelete   = 1 << 3, // property can't be deleted
49                    Function     = 1 << 4, // property is a function - only used by static hashtables
50                    IsGetterSetter = 1 << 5 }; // property is a getter or setter
51
52   /**
53    * Class Information
54    */
55   struct ClassInfo {
56     /**
57      * A string denoting the class name. Example: "Window".
58      */
59     const char* className;
60     /**
61      * Pointer to the class information of the base class.
62      * 0L if there is none.
63      */
64     const ClassInfo* parentClass;
65     /**
66      * Static hash-table of properties.
67      * For classes that can be used from multiple threads, it is accessed via a getter function that would typically return a pointer to thread-specific value.
68      */
69     const HashTable* propHashTable(ExecState* exec) const
70     {
71         if (classPropHashTableGetterFunction)
72             return classPropHashTableGetterFunction(exec);
73         return staticPropHashTable;
74     }
75
76     const HashTable* staticPropHashTable;
77     typedef const HashTable* (*ClassPropHashTableGetterFunction)(ExecState*);
78     const ClassPropHashTableGetterFunction classPropHashTableGetterFunction;
79   };
80   
81   // This is an internal value object which stores getter and setter functions
82   // for a property.
83   class GetterSetter : public JSCell {
84   public:
85     JSType type() const { return GetterSetterType; }
86       
87     GetterSetter() : getter(0), setter(0) { }
88       
89     virtual JSValue* toPrimitive(ExecState*, JSType preferred = UnspecifiedType) const;
90     virtual bool getPrimitiveNumber(ExecState*, double& number, JSValue*& value);
91     virtual bool toBoolean(ExecState *exec) const;
92     virtual double toNumber(ExecState *exec) const;
93     virtual UString toString(ExecState *exec) const;
94     virtual JSObject *toObject(ExecState *exec) const;
95       
96     virtual void mark();
97       
98     JSObject *getGetter() { return getter; }
99     void setGetter(JSObject *g) { getter = g; }
100     JSObject *getSetter() { return setter; }
101     void setSetter(JSObject *s) { setter = s; }
102       
103   private:
104     // Object operations, with the toObject operation included.
105     virtual bool getOwnPropertySlot(ExecState*, const Identifier&, PropertySlot&);
106     virtual bool getOwnPropertySlot(ExecState*, unsigned index, PropertySlot&);
107     virtual void put(ExecState*, const Identifier& propertyName, JSValue*);
108     virtual void put(ExecState*, unsigned propertyName, JSValue*);
109     virtual JSObject* toThisObject(ExecState*) const;
110
111     JSObject *getter;
112     JSObject *setter;  
113   };
114   
115   class JSObject : public JSCell {
116   public:
117     /**
118      * Creates a new JSObject with the specified prototype
119      *
120      * @param proto The prototype
121      */
122     JSObject(JSValue* proto);
123
124     /**
125      * Creates a new JSObject with a prototype of jsNull()
126      * (that is, the ECMAScript "null" value, not a null object pointer).
127      */
128     JSObject();
129     
130     virtual void mark();
131     virtual JSType type() const;
132
133     /**
134      * A pointer to a ClassInfo struct for this class. This provides a basic
135      * facility for run-time type information, and can be used to check an
136      * object's class an inheritance (see inherits()). This should
137      * always return a statically declared pointer, or 0 to indicate that
138      * there is no class information.
139      *
140      * This is primarily useful if you have application-defined classes that you
141      * wish to check against for casting purposes.
142      *
143      * For example, to specify the class info for classes FooImp and BarImp,
144      * where FooImp inherits from BarImp, you would add the following in your
145      * class declarations:
146      *
147      * \code
148      *   class BarImp : public JSObject {
149      *     virtual const ClassInfo *classInfo() const { return &info; }
150      *     static const ClassInfo info;
151      *     // ...
152      *   };
153      *
154      *   class FooImp : public JSObject {
155      *     virtual const ClassInfo *classInfo() const { return &info; }
156      *     static const ClassInfo info;
157      *     // ...
158      *   };
159      * \endcode
160      *
161      * And in your source file:
162      *
163      * \code
164      *   const ClassInfo BarImp::info = { "Bar", 0, 0, 0 }; // no parent class
165      *   const ClassInfo FooImp::info = { "Foo", &BarImp::info, 0, 0 };
166      * \endcode
167      *
168      * @see inherits()
169      */
170     virtual const ClassInfo *classInfo() const;
171
172     /**
173      * Checks whether this object inherits from the class with the specified
174      * classInfo() pointer. This requires that both this class and the other
175      * class return a non-NULL pointer for their classInfo() methods (otherwise
176      * it will return false).
177      *
178      * For example, for two JSObject pointers obj1 and obj2, you can check
179      * if obj1's class inherits from obj2's class using the following:
180      *
181      *   if (obj1->inherits(obj2->classInfo())) {
182      *     // ...
183      *   }
184      *
185      * If you have a handle to a statically declared ClassInfo, such as in the
186      * classInfo() example, you can check for inheritance without needing
187      * an instance of the other class:
188      *
189      *   if (obj1->inherits(FooImp::info)) {
190      *     // ...
191      *   }
192      *
193      * @param cinfo The ClassInfo pointer for the class you want to check
194      * inheritance against.
195      * @return true if this object's class inherits from class with the
196      * ClassInfo pointer specified in cinfo
197      */
198     bool inherits(const ClassInfo *cinfo) const;
199
200     // internal properties (ECMA 262-3 8.6.2)
201
202     /**
203      * Returns the prototype of this object. Note that this is not the same as
204      * the "prototype" property.
205      *
206      * See ECMA 8.6.2
207      *
208      * @return The object's prototype
209      */
210     JSValue *prototype() const;
211     void setPrototype(JSValue *proto);
212
213     /**
214      * Returns the class name of the object
215      *
216      * See ECMA 8.6.2
217      *
218      * @return The object's class name
219      */
220     /**
221      * Implementation of the [[Class]] internal property (implemented by all
222      * Objects)
223      *
224      * The default implementation uses classInfo().
225      * You should either implement classInfo(), or
226      * if you simply need a classname, you can reimplement className()
227      * instead.
228      */
229     virtual UString className() const;
230
231     /**
232      * Retrieves the specified property from the object. If neither the object
233      * or any other object in it's prototype chain have the property, this
234      * function will return Undefined.
235      *
236      * See ECMA 8.6.2.1
237      *
238      * @param exec The current execution state
239      * @param propertyName The name of the property to retrieve
240      *
241      * @return The specified property, or Undefined
242      */
243     JSValue* get(ExecState* exec, const Identifier& propertyName) const;
244     JSValue* get(ExecState* exec, unsigned propertyName) const;
245
246     bool getPropertySlot(ExecState*, const Identifier&, PropertySlot&);
247     bool getPropertySlot(ExecState*, unsigned, PropertySlot&);
248
249     virtual bool getOwnPropertySlot(ExecState*, const Identifier&, PropertySlot&);
250     virtual bool getOwnPropertySlot(ExecState*, unsigned index, PropertySlot&);
251
252     /**
253      * Sets the specified property.
254      *
255      * See ECMA 8.6.2.2
256      *
257      * @param exec The current execution state
258      * @param propertyName The name of the property to set
259      * @param propertyValue The value to set
260      */
261     virtual void put(ExecState*, const Identifier& propertyName, JSValue* value);
262     virtual void put(ExecState*, unsigned propertyName, JSValue* value);
263
264     virtual void putWithAttributes(ExecState*, const Identifier& propertyName, JSValue* value, unsigned attributes);
265     virtual void putWithAttributes(ExecState*, unsigned propertyName, JSValue* value, unsigned attributes);
266
267     /**
268      * Checks if a property is enumerable, that is if it doesn't have the DontEnum
269      * flag set
270      *
271      * See ECMA 15.2.4
272      * @param exec The current execution state
273      * @param propertyName The name of the property
274      * @return true if the property is enumerable, otherwise false
275      */
276     bool propertyIsEnumerable(ExecState *exec, const Identifier &propertyName) const;
277
278     /**
279      * Checks to see whether the object (or any object in it's prototype chain)
280      * has a property with the specified name.
281      *
282      * See ECMA 8.6.2.4
283      *
284      * @param exec The current execution state
285      * @param propertyName The name of the property to check for
286      * @return true if the object has the property, otherwise false
287      */
288     bool hasProperty(ExecState*, const Identifier&) const;
289     bool hasProperty(ExecState*, unsigned) const;
290     bool hasOwnProperty(ExecState*, const Identifier&) const;
291
292     /**
293      * Removes the specified property from the object.
294      *
295      * See ECMA 8.6.2.5
296      *
297      * @param exec The current execution state
298      * @param propertyName The name of the property to delete
299      * @return true if the property was successfully deleted or did not
300      * exist on the object. false if deleting the specified property is not
301      * allowed.
302      */
303     virtual bool deleteProperty(ExecState *exec, const Identifier &propertyName);
304     virtual bool deleteProperty(ExecState *exec, unsigned propertyName);
305
306     /**
307      * Converts the object into a primitive value. The value return may differ
308      * depending on the supplied hint
309      *
310      * See ECMA 8.6.2.6
311      *
312      * @param exec The current execution state
313      * @param hint The desired primitive type to convert to
314      * @return A primitive value converted from the objetc. Note that the
315      * type of primitive value returned may not be the same as the requested
316      * hint.
317      */
318     /**
319      * Implementation of the [[DefaultValue]] internal property (implemented by
320      * all Objects)
321      */
322     virtual JSValue *defaultValue(ExecState *exec, JSType hint) const;
323
324     /**
325      * Creates a new object based on this object. Typically this means the
326      * following:
327      * 1. A new object is created
328      * 2. The prototype of the new object is set to the value of this object's
329      *    "prototype" property
330      * 3. The call() method of this object is called, with the new object
331      *    passed as the this value
332      * 4. The new object is returned
333      *
334      * In some cases, Host objects may differ from these semantics, although
335      * this is discouraged.
336      *
337      * If an error occurs during construction, the execution state's exception
338      * will be set. This can be tested for with ExecState::hadException().
339      * Under some circumstances, the exception object may also be returned.
340      *
341      * Note: This function should not be called if getConstructData() returns
342      * ConstructTypeNone, in which case it will result in an assertion failure.
343      *
344      * @param exec The current execution state
345      * @param args The arguments to be passed to call() once the new object has
346      * been created
347      * @return The newly created &amp; initialized object
348      */
349     /**
350      * Implementation of the [[Construct]] internal property
351      */
352     virtual JSObject* construct(ExecState* exec, const ArgList& args);
353     virtual JSObject* construct(ExecState* exec, const ArgList& args, const Identifier& functionName, const UString& sourceURL, int lineNumber);
354
355     /**
356      * Calls this object as if it is a function.
357      *
358      * Note: This function should not be called if implementsCall() returns
359      * false, in which case it will result in an assertion failure.
360      *
361      * See ECMA 8.6.2.3
362      *
363      * @param exec The current execution state
364      * @param thisObj The obj to be used as "this" within function execution.
365      * Note that in most cases this will be different from the C++ "this"
366      * object. For example, if the ECMAScript code "window.location->toString()"
367      * is executed, call() will be invoked on the C++ object which implements
368      * the toString method, with the thisObj being window.location
369      * @param args ArgList of arguments to be passed to the function
370      * @return The return value from the function
371      */
372     bool implementsCall();
373     virtual JSValue *callAsFunction(ExecState *exec, JSObject *thisObj, const ArgList &args);
374
375     /**
376      * Whether or not the object implements the hasInstance() method. If this
377      * returns false you should not call the hasInstance() method on this
378      * object (typically, an assertion will fail to indicate this).
379      *
380      * @return true if this object implements the hasInstance() method,
381      * otherwise false
382      */
383     virtual bool implementsHasInstance() const;
384
385     /**
386      * Checks whether value delegates behavior to this object. Used by the
387      * instanceof operator.
388      *
389      * @param exec The current execution state
390      * @param value The value to check
391      * @return true if value delegates behavior to this object, otherwise
392      * false
393      */
394     virtual bool hasInstance(ExecState *exec, JSValue *value);
395
396     virtual void getPropertyNames(ExecState*, PropertyNameArray&);
397
398     virtual JSValue* toPrimitive(ExecState*, JSType preferredType = UnspecifiedType) const;
399     virtual bool getPrimitiveNumber(ExecState*, double& number, JSValue*& value);
400     virtual bool toBoolean(ExecState *exec) const;
401     virtual double toNumber(ExecState *exec) const;
402     virtual UString toString(ExecState *exec) const;
403     virtual JSObject *toObject(ExecState *exec) const;
404
405     virtual JSObject* toThisObject(ExecState*) const;
406     virtual JSGlobalObject* toGlobalObject(ExecState*) const;
407
408     virtual bool getPropertyAttributes(ExecState*, const Identifier& propertyName, unsigned& attributes) const;
409     
410     // WebCore uses this to make document.all and style.filter undetectable
411     virtual bool masqueradeAsUndefined() const { return false; }
412     
413     // This get function only looks at the property map.
414     // This is used e.g. by lookupOrCreateFunction (to cache a function, we don't want
415     // to look up in the prototype, it might already exist there)
416     JSValue *getDirect(const Identifier& propertyName) const
417         { return _prop.get(propertyName); }
418     JSValue **getDirectLocation(const Identifier& propertyName)
419         { return _prop.getLocation(propertyName); }
420    JSValue **getDirectLocation(const Identifier& propertyName, bool& isWriteable)
421         { return _prop.getLocation(propertyName, isWriteable); }
422     void putDirect(const Identifier &propertyName, JSValue *value, int attr = 0);
423     void putDirect(ExecState*, const Identifier& propertyName, int value, int attr = 0);
424     void removeDirect(const Identifier &propertyName);
425     
426     // convenience to add a function property under the function's own built-in name
427     void putDirectFunction(InternalFunction*, int attr = 0);
428
429     void fillGetterPropertySlot(PropertySlot& slot, JSValue **location);
430
431     virtual void defineGetter(ExecState*, const Identifier& propertyName, JSObject* getterFunction);
432     virtual void defineSetter(ExecState*, const Identifier& propertyName, JSObject* setterFunction);
433     virtual JSValue* lookupGetter(ExecState*, const Identifier& propertyName);
434     virtual JSValue* lookupSetter(ExecState*, const Identifier& propertyName);
435
436     virtual bool isActivationObject() const { return false; }
437     virtual bool isGlobalObject() const { return false; }
438     virtual bool isVariableObject() const { return false; }
439
440   protected:
441     PropertyMap _prop;
442     bool getOwnPropertySlotForWrite(ExecState*, const Identifier&, PropertySlot&, bool& slotIsWriteable);
443
444   private:
445     const HashEntry* findPropertyHashEntry(ExecState*, const Identifier& propertyName) const;
446     JSValue *_proto;
447   };
448
449   /**
450    * Types of Native Errors available. For custom errors, GeneralError
451    * should be used.
452    */
453   enum ErrorType { GeneralError   = 0,
454                    EvalError      = 1,
455                    RangeError     = 2,
456                    ReferenceError = 3,
457                    SyntaxError    = 4,
458                    TypeError      = 5,
459                    URIError       = 6};
460
461   /**
462    * @short Factory methods for error objects.
463    */
464   class Error {
465   public:
466     /**
467      * Factory method for error objects.
468      *
469      * @param exec The current execution state
470      * @param errtype Type of error.
471      * @param message Optional error message.
472      * @param lineNumber Optional line number.
473      * @param sourceId Optional source id.
474      * @param sourceURL Optional source URL.
475      */
476     static JSObject *create(ExecState *, ErrorType, const UString &message, int lineNumber, int sourceId, const UString &sourceURL);
477     static JSObject *create(ExecState *, ErrorType, const char *message);
478   };
479
480 JSObject *throwError(ExecState *, ErrorType, const UString &message, int lineNumber, int sourceId, const UString &sourceURL);
481 JSObject *throwError(ExecState *, ErrorType, const UString &message);
482 JSObject *throwError(ExecState *, ErrorType, const char *message);
483 JSObject *throwError(ExecState *, ErrorType);
484
485 inline JSObject::JSObject(JSValue* proto)
486     : _proto(proto)
487 {
488     ASSERT(proto);
489     ASSERT(proto == jsNull() || Heap::heap(this) == Heap::heap(proto));
490 }
491
492 inline JSObject::JSObject()
493     : _proto(jsNull())
494 {
495 }
496
497 inline JSValue *JSObject::prototype() const
498 {
499     return _proto;
500 }
501
502 inline void JSObject::setPrototype(JSValue *proto)
503 {
504     ASSERT(proto);
505     _proto = proto;
506 }
507
508 inline bool JSObject::inherits(const ClassInfo *info) const
509 {
510     for (const ClassInfo *ci = classInfo(); ci; ci = ci->parentClass)
511         if (ci == info)
512             return true;
513     return false;
514 }
515
516 // this method is here to be after the inline declaration of JSObject::inherits
517 inline bool JSCell::isObject(const ClassInfo *info) const
518 {
519     return isObject() && static_cast<const JSObject *>(this)->inherits(info);
520 }
521
522 // this method is here to be after the inline declaration of JSCell::isObject
523 inline bool JSValue::isObject(const ClassInfo *c) const
524 {
525     return !JSImmediate::isImmediate(this) && asCell()->isObject(c);
526 }
527
528 inline JSValue *JSObject::get(ExecState *exec, const Identifier &propertyName) const
529 {
530   PropertySlot slot(const_cast<JSObject *>(this));
531
532   if (const_cast<JSObject *>(this)->getPropertySlot(exec, propertyName, slot))
533     return slot.getValue(exec, propertyName);
534     
535   return jsUndefined();
536 }
537
538 inline JSValue *JSObject::get(ExecState *exec, unsigned propertyName) const
539 {
540   PropertySlot slot(const_cast<JSObject *>(this));
541   if (const_cast<JSObject *>(this)->getPropertySlot(exec, propertyName, slot))
542     return slot.getValue(exec, propertyName);
543     
544   return jsUndefined();
545 }
546
547 // It may seem crazy to inline a function this large but it makes a big difference
548 // since this is function very hot in variable lookup
549 inline bool JSObject::getPropertySlot(ExecState *exec, const Identifier& propertyName, PropertySlot& slot)
550 {
551     JSObject *object = this;
552     while (true) {
553         if (object->getOwnPropertySlot(exec, propertyName, slot))
554             return true;
555
556         JSValue *proto = object->_proto;
557         if (!proto->isObject())
558             return false;
559
560         object = static_cast<JSObject *>(proto);
561     }
562 }
563
564 inline bool JSObject::getPropertySlot(ExecState *exec, unsigned propertyName, PropertySlot& slot)
565 {
566   JSObject *imp = this;
567   
568   while (true) {
569     if (imp->getOwnPropertySlot(exec, propertyName, slot))
570       return true;
571     
572     JSValue *proto = imp->_proto;
573     if (!proto->isObject())
574       break;
575     
576     imp = static_cast<JSObject *>(proto);
577   }
578   
579   return false;
580 }
581
582 // It may seem crazy to inline a function this large, especially a virtual function,
583 // but it makes a big difference to property lookup that derived classes can inline their
584 // base class call to this.
585 ALWAYS_INLINE bool JSObject::getOwnPropertySlotForWrite(ExecState* exec, const Identifier& propertyName, PropertySlot& slot, bool& slotIsWriteable)
586 {
587     if (JSValue **location = getDirectLocation(propertyName, slotIsWriteable)) {
588         if (_prop.hasGetterSetterProperties() && location[0]->type() == GetterSetterType) {
589             slotIsWriteable = false;
590             fillGetterPropertySlot(slot, location);
591         } else
592             slot.setValueSlot(location);
593         return true;
594     }
595
596     // non-standard Netscape extension
597     if (propertyName == exec->propertyNames().underscoreProto) {
598         slot.setValueSlot(&_proto);
599         slotIsWriteable = false;
600         return true;
601     }
602
603     return false;
604 }
605
606 // It may seem crazy to inline a function this large, especially a virtual function,
607 // but it makes a big difference to property lookup that derived classes can inline their
608 // base class call to this.
609 ALWAYS_INLINE bool JSObject::getOwnPropertySlot(ExecState* exec, const Identifier& propertyName, PropertySlot& slot)
610 {
611     if (JSValue **location = getDirectLocation(propertyName)) {
612         if (_prop.hasGetterSetterProperties() && location[0]->type() == GetterSetterType)
613             fillGetterPropertySlot(slot, location);
614         else
615             slot.setValueSlot(location);
616         return true;
617     }
618
619     // non-standard Netscape extension
620     if (propertyName == exec->propertyNames().underscoreProto) {
621         slot.setValueSlot(&_proto);
622         return true;
623     }
624
625     return false;
626 }
627
628 inline void JSObject::putDirect(const Identifier &propertyName, JSValue *value, int attr)
629 {
630     _prop.put(propertyName, value, attr);
631 }
632
633 inline void JSObject::putDirect(ExecState* exec, const Identifier &propertyName, int value, int attr)
634 {
635     _prop.put(propertyName, jsNumber(exec, value), attr);
636 }
637
638 inline JSValue* JSObject::toPrimitive(ExecState* exec, JSType preferredType) const
639 {
640     return defaultValue(exec, preferredType);
641 }
642
643 inline JSValue* JSValue::get(ExecState* exec, const Identifier& propertyName) const
644 {
645     if (UNLIKELY(JSImmediate::isImmediate(this))) {
646         JSObject* object = JSImmediate::toObject(this, exec);
647         PropertySlot slot(object);
648         if (!object->getPropertySlot(exec, propertyName, slot))
649             return jsUndefined();
650         return slot.getValue(exec, propertyName);
651     }
652     JSCell* cell = static_cast<JSCell*>(const_cast<JSValue*>(this));
653     PropertySlot slot(cell);
654     while (true) {
655         if (cell->getOwnPropertySlot(exec, propertyName, slot))
656             return slot.getValue(exec, propertyName);
657         ASSERT(cell->isObject());
658         JSValue* proto = static_cast<JSObject*>(cell)->prototype();
659         if (!proto->isObject())
660             return jsUndefined();
661         cell = static_cast<JSCell*>(proto);
662     }
663 }
664
665 inline JSValue* JSValue::get(ExecState* exec, unsigned propertyName) const
666 {
667     if (UNLIKELY(JSImmediate::isImmediate(this))) {
668         JSObject* object = JSImmediate::toObject(this, exec);
669         PropertySlot slot(object);
670         if (!object->getPropertySlot(exec, propertyName, slot))
671             return jsUndefined();
672         return slot.getValue(exec, propertyName);
673     }
674     JSCell* cell = const_cast<JSCell*>(asCell());
675     PropertySlot slot(cell);
676     while (true) {
677         if (cell->getOwnPropertySlot(exec, propertyName, slot))
678             return slot.getValue(exec, propertyName);
679         ASSERT(cell->isObject());
680         JSValue* proto = static_cast<JSObject*>(cell)->prototype();
681         if (!proto->isObject())
682             return jsUndefined();
683         cell = static_cast<JSCell*>(proto);
684     }
685 }
686
687 inline void JSValue::put(ExecState* exec, const Identifier& propertyName, JSValue* value)
688 {
689     if (UNLIKELY(JSImmediate::isImmediate(this))) {
690         JSImmediate::toObject(this, exec)->put(exec, propertyName, value);
691         return;
692     }
693     asCell()->put(exec, propertyName, value);
694 }
695
696 inline void JSValue::put(ExecState* exec, unsigned propertyName, JSValue* value)
697 {
698     if (UNLIKELY(JSImmediate::isImmediate(this))) {
699         JSImmediate::toObject(this, exec)->put(exec, propertyName, value);
700         return;
701     }
702     asCell()->put(exec, propertyName, value);
703 }
704
705 } // namespace
706
707 #endif // KJS_OBJECT_H