source: webkit/trunk/JavaScriptCore/kjs/object.h@ 10744

Last change on this file since 10744 was 10744, checked in by mjs, 20 years ago

JavaScriptCore:

Reviewed by Eric.

  • fixed <rdar://problem/4260481> Remove Reference type from JavaScriptCore

Also fixed some bugs with for..in enumeration while I was at it. object
properties now come before prototype properties and duplicates
between object and prototype are listed only once.

  • JavaScriptCore.xcodeproj/project.pbxproj:
  • kjs/IdentifierSequencedSet.cpp: Added. (KJS::IdentifierSequencedSet::IdentifierSequencedSet): (KJS::IdentifierSequencedSet::deallocateVector): (KJS::IdentifierSequencedSet::~IdentifierSequencedSet): (KJS::IdentifierSequencedSet::insert):
  • kjs/IdentifierSequencedSet.h: Added. (KJS::IdentifierSequencedSetIterator::IdentifierSequencedSetIterator): (KJS::IdentifierSequencedSetIterator::operator*): (KJS::IdentifierSequencedSetIterator::operator->): (KJS::IdentifierSequencedSetIterator::operator++): (KJS::IdentifierSequencedSetIterator::operator==): (KJS::IdentifierSequencedSetIterator::operator!=): (KJS::IdentifierSequencedSet::begin): (KJS::IdentifierSequencedSet::end): (KJS::IdentifierSequencedSet::size):
  • kjs/array_instance.h:
  • kjs/array_object.cpp: (ArrayInstanceImp::getPropertyNames): (ArrayInstanceImp::setLength): (ArrayInstanceImp::pushUndefinedObjectsToEnd):
  • kjs/nodes.cpp: (ForInNode::execute):
  • kjs/nodes.h:
  • kjs/object.cpp: (KJS::ObjectImp::getPropertyNames):
  • kjs/object.h:
  • kjs/property_map.cpp: (KJS::PropertyMap::getEnumerablePropertyNames): (KJS::PropertyMap::getSparseArrayPropertyNames):
  • kjs/property_map.h:
  • kjs/protect.h:
  • kjs/protected_reference.h: Removed.
  • kjs/reference.cpp: Removed.
  • kjs/reference.h: Removed.
  • kjs/reference_list.cpp: Removed.
  • kjs/reference_list.h: Removed.
  • kjs/ustring.h: (KJS::UString::impl):
  • kxmlcore/HashSet.h:

LayoutTests:

Reviewed by Eric.

  • test case for some fixes I made to for..in enumeration. object properties now come before prototype properties and duplicates between object and prototype are listed only once.
  • fast/js/for-in-expected.txt: Added.
  • fast/js/for-in.html: Added.
  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 20.4 KB
Line 
1// -*- c-basic-offset: 2 -*-
2/*
3 * This file is part of the KDE libraries
4 * Copyright (C) 1999-2001 Harri Porten ([email protected])
5 * Copyright (C) 2001 Peter Kelly ([email protected])
6 * Copyright (C) 2003 Apple Computer, Inc.
7 *
8 * This library is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU Library General Public
10 * License as published by the Free Software Foundation; either
11 * version 2 of the License, or (at your option) any later version.
12 *
13 * This library is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 * Library General Public License for more details.
17 *
18 * You should have received a copy of the GNU Library General Public License
19 * along with this library; see the file COPYING.LIB. If not, write to
20 * the Free Software Foundation, Inc., 51 Franklin Steet, Fifth Floor,
21 * Boston, MA 02110-1301, USA.
22 *
23 */
24
25#ifndef KJS_OBJECT_H
26#define KJS_OBJECT_H
27
28// Objects
29
30// maximum global call stack size. Protects against accidental or
31// malicious infinite recursions. Define to -1 if you want no limit.
32#if APPLE_CHANGES
33// Given OS X stack sizes we run out of stack at about 350 levels.
34// If we improve our stack usage, we can bump this number.
35#define KJS_MAX_STACK 100
36#else
37#define KJS_MAX_STACK 1000
38#endif
39
40#include "interpreter.h"
41#include "property_map.h"
42#include "property_slot.h"
43#include "scope_chain.h"
44
45namespace KJS {
46
47 class HashTable;
48 class HashEntry;
49 class ListImp;
50 class IdentifierSequencedSet;
51
52 // ECMA 262-3 8.6.1
53 // Property attributes
54 enum Attribute { None = 0,
55 ReadOnly = 1 << 1, // property can be only read, not written
56 DontEnum = 1 << 2, // property doesn't appear in (for .. in ..)
57 DontDelete = 1 << 3, // property can't be deleted
58 Internal = 1 << 4, // an internal property, set to bypass checks
59 Function = 1 << 5 }; // property is a function - only used by static hashtables
60
61 /**
62 * Class Information
63 */
64 struct ClassInfo {
65 /**
66 * A string denoting the class name. Example: "Window".
67 */
68 const char* className;
69 /**
70 * Pointer to the class information of the base class.
71 * 0L if there is none.
72 */
73 const ClassInfo *parentClass;
74 /**
75 * Static hash-table of properties.
76 */
77 const HashTable *propHashTable;
78 /**
79 * Reserved for future extension.
80 */
81 void *dummy;
82 };
83
84 class ObjectImp : public AllocatedValueImp {
85 public:
86 /**
87 * Creates a new ObjectImp with the specified prototype
88 *
89 * @param proto The prototype
90 */
91 ObjectImp(ObjectImp *proto);
92
93 /**
94 * Creates a new ObjectImp with a prototype of jsNull()
95 * (that is, the ECMAScript "null" value, not a null object pointer).
96 */
97 ObjectImp();
98
99 virtual void mark();
100 virtual Type type() const;
101
102 /**
103 * A pointer to a ClassInfo struct for this class. This provides a basic
104 * facility for run-time type information, and can be used to check an
105 * object's class an inheritance (see inherits()). This should
106 * always return a statically declared pointer, or 0 to indicate that
107 * there is no class information.
108 *
109 * This is primarily useful if you have application-defined classes that you
110 * wish to check against for casting purposes.
111 *
112 * For example, to specify the class info for classes FooImp and BarImp,
113 * where FooImp inherits from BarImp, you would add the following in your
114 * class declarations:
115 *
116 * \code
117 * class BarImp : public ObjectImp {
118 * virtual const ClassInfo *classInfo() const { return &info; }
119 * static const ClassInfo info;
120 * // ...
121 * };
122 *
123 * class FooImp : public ObjectImp {
124 * virtual const ClassInfo *classInfo() const { return &info; }
125 * static const ClassInfo info;
126 * // ...
127 * };
128 * \endcode
129 *
130 * And in your source file:
131 *
132 * \code
133 * const ClassInfo BarImp::info = {"Bar", 0, 0, 0}; // no parent class
134 * const ClassInfo FooImp::info = {"Foo", &BarImp::info, 0, 0};
135 * \endcode
136 *
137 * @see inherits()
138 */
139 virtual const ClassInfo *classInfo() const;
140
141 /**
142 * Checks whether this object inherits from the class with the specified
143 * classInfo() pointer. This requires that both this class and the other
144 * class return a non-NULL pointer for their classInfo() methods (otherwise
145 * it will return false).
146 *
147 * For example, for two ObjectImp pointers obj1 and obj2, you can check
148 * if obj1's class inherits from obj2's class using the following:
149 *
150 * if (obj1->inherits(obj2->classInfo())) {
151 * // ...
152 * }
153 *
154 * If you have a handle to a statically declared ClassInfo, such as in the
155 * classInfo() example, you can check for inheritance without needing
156 * an instance of the other class:
157 *
158 * if (obj1->inherits(FooImp::info)) {
159 * // ...
160 * }
161 *
162 * @param cinfo The ClassInfo pointer for the class you want to check
163 * inheritance against.
164 * @return true if this object's class inherits from class with the
165 * ClassInfo pointer specified in cinfo
166 */
167 bool inherits(const ClassInfo *cinfo) const;
168
169 // internal properties (ECMA 262-3 8.6.2)
170
171 /**
172 * Returns the prototype of this object. Note that this is not the same as
173 * the "prototype" property.
174 *
175 * See ECMA 8.6.2
176 *
177 * @return The object's prototype
178 */
179 ValueImp *prototype() const;
180 void setPrototype(ValueImp *proto);
181
182 /**
183 * Returns the class name of the object
184 *
185 * See ECMA 8.6.2
186 *
187 * @return The object's class name
188 */
189 /**
190 * Implementation of the [[Class]] internal property (implemented by all
191 * Objects)
192 *
193 * The default implementation uses classInfo().
194 * You should either implement classInfo(), or
195 * if you simply need a classname, you can reimplement className()
196 * instead.
197 */
198 virtual UString className() const;
199
200 /**
201 * Retrieves the specified property from the object. If neither the object
202 * or any other object in it's prototype chain have the property, this
203 * function will return Undefined.
204 *
205 * See ECMA 8.6.2.1
206 *
207 * @param exec The current execution state
208 * @param propertyName The name of the property to retrieve
209 *
210 * @return The specified property, or Undefined
211 */
212 ValueImp *get(ExecState *exec, const Identifier &propertyName) const;
213 ValueImp *get(ExecState *exec, unsigned propertyName) const;
214
215 bool getPropertySlot(ExecState *, const Identifier&, PropertySlot&);
216 bool getPropertySlot(ExecState *, unsigned, PropertySlot&);
217
218 virtual bool getOwnPropertySlot(ExecState *, const Identifier&, PropertySlot&);
219 virtual bool getOwnPropertySlot(ExecState *, unsigned index, PropertySlot&);
220
221 /**
222 * Sets the specified property.
223 *
224 * See ECMA 8.6.2.2
225 *
226 * @param exec The current execution state
227 * @param propertyName The name of the property to set
228 * @param propertyValue The value to set
229 */
230 virtual void put(ExecState *exec, const Identifier &propertyName, ValueImp *value, int attr = None);
231 virtual void put(ExecState *exec, unsigned propertyName, ValueImp *value, int attr = None);
232
233 /**
234 * Used to check whether or not a particular property is allowed to be set
235 * on an object
236 *
237 * See ECMA 8.6.2.3
238 *
239 * @param exec The current execution state
240 * @param propertyName The name of the property
241 * @return true if the property can be set, otherwise false
242 */
243 /**
244 * Implementation of the [[CanPut]] internal property (implemented by all
245 * Objects)
246 */
247 virtual bool canPut(ExecState *exec, const Identifier &propertyName) const;
248
249 /**
250 * Checks to see whether the object (or any object in it's prototype chain)
251 * has a property with the specified name.
252 *
253 * See ECMA 8.6.2.4
254 *
255 * @param exec The current execution state
256 * @param propertyName The name of the property to check for
257 * @return true if the object has the property, otherwise false
258 */
259 bool hasProperty(ExecState *exec, const Identifier &propertyName) const;
260 bool hasProperty(ExecState *exec, unsigned propertyName) const;
261
262 /**
263 * Removes the specified property from the object.
264 *
265 * See ECMA 8.6.2.5
266 *
267 * @param exec The current execution state
268 * @param propertyName The name of the property to delete
269 * @return true if the property was successfully deleted or did not
270 * exist on the object. false if deleting the specified property is not
271 * allowed.
272 */
273 virtual bool deleteProperty(ExecState *exec, const Identifier &propertyName);
274 virtual bool deleteProperty(ExecState *exec, unsigned propertyName);
275
276 /**
277 * Converts the object into a primitive value. The value return may differ
278 * depending on the supplied hint
279 *
280 * See ECMA 8.6.2.6
281 *
282 * @param exec The current execution state
283 * @param hint The desired primitive type to convert to
284 * @return A primitive value converted from the objetc. Note that the
285 * type of primitive value returned may not be the same as the requested
286 * hint.
287 */
288 /**
289 * Implementation of the [[DefaultValue]] internal property (implemented by
290 * all Objects)
291 */
292 virtual ValueImp *defaultValue(ExecState *exec, Type hint) const;
293
294 /**
295 * Whether or not the object implements the construct() method. If this
296 * returns false you should not call the construct() method on this
297 * object (typically, an assertion will fail to indicate this).
298 *
299 * @return true if this object implements the construct() method, otherwise
300 * false
301 */
302 virtual bool implementsConstruct() const;
303
304 /**
305 * Creates a new object based on this object. Typically this means the
306 * following:
307 * 1. A new object is created
308 * 2. The prototype of the new object is set to the value of this object's
309 * "prototype" property
310 * 3. The call() method of this object is called, with the new object
311 * passed as the this value
312 * 4. The new object is returned
313 *
314 * In some cases, Host objects may differ from these semantics, although
315 * this is discouraged.
316 *
317 * If an error occurs during construction, the execution state's exception
318 * will be set. This can be tested for with ExecState::hadException().
319 * Under some circumstances, the exception object may also be returned.
320 *
321 * Note: This function should not be called if implementsConstruct() returns
322 * false, in which case it will result in an assertion failure.
323 *
324 * @param exec The current execution state
325 * @param args The arguments to be passed to call() once the new object has
326 * been created
327 * @return The newly created &amp; initialized object
328 */
329 /**
330 * Implementation of the [[Construct]] internal property
331 */
332 virtual ObjectImp *construct(ExecState *exec, const List &args);
333 virtual ObjectImp *construct(ExecState *exec, const List &args, const UString &sourceURL, int lineNumber);
334
335 /**
336 * Whether or not the object implements the call() method. If this returns
337 * false you should not call the call() method on this object (typically,
338 * an assertion will fail to indicate this).
339 *
340 * @return true if this object implements the call() method, otherwise
341 * false
342 */
343 virtual bool implementsCall() const;
344
345 /**
346 * Calls this object as if it is a function.
347 *
348 * Note: This function should not be called if implementsCall() returns
349 * false, in which case it will result in an assertion failure.
350 *
351 * See ECMA 8.6.2.3
352 *
353 * @param exec The current execution state
354 * @param thisObj The obj to be used as "this" within function execution.
355 * Note that in most cases this will be different from the C++ "this"
356 * object. For example, if the ECMAScript code "window.location->toString()"
357 * is executed, call() will be invoked on the C++ object which implements
358 * the toString method, with the thisObj being window.location
359 * @param args List of arguments to be passed to the function
360 * @return The return value from the function
361 */
362 ValueImp *call(ExecState *exec, ObjectImp *thisObj, const List &args);
363 virtual ValueImp *callAsFunction(ExecState *exec, ObjectImp *thisObj, const List &args);
364
365 /**
366 * Whether or not the object implements the hasInstance() method. If this
367 * returns false you should not call the hasInstance() method on this
368 * object (typically, an assertion will fail to indicate this).
369 *
370 * @return true if this object implements the hasInstance() method,
371 * otherwise false
372 */
373 virtual bool implementsHasInstance() const;
374
375 /**
376 * Checks whether value delegates behavior to this object. Used by the
377 * instanceof operator.
378 *
379 * @param exec The current execution state
380 * @param value The value to check
381 * @return true if value delegates behavior to this object, otherwise
382 * false
383 */
384 virtual bool hasInstance(ExecState *exec, ValueImp *value);
385
386 /**
387 * Returns the scope of this object. This is used when execution declared
388 * functions - the execution context for the function is initialized with
389 * extra object in it's scope. An example of this is functions declared
390 * inside other functions:
391 *
392 * \code
393 * function f() {
394 *
395 * function b() {
396 * return prototype;
397 * }
398 *
399 * var x = 4;
400 * // do some stuff
401 * }
402 * f.prototype = new String();
403 * \endcode
404 *
405 * When the function f.b is executed, its scope will include properties of
406 * f. So in the example above the return value of f.b() would be the new
407 * String object that was assigned to f.prototype.
408 *
409 * @param exec The current execution state
410 * @return The function's scope
411 */
412 const ScopeChain &scope() const { return _scope; }
413 void setScope(const ScopeChain &s) { _scope = s; }
414
415 /**
416 * Returns a List of References to all the properties of the object. Used
417 * in "for x in y" statements. The list is created new, so it can be freely
418 * modified without affecting the object's properties. It should be deleted
419 * by the caller.
420 *
421 * Subclasses can override this method in ObjectImpl to provide the
422 * appearance of
423 * having extra properties other than those set specifically with put().
424 *
425 * @param exec The current execution state
426 * @param propertyNames A list of property names to be filled in by this call
427 **/
428 virtual void getPropertyNames(ExecState *exec, IdentifierSequencedSet& propertyNames);
429
430 /**
431 * Returns the internal value of the object. This is used for objects such
432 * as String and Boolean which are wrappers for native types. The interal
433 * value is the actual value represented by the wrapper objects.
434 *
435 * @see ECMA 8.6.2
436 * @return The internal value of the object
437 */
438 ValueImp *internalValue() const;
439
440 /**
441 * Sets the internal value of the object
442 *
443 * @see internalValue()
444 *
445 * @param v The new internal value
446 */
447 void setInternalValue(ValueImp *v);
448
449 ValueImp *toPrimitive(ExecState *exec, Type preferredType = UnspecifiedType) const;
450 bool toBoolean(ExecState *exec) const;
451 double toNumber(ExecState *exec) const;
452 UString toString(ExecState *exec) const;
453 ObjectImp *toObject(ExecState *exec) const;
454
455 // This get function only looks at the property map.
456 // This is used e.g. by lookupOrCreateFunction (to cache a function, we don't want
457 // to look up in the prototype, it might already exist there)
458 ValueImp *getDirect(const Identifier& propertyName) const
459 { return _prop.get(propertyName); }
460 ValueImp **getDirectLocation(const Identifier& propertyName)
461 { return _prop.getLocation(propertyName); }
462 void putDirect(const Identifier &propertyName, ValueImp *value, int attr = 0);
463 void putDirect(const Identifier &propertyName, int value, int attr = 0);
464
465 /**
466 * Remove all properties from this object.
467 * This doesn't take DontDelete into account, and isn't in the ECMA spec.
468 * It's simply a quick way to remove everything stored in the property map.
469 */
470 void clearProperties() { _prop.clear(); }
471
472 void saveProperties(SavedProperties &p) const { _prop.save(p); }
473 void restoreProperties(const SavedProperties &p) { _prop.restore(p); }
474
475 virtual bool isActivation() { return false; }
476 protected:
477 PropertyMap _prop;
478 private:
479 const HashEntry* findPropertyHashEntry( const Identifier& propertyName ) const;
480 ValueImp *_proto;
481 ValueImp *_internalValue;
482 ScopeChain _scope;
483 };
484
485 /**
486 * Types of Native Errors available. For custom errors, GeneralError
487 * should be used.
488 */
489 enum ErrorType { GeneralError = 0,
490 EvalError = 1,
491 RangeError = 2,
492 ReferenceError = 3,
493 SyntaxError = 4,
494 TypeError = 5,
495 URIError = 6};
496
497 /**
498 * @short Factory methods for error objects.
499 */
500 class Error {
501 public:
502 /**
503 * Factory method for error objects.
504 *
505 * @param exec The current execution state
506 * @param errtype Type of error.
507 * @param message Optional error message.
508 * @param lineNumber Optional line number.
509 * @param sourceId Optional source id.
510 * @param sourceURL Optional source URL.
511 */
512 static ObjectImp *create(ExecState *, ErrorType, const UString &message, int lineNumber, int sourceId, const UString *sourceURL);
513 static ObjectImp *create(ExecState *, ErrorType, const char *message);
514
515 /**
516 * Array of error names corresponding to ErrorType
517 */
518 static const char * const * const errorNames;
519 };
520
521ObjectImp *throwError(ExecState *, ErrorType, const UString &message, int lineNumber, int sourceId, const UString *sourceURL);
522ObjectImp *throwError(ExecState *, ErrorType, const UString &message);
523ObjectImp *throwError(ExecState *, ErrorType, const char *message);
524ObjectImp *throwError(ExecState *, ErrorType);
525
526inline bool AllocatedValueImp::isObject(const ClassInfo *info) const
527{
528 return isObject() && static_cast<const ObjectImp *>(this)->inherits(info);
529}
530
531inline ObjectImp::ObjectImp(ObjectImp *proto)
532 : _proto(proto), _internalValue(0)
533{
534 assert(proto);
535}
536
537inline ObjectImp::ObjectImp()
538 : _proto(jsNull()), _internalValue(0)
539{
540}
541
542inline ValueImp *ObjectImp::internalValue() const
543{
544 return _internalValue;
545}
546
547inline void ObjectImp::setInternalValue(ValueImp *v)
548{
549 _internalValue = v;
550}
551
552inline ValueImp *ObjectImp::prototype() const
553{
554 return _proto;
555}
556
557inline void ObjectImp::setPrototype(ValueImp *proto)
558{
559 assert(proto);
560 _proto = proto;
561}
562
563inline bool ObjectImp::inherits(const ClassInfo *info) const
564{
565 for (const ClassInfo *ci = classInfo(); ci; ci = ci->parentClass)
566 if (ci == info)
567 return true;
568 return false;
569}
570
571// It may seem crazy to inline a function this large but it makes a big difference
572// since this is function very hot in variable lookup
573inline bool ObjectImp::getPropertySlot(ExecState *exec, const Identifier& propertyName, PropertySlot& slot)
574{
575 ObjectImp *object = this;
576 while (true) {
577 if (object->getOwnPropertySlot(exec, propertyName, slot))
578 return true;
579
580 ValueImp *proto = object->_proto;
581 if (!proto->isObject())
582 return false;
583
584 object = static_cast<ObjectImp *>(proto);
585 }
586}
587
588// It may seem crazy to inline a function this large, especially a virtual function,
589// but it makes a big difference to property lookup that derived classes can inline their
590// base class call to this.
591inline bool ObjectImp::getOwnPropertySlot(ExecState *exec, const Identifier& propertyName, PropertySlot& slot)
592{
593 if (ValueImp **location = getDirectLocation(propertyName)) {
594 slot.setValueSlot(this, location);
595 return true;
596 }
597
598 // non-standard Netscape extension
599 if (propertyName == exec->dynamicInterpreter()->specialPrototypeIdentifier()) {
600 slot.setValueSlot(this, &_proto);
601 return true;
602 }
603
604 return false;
605}
606
607} // namespace
608
609#endif // KJS_OBJECT_H
Note: See TracBrowser for help on using the repository browser.