source: webkit/trunk/JavaScriptCore/kjs/JSObject.cpp@ 34854

Last change on this file since 34854 was 34821, checked in by Darin Adler, 17 years ago

2008-06-26 Darin Adler <Darin Adler>

Reviewed by Geoff.

  • optimize UString append and the replace function a bit

SunSpider says 1.8% faster.

  • VM/JSPropertyNameIterator.cpp: Added include of JSString.h, now needed because jsString returns a JSString*.
  • VM/Machine.cpp: (KJS::Machine::privateExecute): Removed the toObject call from native function calls. Also removed code to put the this value into a register.
  • kjs/BooleanObject.cpp: (KJS::booleanProtoFuncToString): Rewrite to handle false and true separately.
  • kjs/FunctionPrototype.cpp: (KJS::constructFunction): Use single-character append rather than building a string for each character.
  • kjs/JSFunction.cpp: (KJS::globalFuncUnescape): Ditto.
  • kjs/JSImmediate.cpp: (KJS::JSImmediate::prototype): Added. Gets the appropriate prototype for use with an immediate value. To be used instead of toObject when doing a get on an immediate value.
  • kjs/JSImmediate.h: Added prototype.
  • kjs/JSObject.cpp: (KJS::JSObject::toString): Tweaked formatting.
  • kjs/JSObject.h: (KJS::JSValue::get): Use prototype instead of toObject to avoid creating an object wrapper just to search for properties. This also saves an unnecessary hash table lookup since the object wrappers themselves don't have any properties.
  • kjs/JSString.h: Added toThisString and toThisJSString.
  • kjs/JSValue.cpp: (KJS::JSCell::toThisString): Added. (KJS::JSCell::toThisJSString): Added. (KJS::JSCell::getJSNumber): Added. (KJS::jsString): Changed return type to JSString*. (KJS::jsOwnedString): Ditto.
  • kjs/JSValue.h: (KJS::JSValue::toThisString): Added. (KJS::JSValue::toThisJSString): Added. (KJS::JSValue::getJSNumber): Added.
  • kjs/NumberObject.cpp: (KJS::NumberObject::getJSNumber): Added. (KJS::integer_part_noexp): Append C string directly rather than first turning it into a UString. (KJS::numberProtoFuncToString): Use getJSNumber to check if the value is a number rather than isObject(&NumberObject::info). This works for immediate numbers, number cells, and NumberObject instances. (KJS::numberProtoFuncToLocaleString): Ditto. (KJS::numberProtoFuncValueOf): Ditto. (KJS::numberProtoFuncToFixed): Ditto. (KJS::numberProtoFuncToExponential): Ditto. (KJS::numberProtoFuncToPrecision): Ditto.
  • kjs/NumberObject.h: Added getJSNumber.
  • kjs/PropertySlot.cpp: Tweaked comment.
  • kjs/internal.cpp: (KJS::JSString::toThisString): Added. (KJS::JSString::toThisJSString): Added. (KJS::JSString::getOwnPropertySlot): Changed code that searches the prototype chain to start with the string prototype and not create a string object. (KJS::JSNumberCell::toThisString): Added. (KJS::JSNumberCell::getJSNumber): Added.
  • kjs/lookup.cpp: (KJS::staticFunctionGetter): Moved here, because there's no point in having a function that's only used for a function pointer be inline. (KJS::setUpStaticFunctionSlot): New function for getStaticFunctionSlot.
  • kjs/lookup.h: (KJS::staticValueGetter): Don't mark this inline. It doesn't make sense to have a function that's only used for a function pointer be inline. (KJS::getStaticFunctionSlot): Changed to get properties from the parent first before doing any handling of functions. This is the fastest way to return the function once the initial setup is done.
  • kjs/string_object.cpp: (KJS::StringObject::getPropertyNames): Call value() instead of getString(), avoiding an unnecessary virtual function call (the call to the type() function in the implementation of the isString() function). (KJS::StringObject::toString): Added. (KJS::StringObject::toThisString): Added. (KJS::StringObject::toThisJSString): Added. (KJS::substituteBackreferences): Rewrote to use a appending algorithm instead of a the old one that tried to replace in place. (KJS::stringProtoFuncReplace): Merged this function and the replace function. Replaced the hand-rolled dynamic arrays for source ranges and replacements with Vector. (KJS::stringProtoFuncToString): Handle JSString as well as StringObject. Removed the separate valueOf implementation, since it can just share this. (KJS::stringProtoFuncCharAt): Use toThisString, which handles JSString as well as StringObject, and is slightly more efficient than the old code too. (KJS::stringProtoFuncCharCodeAt): Ditto. (KJS::stringProtoFuncConcat): Ditto. (KJS::stringProtoFuncIndexOf): Ditto. (KJS::stringProtoFuncLastIndexOf): Ditto. (KJS::stringProtoFuncMatch): Ditto. (KJS::stringProtoFuncSearch): Ditto. (KJS::stringProtoFuncSlice): Ditto. (KJS::stringProtoFuncSplit): Ditto. (KJS::stringProtoFuncSubstr): Ditto. (KJS::stringProtoFuncSubstring): Ditto. (KJS::stringProtoFuncToLowerCase): Use toThisJSString. (KJS::stringProtoFuncToUpperCase): Ditto. (KJS::stringProtoFuncToLocaleLowerCase): Ditto. (KJS::stringProtoFuncToLocaleUpperCase): Ditto. (KJS::stringProtoFuncLocaleCompare): Ditto. (KJS::stringProtoFuncBig): Use toThisString. (KJS::stringProtoFuncSmall): Ditto. (KJS::stringProtoFuncBlink): Ditto. (KJS::stringProtoFuncBold): Ditto. (KJS::stringProtoFuncFixed): Ditto. (KJS::stringProtoFuncItalics): Ditto. (KJS::stringProtoFuncStrike): Ditto. (KJS::stringProtoFuncSub): Ditto. (KJS::stringProtoFuncSup): Ditto. (KJS::stringProtoFuncFontcolor): Ditto. (KJS::stringProtoFuncFontsize): Ditto. (KJS::stringProtoFuncAnchor): Ditto. (KJS::stringProtoFuncLink): Ditto.
  • kjs/string_object.h: Added toString, toThisString, and toThisJSString.
  • kjs/ustring.cpp: (KJS::UString::append): Added a version that takes a character pointer and size, so we don't have to create a UString just to append to another UString.
  • kjs/ustring.h:
  • Property svn:eol-style set to native
File size: 16.5 KB
Line 
1// -*- c-basic-offset: 2 -*-
2/*
3 * Copyright (C) 1999-2001 Harri Porten ([email protected])
4 * Copyright (C) 2001 Peter Kelly ([email protected])
5 * Copyright (C) 2003, 2004, 2005, 2006, 2008 Apple Inc. All rights reserved.
6 * Copyright (C) 2007 Eric Seidel ([email protected])
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#include "config.h"
26#include "JSObject.h"
27
28#include "date_object.h"
29#include "error_object.h"
30#include "nodes.h"
31#include "operations.h"
32#include "PropertyNameArray.h"
33#include <math.h>
34#include <profiler/Profiler.h>
35#include <wtf/Assertions.h>
36
37#define JAVASCRIPT_MARK_TRACING 0
38
39namespace KJS {
40
41// ------------------------------ JSObject ------------------------------------
42
43void JSObject::mark()
44{
45 JSCell::mark();
46
47#if JAVASCRIPT_MARK_TRACING
48 static int markStackDepth = 0;
49 markStackDepth++;
50 for (int i = 0; i < markStackDepth; i++)
51 putchar('-');
52
53 printf("%s (%p)\n", className().UTF8String().c_str(), this);
54#endif
55
56 JSValue *proto = _proto;
57 if (!proto->marked())
58 proto->mark();
59
60 _prop.mark();
61
62#if JAVASCRIPT_MARK_TRACING
63 markStackDepth--;
64#endif
65}
66
67JSType JSObject::type() const
68{
69 return ObjectType;
70}
71
72UString JSObject::className() const
73{
74 const ClassInfo *ci = classInfo();
75 if ( ci )
76 return ci->className;
77 return "Object";
78}
79
80bool JSObject::getOwnPropertySlot(ExecState *exec, unsigned propertyName, PropertySlot& slot)
81{
82 return getOwnPropertySlot(exec, Identifier::from(exec, propertyName), slot);
83}
84
85static void throwSetterError(ExecState *exec)
86{
87 throwError(exec, TypeError, "setting a property that has only a getter");
88}
89
90// ECMA 8.6.2.2
91void JSObject::put(ExecState* exec, const Identifier& propertyName, JSValue* value)
92{
93 ASSERT(value);
94 ASSERT(!Heap::heap(value) || Heap::heap(value) == Heap::heap(this));
95
96 if (propertyName == exec->propertyNames().underscoreProto) {
97 JSObject* proto = value->getObject();
98
99 // Setting __proto__ to a non-object, non-null value is silently ignored to match Mozilla.
100 if (!proto && value != jsNull())
101 return;
102
103 while (proto) {
104 if (proto == this) {
105 throwError(exec, GeneralError, "cyclic __proto__ value");
106 return;
107 }
108 proto = proto->prototype() ? proto->prototype()->getObject() : 0;
109 }
110
111 setPrototype(value);
112 return;
113 }
114
115 // Check if there are any setters or getters in the prototype chain
116 JSValue* prototype;
117 for (JSObject* obj = this; !obj->_prop.hasGetterSetterProperties(); obj = static_cast<JSObject*>(prototype)) {
118 prototype = obj->_proto;
119 if (prototype == jsNull()) {
120 _prop.put(propertyName, value, 0, true);
121 return;
122 }
123 }
124
125 unsigned attributes;
126 if (_prop.get(propertyName, attributes) && attributes & ReadOnly)
127 return;
128
129 for (JSObject* obj = this; ; obj = static_cast<JSObject*>(prototype)) {
130 if (JSValue* gs = obj->_prop.get(propertyName, attributes)) {
131 if (attributes & IsGetterSetter) {
132 JSObject* setterFunc = static_cast<GetterSetter*>(gs)->setter();
133 if (!setterFunc) {
134 throwSetterError(exec);
135 return;
136 }
137
138 CallData callData;
139 CallType callType = setterFunc->getCallData(callData);
140 ArgList args;
141 args.append(value);
142 call(exec, setterFunc, callType, callData, this, args);
143 return;
144 }
145
146 // If there's an existing property on the object or one of its
147 // prototypes it should be replaced, so break here.
148 break;
149 }
150
151 prototype = obj->_proto;
152 if (prototype == jsNull())
153 break;
154 }
155
156 _prop.put(propertyName, value, 0, true);
157}
158
159void JSObject::put(ExecState* exec, unsigned propertyName, JSValue* value)
160{
161 put(exec, Identifier::from(exec, propertyName), value);
162}
163
164void JSObject::putWithAttributes(ExecState*, const Identifier& propertyName, JSValue* value, unsigned attributes)
165{
166 putDirect(propertyName, value, attributes);
167}
168
169void JSObject::putWithAttributes(ExecState* exec, unsigned propertyName, JSValue* value, unsigned attributes)
170{
171 putWithAttributes(exec, Identifier::from(exec, propertyName), value, attributes);
172}
173
174bool JSObject::hasProperty(ExecState *exec, const Identifier &propertyName) const
175{
176 PropertySlot slot;
177 return const_cast<JSObject *>(this)->getPropertySlot(exec, propertyName, slot);
178}
179
180bool JSObject::hasProperty(ExecState *exec, unsigned propertyName) const
181{
182 PropertySlot slot;
183 return const_cast<JSObject *>(this)->getPropertySlot(exec, propertyName, slot);
184}
185
186// ECMA 8.6.2.5
187bool JSObject::deleteProperty(ExecState* exec, const Identifier &propertyName)
188{
189 unsigned attributes;
190 JSValue *v = _prop.get(propertyName, attributes);
191 if (v) {
192 if ((attributes & DontDelete))
193 return false;
194 _prop.remove(propertyName);
195 if (attributes & IsGetterSetter)
196 _prop.setHasGetterSetterProperties(_prop.containsGettersOrSetters());
197 return true;
198 }
199
200 // Look in the static hashtable of properties
201 const HashEntry* entry = findPropertyHashEntry(exec, propertyName);
202 if (entry && entry->attributes & DontDelete)
203 return false; // this builtin property can't be deleted
204 // FIXME: Should the code here actually do some deletion?
205 return true;
206}
207
208bool JSObject::hasOwnProperty(ExecState* exec, const Identifier& propertyName) const
209{
210 PropertySlot slot;
211 return const_cast<JSObject*>(this)->getOwnPropertySlot(exec, propertyName, slot);
212}
213
214bool JSObject::deleteProperty(ExecState *exec, unsigned propertyName)
215{
216 return deleteProperty(exec, Identifier::from(exec, propertyName));
217}
218
219static ALWAYS_INLINE JSValue* callDefaultValueFunction(ExecState* exec, const JSObject* object, const Identifier& propertyName)
220{
221 JSValue* function = object->get(exec, propertyName);
222 CallData callData;
223 CallType callType = function->getCallData(callData);
224 if (callType == CallTypeNone)
225 return 0;
226 JSValue* result = call(exec, function, callType, callData, const_cast<JSObject*>(object), exec->emptyList());
227 ASSERT(result->type() != GetterSetterType);
228 if (exec->hadException())
229 return exec->exception();
230 if (result->isObject())
231 return 0;
232 return result;
233}
234
235bool JSObject::getPrimitiveNumber(ExecState* exec, double& number, JSValue*& result)
236{
237 result = defaultValue(exec, NumberType);
238 number = result->toNumber(exec);
239 return !result->isString();
240}
241
242// ECMA 8.6.2.6
243JSValue* JSObject::defaultValue(ExecState* exec, JSType hint) const
244{
245 // We need this check to guard against the case where this object is rhs of
246 // a binary expression where lhs threw an exception in its conversion to
247 // primitive.
248 if (exec->hadException())
249 return exec->exception();
250
251 // Must call toString first for Date objects.
252 if ((hint == StringType) || (hint != NumberType && _proto == exec->lexicalGlobalObject()->datePrototype())) {
253 if (JSValue* value = callDefaultValueFunction(exec, this, exec->propertyNames().toString))
254 return value;
255 if (JSValue* value = callDefaultValueFunction(exec, this, exec->propertyNames().valueOf))
256 return value;
257 } else {
258 if (JSValue* value = callDefaultValueFunction(exec, this, exec->propertyNames().valueOf))
259 return value;
260 if (JSValue* value = callDefaultValueFunction(exec, this, exec->propertyNames().toString))
261 return value;
262 }
263
264 ASSERT(!exec->hadException());
265
266 return throwError(exec, TypeError, "No default value");
267}
268
269const HashEntry* JSObject::findPropertyHashEntry(ExecState* exec, const Identifier& propertyName) const
270{
271 for (const ClassInfo* info = classInfo(); info; info = info->parentClass) {
272 if (const HashTable* propHashTable = info->propHashTable(exec)) {
273 if (const HashEntry* e = propHashTable->entry(exec, propertyName))
274 return e;
275 }
276 }
277 return 0;
278}
279
280void JSObject::defineGetter(ExecState* exec, const Identifier& propertyName, JSObject* getterFunc)
281{
282 JSValue *o = getDirect(propertyName);
283 GetterSetter *gs;
284
285 if (o && o->type() == GetterSetterType) {
286 gs = static_cast<GetterSetter *>(o);
287 } else {
288 gs = new (exec) GetterSetter;
289 putDirect(propertyName, gs, IsGetterSetter);
290 }
291
292 _prop.setHasGetterSetterProperties(true);
293 gs->setGetter(getterFunc);
294}
295
296void JSObject::defineSetter(ExecState* exec, const Identifier& propertyName, JSObject* setterFunc)
297{
298 JSValue *o = getDirect(propertyName);
299 GetterSetter *gs;
300
301 if (o && o->type() == GetterSetterType) {
302 gs = static_cast<GetterSetter *>(o);
303 } else {
304 gs = new (exec) GetterSetter;
305 putDirect(propertyName, gs, IsGetterSetter);
306 }
307
308 _prop.setHasGetterSetterProperties(true);
309 gs->setSetter(setterFunc);
310}
311
312JSValue* JSObject::lookupGetter(ExecState*, const Identifier& propertyName)
313{
314 JSObject* obj = this;
315 while (true) {
316 JSValue* v = obj->getDirect(propertyName);
317 if (v) {
318 if (v->type() != GetterSetterType)
319 return jsUndefined();
320 JSObject* funcObj = static_cast<GetterSetter*>(v)->getter();
321 if (!funcObj)
322 return jsUndefined();
323 return funcObj;
324 }
325
326 if (!obj->prototype() || !obj->prototype()->isObject())
327 return jsUndefined();
328 obj = static_cast<JSObject*>(obj->prototype());
329 }
330}
331
332JSValue* JSObject::lookupSetter(ExecState*, const Identifier& propertyName)
333{
334 JSObject* obj = this;
335 while (true) {
336 JSValue* v = obj->getDirect(propertyName);
337 if (v) {
338 if (v->type() != GetterSetterType)
339 return jsUndefined();
340 JSObject* funcObj = static_cast<GetterSetter*>(v)->setter();
341 if (!funcObj)
342 return jsUndefined();
343 return funcObj;
344 }
345
346 if (!obj->prototype() || !obj->prototype()->isObject())
347 return jsUndefined();
348 obj = static_cast<JSObject*>(obj->prototype());
349 }
350}
351
352bool JSObject::implementsHasInstance() const
353{
354 return false;
355}
356
357bool JSObject::hasInstance(ExecState* exec, JSValue* value)
358{
359 JSValue* proto = get(exec, exec->propertyNames().prototype);
360 if (!proto->isObject()) {
361 throwError(exec, TypeError, "instanceof called on an object with an invalid prototype property.");
362 return false;
363 }
364
365 if (!value->isObject())
366 return false;
367
368 JSObject* o = static_cast<JSObject*>(value);
369 while ((o = o->prototype()->getObject())) {
370 if (o == proto)
371 return true;
372 }
373 return false;
374}
375
376bool JSObject::propertyIsEnumerable(ExecState* exec, const Identifier& propertyName) const
377{
378 unsigned attributes;
379
380 if (!getPropertyAttributes(exec, propertyName, attributes))
381 return false;
382 else
383 return !(attributes & DontEnum);
384}
385
386bool JSObject::getPropertyAttributes(ExecState* exec, const Identifier& propertyName, unsigned& attributes) const
387{
388 if (_prop.get(propertyName, attributes))
389 return true;
390
391 // Look in the static hashtable of properties
392 const HashEntry* e = findPropertyHashEntry(exec, propertyName);
393 if (e) {
394 attributes = e->attributes;
395 return true;
396 }
397
398 return false;
399}
400
401void JSObject::getPropertyNames(ExecState* exec, PropertyNameArray& propertyNames)
402{
403 _prop.getEnumerablePropertyNames(propertyNames);
404
405 // Add properties from the static hashtables of properties
406 for (const ClassInfo* info = classInfo(); info; info = info->parentClass) {
407 const HashTable* table = info->propHashTable(exec);
408 if (!table)
409 continue;
410 table->initializeIfNeeded(exec);
411 ASSERT(table->table);
412 int hashSizeMask = table->hashSizeMask;
413 const HashEntry* e = table->table;
414 for (int i = 0; i <= hashSizeMask; ++i, ++e) {
415 if (e->key && !(e->attributes & DontEnum))
416 propertyNames.add(e->key);
417 }
418 }
419
420 if (_proto->isObject())
421 static_cast<JSObject*>(_proto)->getPropertyNames(exec, propertyNames);
422}
423
424bool JSObject::toBoolean(ExecState*) const
425{
426 return true;
427}
428
429double JSObject::toNumber(ExecState *exec) const
430{
431 JSValue *prim = toPrimitive(exec,NumberType);
432 if (exec->hadException()) // should be picked up soon in nodes.cpp
433 return 0.0;
434 return prim->toNumber(exec);
435}
436
437UString JSObject::toString(ExecState* exec) const
438{
439 JSValue* primitive = toPrimitive(exec, StringType);
440 if (exec->hadException())
441 return "";
442 return primitive->toString(exec);
443}
444
445JSObject *JSObject::toObject(ExecState*) const
446{
447 return const_cast<JSObject*>(this);
448}
449
450JSObject* JSObject::toThisObject(ExecState*) const
451{
452 return const_cast<JSObject*>(this);
453}
454
455JSGlobalObject* JSObject::toGlobalObject(ExecState*) const
456{
457 return 0;
458}
459
460void JSObject::removeDirect(const Identifier &propertyName)
461{
462 _prop.remove(propertyName);
463}
464
465void JSObject::putDirectFunction(InternalFunction* func, int attr)
466{
467 putDirect(func->functionName(), func, attr);
468}
469
470void JSObject::fillGetterPropertySlot(PropertySlot& slot, JSValue** location)
471{
472 if (JSObject* getterFunc = static_cast<GetterSetter*>(*location)->getter())
473 slot.setGetterSlot(getterFunc);
474 else
475 slot.setUndefined();
476}
477
478// ------------------------------ Error ----------------------------------------
479
480JSObject* Error::create(ExecState* exec, ErrorType errtype, const UString& message,
481 int lineno, int sourceId, const UString& sourceURL)
482{
483 JSObject* cons;
484 const char* name;
485 switch (errtype) {
486 case EvalError:
487 cons = exec->lexicalGlobalObject()->evalErrorConstructor();
488 name = "Evaluation error";
489 break;
490 case RangeError:
491 cons = exec->lexicalGlobalObject()->rangeErrorConstructor();
492 name = "Range error";
493 break;
494 case ReferenceError:
495 cons = exec->lexicalGlobalObject()->referenceErrorConstructor();
496 name = "Reference error";
497 break;
498 case SyntaxError:
499 cons = exec->lexicalGlobalObject()->syntaxErrorConstructor();
500 name = "Syntax error";
501 break;
502 case TypeError:
503 cons = exec->lexicalGlobalObject()->typeErrorConstructor();
504 name = "Type error";
505 break;
506 case URIError:
507 cons = exec->lexicalGlobalObject()->URIErrorConstructor();
508 name = "URI error";
509 break;
510 default:
511 cons = exec->lexicalGlobalObject()->errorConstructor();
512 name = "Error";
513 break;
514 }
515
516 ArgList args;
517 if (message.isEmpty())
518 args.append(jsString(exec, name));
519 else
520 args.append(jsString(exec, message));
521 ConstructData constructData;
522 ConstructType constructType = cons->getConstructData(constructData);
523 JSObject* err = construct(exec, cons, constructType, constructData, args);
524
525 if (lineno != -1)
526 err->put(exec, Identifier(exec, "line"), jsNumber(exec, lineno));
527 if (sourceId != -1)
528 err->put(exec, Identifier(exec, "sourceId"), jsNumber(exec, sourceId));
529
530 if(!sourceURL.isNull())
531 err->put(exec, Identifier(exec, "sourceURL"), jsString(exec, sourceURL));
532
533 return err;
534}
535
536JSObject *Error::create(ExecState *exec, ErrorType type, const char *message)
537{
538 return create(exec, type, message, -1, -1, NULL);
539}
540
541JSObject *throwError(ExecState *exec, ErrorType type)
542{
543 JSObject *error = Error::create(exec, type, UString(), -1, -1, NULL);
544 exec->setException(error);
545 return error;
546}
547
548JSObject *throwError(ExecState *exec, ErrorType type, const UString &message)
549{
550 JSObject *error = Error::create(exec, type, message, -1, -1, NULL);
551 exec->setException(error);
552 return error;
553}
554
555JSObject *throwError(ExecState *exec, ErrorType type, const char *message)
556{
557 JSObject *error = Error::create(exec, type, message, -1, -1, NULL);
558 exec->setException(error);
559 return error;
560}
561
562JSObject *throwError(ExecState *exec, ErrorType type, const UString &message, int line, int sourceId, const UString &sourceURL)
563{
564 JSObject *error = Error::create(exec, type, message, line, sourceId, sourceURL);
565 exec->setException(error);
566 return error;
567}
568
569JSObject* constructEmptyObject(ExecState* exec)
570{
571 return new (exec) JSObject(exec->lexicalGlobalObject()->objectPrototype());
572}
573
574} // namespace KJS
Note: See TracBrowser for help on using the repository browser.