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

Last change on this file since 28476 was 28468, checked in by [email protected], 17 years ago

JavaScriptCore:

Reviewed by Darin Adler.

Third step in refactoring JSGlobalObject: Moved data members and
functions accessing data members from Interpreter to JSGlobalObject.
Changed Interpreter member functions to static functions.


This resolves a bug in global object bootstrapping, where the global
ExecState could be used when uninitialized.


This is a big change, but it's mostly code motion and renaming.


Layout and JS tests, and testjsglue and testapi, pass. SunSpider reports
a .7% regression, but Shark sees no difference related to this patch,
and SunSpider reported a .7% speedup from an earlier step in this
refactoring, so I think it's fair to call that a wash.

JavaScriptGlue:

Reviewed by Darin Adler.

Third step in refactoring JSGlobalObject: Moved data members and data
member access from Interpreter to JSGlobalObject. Replaced JSInterpreter
subclass with JSGlobalObject subclass.


  • JSRun.cpp: (JSRun::JSRun): (JSRun::Evaluate): (JSRun::CheckSyntax):
  • JSRun.h: (JSGlueGlobalObject::JSGlueGlobalObject):
  • JSUtils.cpp: (KJSValueToCFTypeInternal):
  • JSValueWrapper.cpp: (getThreadGlobalExecState):

WebCore:

Reviewed by Darin Adler.

Third step in refactoring JSGlobalObject: Moved data members and data
member access from Interpreter to JSGlobalObject. Changed Interpreter
member functions to static functions. Same for the subclass,
ScriptInterpreter.


This is a big change, but it's mostly code motion and renaming.

WebKit/mac:

Reviewed by Darin Adler.

Third step in refactoring JSGlobalObject: Moved data members and data
member access from Interpreter to JSGlobalObject.


  • WebView/WebFrame.mm: (-[WebFrame _attachScriptDebugger]):

WebKit/win:

Reviewed by Darin Adler.

Third step in refactoring JSGlobalObject: Moved data members and data
member access from Interpreter to JSGlobalObject.


  • WebFrame.cpp: (WebFrame::globalContext): (WebFrame::attachScriptDebugger): (WebFrame::windowObjectCleared):
  • WebScriptDebugger.cpp: (WebScriptDebugger::WebScriptDebugger):
  • Property svn:eol-style set to native
File size: 21.2 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, 2004, 2005, 2006 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 Street, Fifth Floor,
21 * Boston, MA 02110-1301, USA.
22 *
23 */
24
25#ifndef KJS_OBJECT_H
26#define KJS_OBJECT_H
27
28#include "CommonIdentifiers.h"
29#include "ExecState.h"
30#include "JSType.h"
31#include "list.h"
32#include "property_map.h"
33#include "property_slot.h"
34#include "scope_chain.h"
35
36namespace KJS {
37
38 class InternalFunctionImp;
39 class PropertyNameArray;
40
41 struct HashEntry;
42 struct HashTable;
43
44 // ECMA 262-3 8.6.1
45 // Property attributes
46 enum Attribute { None = 0,
47 ReadOnly = 1 << 1, // property can be only read, not written
48 DontEnum = 1 << 2, // property doesn't appear in (for .. in ..)
49 DontDelete = 1 << 3, // property can't be deleted
50 Internal = 1 << 4, // an internal property, set to bypass checks
51 Function = 1 << 5, // property is a function - only used by static hashtables
52 GetterSetter = 1 << 6 }; // property is a getter or setter
53
54 /**
55 * Class Information
56 */
57 struct ClassInfo {
58 /**
59 * A string denoting the class name. Example: "Window".
60 */
61 const char* className;
62 /**
63 * Pointer to the class information of the base class.
64 * 0L if there is none.
65 */
66 const ClassInfo* parentClass;
67 /**
68 * Static hash-table of properties.
69 */
70 const HashTable* propHashTable;
71 };
72
73 // This is an internal value object which stores getter and setter functions
74 // for a property.
75 class GetterSetterImp : public JSCell {
76 public:
77 JSType type() const { return GetterSetterType; }
78
79 GetterSetterImp() : getter(0), setter(0) { }
80
81 virtual JSValue* toPrimitive(ExecState*, JSType preferred = UnspecifiedType) const;
82 virtual bool getPrimitiveNumber(ExecState*, double& number, JSValue*& value);
83 virtual bool toBoolean(ExecState *exec) const;
84 virtual double toNumber(ExecState *exec) const;
85 virtual UString toString(ExecState *exec) const;
86 virtual JSObject *toObject(ExecState *exec) const;
87
88 virtual void mark();
89
90 JSObject *getGetter() { return getter; }
91 void setGetter(JSObject *g) { getter = g; }
92 JSObject *getSetter() { return setter; }
93 void setSetter(JSObject *s) { setter = s; }
94
95 private:
96 JSObject *getter;
97 JSObject *setter;
98 };
99
100 class JSObject : public JSCell {
101 public:
102 /**
103 * Creates a new JSObject with the specified prototype
104 *
105 * @param proto The prototype
106 */
107 JSObject(JSValue* proto);
108
109 /**
110 * Creates a new JSObject with a prototype of jsNull()
111 * (that is, the ECMAScript "null" value, not a null object pointer).
112 */
113 JSObject();
114
115 virtual void mark();
116 virtual JSType type() const;
117
118 /**
119 * A pointer to a ClassInfo struct for this class. This provides a basic
120 * facility for run-time type information, and can be used to check an
121 * object's class an inheritance (see inherits()). This should
122 * always return a statically declared pointer, or 0 to indicate that
123 * there is no class information.
124 *
125 * This is primarily useful if you have application-defined classes that you
126 * wish to check against for casting purposes.
127 *
128 * For example, to specify the class info for classes FooImp and BarImp,
129 * where FooImp inherits from BarImp, you would add the following in your
130 * class declarations:
131 *
132 * \code
133 * class BarImp : public JSObject {
134 * virtual const ClassInfo *classInfo() const { return &info; }
135 * static const ClassInfo info;
136 * // ...
137 * };
138 *
139 * class FooImp : public JSObject {
140 * virtual const ClassInfo *classInfo() const { return &info; }
141 * static const ClassInfo info;
142 * // ...
143 * };
144 * \endcode
145 *
146 * And in your source file:
147 *
148 * \code
149 * const ClassInfo BarImp::info = { "Bar", 0, 0 }; // no parent class
150 * const ClassInfo FooImp::info = { "Foo", &BarImp::info, 0 };
151 * \endcode
152 *
153 * @see inherits()
154 */
155 virtual const ClassInfo *classInfo() const;
156
157 /**
158 * Checks whether this object inherits from the class with the specified
159 * classInfo() pointer. This requires that both this class and the other
160 * class return a non-NULL pointer for their classInfo() methods (otherwise
161 * it will return false).
162 *
163 * For example, for two JSObject pointers obj1 and obj2, you can check
164 * if obj1's class inherits from obj2's class using the following:
165 *
166 * if (obj1->inherits(obj2->classInfo())) {
167 * // ...
168 * }
169 *
170 * If you have a handle to a statically declared ClassInfo, such as in the
171 * classInfo() example, you can check for inheritance without needing
172 * an instance of the other class:
173 *
174 * if (obj1->inherits(FooImp::info)) {
175 * // ...
176 * }
177 *
178 * @param cinfo The ClassInfo pointer for the class you want to check
179 * inheritance against.
180 * @return true if this object's class inherits from class with the
181 * ClassInfo pointer specified in cinfo
182 */
183 bool inherits(const ClassInfo *cinfo) const;
184
185 // internal properties (ECMA 262-3 8.6.2)
186
187 /**
188 * Returns the prototype of this object. Note that this is not the same as
189 * the "prototype" property.
190 *
191 * See ECMA 8.6.2
192 *
193 * @return The object's prototype
194 */
195 JSValue *prototype() const;
196 void setPrototype(JSValue *proto);
197
198 /**
199 * Returns the class name of the object
200 *
201 * See ECMA 8.6.2
202 *
203 * @return The object's class name
204 */
205 /**
206 * Implementation of the [[Class]] internal property (implemented by all
207 * Objects)
208 *
209 * The default implementation uses classInfo().
210 * You should either implement classInfo(), or
211 * if you simply need a classname, you can reimplement className()
212 * instead.
213 */
214 virtual UString className() const;
215
216 /**
217 * Retrieves the specified property from the object. If neither the object
218 * or any other object in it's prototype chain have the property, this
219 * function will return Undefined.
220 *
221 * See ECMA 8.6.2.1
222 *
223 * @param exec The current execution state
224 * @param propertyName The name of the property to retrieve
225 *
226 * @return The specified property, or Undefined
227 */
228 JSValue *get(ExecState *exec, const Identifier &propertyName) const;
229 JSValue *get(ExecState *exec, unsigned propertyName) const;
230
231 bool getPropertySlot(ExecState *, const Identifier&, PropertySlot&);
232 bool getPropertySlot(ExecState *, unsigned, PropertySlot&);
233
234 virtual bool getOwnPropertySlot(ExecState *, const Identifier&, PropertySlot&);
235 virtual bool getOwnPropertySlot(ExecState *, unsigned index, PropertySlot&);
236
237 /**
238 * Sets the specified property.
239 *
240 * See ECMA 8.6.2.2
241 *
242 * @param exec The current execution state
243 * @param propertyName The name of the property to set
244 * @param propertyValue The value to set
245 */
246 virtual void put(ExecState* exec, const Identifier &propertyName, JSValue* value, int attr = None);
247 virtual void put(ExecState* exec, unsigned propertyName, JSValue* value, int attr = None);
248
249 /**
250 * Used to check whether or not a particular property is allowed to be set
251 * on an object
252 *
253 * See ECMA 8.6.2.3
254 *
255 * @param exec The current execution state
256 * @param propertyName The name of the property
257 * @return true if the property can be set, otherwise false
258 */
259 /**
260 * Implementation of the [[CanPut]] internal property (implemented by all
261 * Objects)
262 */
263 virtual bool canPut(ExecState *exec, const Identifier &propertyName) const;
264
265 /**
266 * Checks if a property is enumerable, that is if it doesn't have the DontEnum
267 * flag set
268 *
269 * See ECMA 15.2.4
270 * @param exec The current execution state
271 * @param propertyName The name of the property
272 * @return true if the property is enumerable, otherwise false
273 */
274 bool propertyIsEnumerable(ExecState *exec, const Identifier &propertyName) const;
275
276 /**
277 * Checks to see whether the object (or any object in it's prototype chain)
278 * has a property with the specified name.
279 *
280 * See ECMA 8.6.2.4
281 *
282 * @param exec The current execution state
283 * @param propertyName The name of the property to check for
284 * @return true if the object has the property, otherwise false
285 */
286 bool hasProperty(ExecState *exec, const Identifier &propertyName) const;
287 bool hasProperty(ExecState *exec, unsigned propertyName) const;
288
289 /**
290 * Removes the specified property from the object.
291 *
292 * See ECMA 8.6.2.5
293 *
294 * @param exec The current execution state
295 * @param propertyName The name of the property to delete
296 * @return true if the property was successfully deleted or did not
297 * exist on the object. false if deleting the specified property is not
298 * allowed.
299 */
300 virtual bool deleteProperty(ExecState *exec, const Identifier &propertyName);
301 virtual bool deleteProperty(ExecState *exec, unsigned propertyName);
302
303 /**
304 * Converts the object into a primitive value. The value return may differ
305 * depending on the supplied hint
306 *
307 * See ECMA 8.6.2.6
308 *
309 * @param exec The current execution state
310 * @param hint The desired primitive type to convert to
311 * @return A primitive value converted from the objetc. Note that the
312 * type of primitive value returned may not be the same as the requested
313 * hint.
314 */
315 /**
316 * Implementation of the [[DefaultValue]] internal property (implemented by
317 * all Objects)
318 */
319 virtual JSValue *defaultValue(ExecState *exec, JSType hint) const;
320
321 /**
322 * Whether or not the object implements the construct() method. If this
323 * returns false you should not call the construct() method on this
324 * object (typically, an assertion will fail to indicate this).
325 *
326 * @return true if this object implements the construct() method, otherwise
327 * false
328 */
329 virtual bool implementsConstruct() const;
330
331 /**
332 * Creates a new object based on this object. Typically this means the
333 * following:
334 * 1. A new object is created
335 * 2. The prototype of the new object is set to the value of this object's
336 * "prototype" property
337 * 3. The call() method of this object is called, with the new object
338 * passed as the this value
339 * 4. The new object is returned
340 *
341 * In some cases, Host objects may differ from these semantics, although
342 * this is discouraged.
343 *
344 * If an error occurs during construction, the execution state's exception
345 * will be set. This can be tested for with ExecState::hadException().
346 * Under some circumstances, the exception object may also be returned.
347 *
348 * Note: This function should not be called if implementsConstruct() returns
349 * false, in which case it will result in an assertion failure.
350 *
351 * @param exec The current execution state
352 * @param args The arguments to be passed to call() once the new object has
353 * been created
354 * @return The newly created &amp; initialized object
355 */
356 /**
357 * Implementation of the [[Construct]] internal property
358 */
359 virtual JSObject* construct(ExecState* exec, const List& args);
360 virtual JSObject* construct(ExecState* exec, const List& args, const Identifier& functionName, const UString& sourceURL, int lineNumber);
361
362 /**
363 * Whether or not the object implements the call() method. If this returns
364 * false you should not call the call() method on this object (typically,
365 * an assertion will fail to indicate this).
366 *
367 * @return true if this object implements the call() method, otherwise
368 * false
369 */
370 virtual bool implementsCall() const;
371
372 /**
373 * Calls this object as if it is a function.
374 *
375 * Note: This function should not be called if implementsCall() returns
376 * false, in which case it will result in an assertion failure.
377 *
378 * See ECMA 8.6.2.3
379 *
380 * @param exec The current execution state
381 * @param thisObj The obj to be used as "this" within function execution.
382 * Note that in most cases this will be different from the C++ "this"
383 * object. For example, if the ECMAScript code "window.location->toString()"
384 * is executed, call() will be invoked on the C++ object which implements
385 * the toString method, with the thisObj being window.location
386 * @param args List of arguments to be passed to the function
387 * @return The return value from the function
388 */
389 JSValue *call(ExecState *exec, JSObject *thisObj, const List &args);
390 virtual JSValue *callAsFunction(ExecState *exec, JSObject *thisObj, const List &args);
391
392 /**
393 * Whether or not the object implements the hasInstance() method. If this
394 * returns false you should not call the hasInstance() method on this
395 * object (typically, an assertion will fail to indicate this).
396 *
397 * @return true if this object implements the hasInstance() method,
398 * otherwise false
399 */
400 virtual bool implementsHasInstance() const;
401
402 /**
403 * Checks whether value delegates behavior to this object. Used by the
404 * instanceof operator.
405 *
406 * @param exec The current execution state
407 * @param value The value to check
408 * @return true if value delegates behavior to this object, otherwise
409 * false
410 */
411 virtual bool hasInstance(ExecState *exec, JSValue *value);
412
413 virtual void getPropertyNames(ExecState*, PropertyNameArray&);
414
415 virtual JSValue* toPrimitive(ExecState*, JSType preferredType = UnspecifiedType) const;
416 virtual bool getPrimitiveNumber(ExecState*, double& number, JSValue*& value);
417 virtual bool toBoolean(ExecState *exec) const;
418 virtual double toNumber(ExecState *exec) const;
419 virtual UString toString(ExecState *exec) const;
420 virtual JSObject *toObject(ExecState *exec) const;
421
422 bool getPropertyAttributes(const Identifier& propertyName, unsigned& attributes) const;
423
424 // WebCore uses this to make document.all and style.filter undetectable
425 virtual bool masqueradeAsUndefined() const { return false; }
426
427 // This get function only looks at the property map.
428 // This is used e.g. by lookupOrCreateFunction (to cache a function, we don't want
429 // to look up in the prototype, it might already exist there)
430 JSValue *getDirect(const Identifier& propertyName) const
431 { return _prop.get(propertyName); }
432 JSValue **getDirectLocation(const Identifier& propertyName)
433 { return _prop.getLocation(propertyName); }
434 void putDirect(const Identifier &propertyName, JSValue *value, int attr = 0);
435 void putDirect(const Identifier &propertyName, int value, int attr = 0);
436 void removeDirect(const Identifier &propertyName);
437
438 // convenience to add a function property under the function's own built-in name
439 void putDirectFunction(InternalFunctionImp*, int attr = 0);
440
441 void fillGetterPropertySlot(PropertySlot& slot, JSValue **location);
442
443 void defineGetter(ExecState *exec, const Identifier& propertyName, JSObject *getterFunc);
444 void defineSetter(ExecState *exec, const Identifier& propertyName, JSObject *setterFunc);
445
446 /**
447 * Remove all properties from this object.
448 * This doesn't take DontDelete into account, and isn't in the ECMA spec.
449 * It's simply a quick way to remove everything stored in the property map.
450 */
451 void clearProperties() { _prop.clear(); }
452
453 void saveProperties(SavedProperties &p) const { _prop.save(p); }
454 void restoreProperties(const SavedProperties &p) { _prop.restore(p); }
455
456 virtual bool isActivation() { return false; }
457 virtual bool isGlobalObject() const { return false; }
458 protected:
459 PropertyMap _prop;
460 private:
461 const HashEntry* findPropertyHashEntry( const Identifier& propertyName ) const;
462 JSValue *_proto;
463 };
464
465 /**
466 * Types of Native Errors available. For custom errors, GeneralError
467 * should be used.
468 */
469 enum ErrorType { GeneralError = 0,
470 EvalError = 1,
471 RangeError = 2,
472 ReferenceError = 3,
473 SyntaxError = 4,
474 TypeError = 5,
475 URIError = 6};
476
477 /**
478 * @short Factory methods for error objects.
479 */
480 class Error {
481 public:
482 /**
483 * Factory method for error objects.
484 *
485 * @param exec The current execution state
486 * @param errtype Type of error.
487 * @param message Optional error message.
488 * @param lineNumber Optional line number.
489 * @param sourceId Optional source id.
490 * @param sourceURL Optional source URL.
491 */
492 static JSObject *create(ExecState *, ErrorType, const UString &message, int lineNumber, int sourceId, const UString &sourceURL);
493 static JSObject *create(ExecState *, ErrorType, const char *message);
494
495 /**
496 * Array of error names corresponding to ErrorType
497 */
498 static const char * const * const errorNames;
499 };
500
501JSObject *throwError(ExecState *, ErrorType, const UString &message, int lineNumber, int sourceId, const UString &sourceURL);
502JSObject *throwError(ExecState *, ErrorType, const UString &message);
503JSObject *throwError(ExecState *, ErrorType, const char *message);
504JSObject *throwError(ExecState *, ErrorType);
505
506inline JSObject::JSObject(JSValue* proto)
507 : _proto(proto)
508{
509 ASSERT(proto);
510}
511
512inline JSObject::JSObject()
513 : _proto(jsNull())
514{
515}
516
517inline JSValue *JSObject::prototype() const
518{
519 return _proto;
520}
521
522inline void JSObject::setPrototype(JSValue *proto)
523{
524 ASSERT(proto);
525 _proto = proto;
526}
527
528inline bool JSObject::inherits(const ClassInfo *info) const
529{
530 for (const ClassInfo *ci = classInfo(); ci; ci = ci->parentClass)
531 if (ci == info)
532 return true;
533 return false;
534}
535
536// this method is here to be after the inline declaration of JSObject::inherits
537inline bool JSCell::isObject(const ClassInfo *info) const
538{
539 return isObject() && static_cast<const JSObject *>(this)->inherits(info);
540}
541
542// this method is here to be after the inline declaration of JSCell::isObject
543inline bool JSValue::isObject(const ClassInfo *c) const
544{
545 return !JSImmediate::isImmediate(this) && asCell()->isObject(c);
546}
547
548// It may seem crazy to inline a function this large but it makes a big difference
549// since this is function very hot in variable lookup
550inline bool JSObject::getPropertySlot(ExecState *exec, const Identifier& propertyName, PropertySlot& slot)
551{
552 JSObject *object = this;
553 while (true) {
554 if (object->getOwnPropertySlot(exec, propertyName, slot))
555 return true;
556
557 JSValue *proto = object->_proto;
558 if (!proto->isObject())
559 return false;
560
561 object = static_cast<JSObject *>(proto);
562 }
563}
564
565// It may seem crazy to inline a function this large, especially a virtual function,
566// but it makes a big difference to property lookup that derived classes can inline their
567// base class call to this.
568ALWAYS_INLINE bool JSObject::getOwnPropertySlot(ExecState* exec, const Identifier& propertyName, PropertySlot& slot)
569{
570 if (JSValue **location = getDirectLocation(propertyName)) {
571 if (_prop.hasGetterSetterProperties() && location[0]->type() == GetterSetterType)
572 fillGetterPropertySlot(slot, location);
573 else
574 slot.setValueSlot(this, location);
575 return true;
576 }
577
578 // non-standard Netscape extension
579 if (propertyName == exec->propertyNames().underscoreProto) {
580 slot.setValueSlot(this, &_proto);
581 return true;
582 }
583
584 return false;
585}
586
587
588// FIXME: Put this function in a separate file named something like scope_chain_mark.h -- can't put it in scope_chain.h since it depends on JSObject.
589
590inline void ScopeChain::mark()
591{
592 for (ScopeChainNode *n = _node; n; n = n->next) {
593 JSObject *o = n->object;
594 if (!o->marked())
595 o->mark();
596 }
597}
598
599inline void ScopeChain::release()
600{
601 // This function is only called by deref(),
602 // Deref ensures these conditions are true.
603 ASSERT(_node && _node->refCount == 0);
604 ScopeChainNode *n = _node;
605 do {
606 ScopeChainNode *next = n->next;
607 delete n;
608 n = next;
609 } while (n && --n->refCount == 0);
610}
611
612inline JSValue* JSObject::toPrimitive(ExecState* exec, JSType preferredType) const
613{
614 return defaultValue(exec, preferredType);
615}
616
617} // namespace
618
619#endif // KJS_OBJECT_H
Note: See TracBrowser for help on using the repository browser.