source: webkit/trunk/JavaScriptCore/kjs/object.cpp@ 1799

Last change on this file since 1799 was 1799, checked in by darin, 23 years ago

top level:

  • Tests/WebFoundation-Misc/ifnsurlextensions-test.m: (TestURLCommon): Add tests for the new WebNSURLExtras methods.
  • Tests/libiftest/IFCheckLeaks.c: (IFCheckLeaksAtExit): Remove workaround for CFPreferences race condition; it's now in WebFoundation.

JavaScriptCore:

Speed improvements. 19% faster on cvs-js-performance, 1% on cvs-static-urls.

Use global string objects for length and other common property names rather
than constantly making and destroying them. Use integer versions of get() and
other related calls rather than always making a string.

Also get rid of many unneeded constructors, destructors, copy constructors, and
assignment operators. And make some functions non-virtual.

  • kjs/internal.h:
  • kjs/internal.cpp: (NumberImp::toUInt32): Implement. (ReferenceImp::ReferenceImp): Special case for numeric property names. (ReferenceImp::getPropertyName): Moved guts here from ValueImp. Handle numeric case. (ReferenceImp::getValue): Moved guts here from ValueImp. Handle numeric case. (ReferenceImp::putValue): Moved guts here from ValueImp. Handle numeric case. (ReferenceImp::deleteValue): Added. Handle numeric case.
  • kjs/array_object.h:
  • kjs/array_object.cpp: All-new array implementation that stores the elements in a C++ array rather than in a property map. (ArrayInstanceImp::ArrayInstanceImp): Allocate the C++ array. (ArrayInstanceImp::~ArrayInstanceImp): Delete the C++ array. (ArrayInstanceImp::get): Implement both the old version and the new overload that takes an unsigned index for speed. (ArrayInstanceImp::put): Implement both the old version and the new overload that takes an unsigned index for speed. (ArrayInstanceImp::hasProperty): Implement both the old version and the new overload that takes an unsigned index for speed. (ArrayInstanceImp::deleteProperty): Implement both the old version and the new overload that takes an unsigned index for speed. (ArrayInstanceImp::setLength): Added. Used by the above to resize the array. (ArrayInstanceImp::mark): Mark the elements of the array too. (ArrayPrototypeImp::ArrayPrototypeImp): Pass the length to the array instance constructor.
  • kjs/bool_object.cpp:
  • kjs/date_object.cpp:
  • kjs/error_object.cpp:
  • kjs/function.cpp:
  • kjs/function_object.cpp:
  • kjs/math_object.cpp:
  • kjs/nodes.cpp:
  • kjs/nodes.h:
  • kjs/number_object.cpp:
  • kjs/object_object.cpp:
  • kjs/regexp_object.cpp:
  • kjs/string_object.cpp:
  • kjs/nodes2string.cpp: (SourceStream::operator<<): Add a special case for char now that you can't create a UString from a char implicitly.
  • kjs/object.h:
  • kjs/object.cpp: (ObjectImp::get): Call through to the string version if the numeric version is not implemented. (ObjectImp::put): Call through to the string version if the numeric version is not implemented. (ObjectImp::hasProperty): Call through to the string version if the numeric version is not implemented. (ObjectImp::deleteProperty): Call through to the string version if the numeric version is not implemented.
  • kjs/types.h:
  • kjs/types.cpp: (Reference::Reference): Added constructors for the numeric property name case.
  • kjs/ustring.h: Made the constructor that turns a character into a string be explicit so we don't get numbers that turn themselves into strings.
  • kjs/ustring.cpp: (UString::UString): Detect the empty string case, and use a shared empty string. (UString::find): Add an overload for single character finds. (UString::rfind): Add an overload for single character finds. (KJS::operator==): Fix bug where it would call strlen(0) if the first string was not null. Also handle non-ASCII characters consistently with the rest of the code by casting to unsigned char just in case.
  • kjs/value.h: Make ValueImp and all subclasses non-copyable and non-assignable.
  • kjs/value.cpp: (ValueImp::toUInt32): New interface, mainly useful so we can detect array indices and not turn them into strings and back. (ValueImp::toInteger): Use the new toUInt32. Probably can use more improvement. (ValueImp::toInt32): Use the new toUInt32. Probably can use more improvement. (ValueImp::toUInt16): Use the new toUInt32. Probably can use more improvement. (ValueImp::getBase): Remove handling of the Reference case. That's in ReferenceImp now. (ValueImp::getPropertyName): Remove handling of the Reference case. That's in ReferenceImp now. (ValueImp::getValue): Remove handling of the Reference case. That's in ReferenceImp now. (ValueImp::putValue): Remove handling of the Reference case. That's in ReferenceImp now. (ValueImp::deleteValue): Added. Used so we can do delete the same way we do put.

WebFoundation:

  • CacheLoader.subproj/WebHTTPResourceLoader.m: (-[WebHTTPProtocolHandler createWFLoadRequest]): Fix handling of paths with queries and some other subtle path and port number handling issues by using _web_hostWithPort and _web_pathWithQuery.
  • Misc.subproj/WebNSURLExtras.h:
  • Misc.subproj/WebNSURLExtras.m: (-[NSURL _web_hostWithPort]): Added. (-[NSURL _web_pathWithQuery]): Added.
  • CacheLoader.subproj/WebResourceLoad.m: (initLoader): Get some random preference before creating threads. This makes it impossible to run into the CFPreferences race condition.

WebCore:

  • force-clean-timestamp: Need a full build because of KJS changes.
  • khtml/ecma/kjs_window.h: Need to store an Object, not an ObjectImp, because there's no way to copy an ObjectImp. KJS changes caught this mistake.
  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 13.7 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 *
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., 59 Temple Place - Suite 330,
20 * Boston, MA 02111-1307, USA.
21 *
22 */
23
24#include "value.h"
25#include "object.h"
26#include "types.h"
27#include "interpreter.h"
28#include "lookup.h"
29
30#include <assert.h>
31#include <math.h>
32#include <stdio.h>
33
34#include "internal.h"
35#include "collector.h"
36#include "operations.h"
37#include "error_object.h"
38#include "nodes.h"
39#include "property_map.h"
40
41namespace KJS {
42
43extern const UString lengthPropertyName("length");
44extern const UString prototypePropertyName("prototype");
45extern const UString toStringPropertyName("toString");
46extern const UString valueOfPropertyName("valueOf");
47
48// ------------------------------ Object ---------------------------------------
49
50Object Object::dynamicCast(const Value &v)
51{
52 if (v.isNull() || v.type() != ObjectType)
53 return Object(0);
54
55 return Object(static_cast<ObjectImp*>(v.imp()));
56}
57
58// ------------------------------ ObjectImp ------------------------------------
59
60ObjectImp::ObjectImp(const Object &proto)
61 : _prop(0), _proto(static_cast<ObjectImp*>(proto.imp())), _internalValue(0L), _scope(0)
62{
63 //fprintf(stderr,"ObjectImp::ObjectImp %p\n",(void*)this);
64 _scope = ListImp::empty();
65 _prop = new PropertyMap();
66}
67
68ObjectImp::ObjectImp()
69{
70 //fprintf(stderr,"ObjectImp::ObjectImp %p\n",(void*)this);
71 _prop = 0;
72 _proto = NullImp::staticNull;
73 _internalValue = 0L;
74 _scope = ListImp::empty();
75 _prop = new PropertyMap();
76}
77
78ObjectImp::~ObjectImp()
79{
80 //fprintf(stderr,"ObjectImp::~ObjectImp %p\n",(void*)this);
81 if (_proto)
82 _proto->setGcAllowed();
83 if (_internalValue)
84 _internalValue->setGcAllowed();
85 if (_scope)
86 _scope->setGcAllowed();
87 delete _prop;
88}
89
90void ObjectImp::mark()
91{
92 //fprintf(stderr,"ObjectImp::mark() %p\n",(void*)this);
93 ValueImp::mark();
94
95 if (_proto && !_proto->marked())
96 _proto->mark();
97
98 PropertyMapNode *node = _prop->first();
99 while (node) {
100 if (!node->value->marked())
101 node->value->mark();
102 node = node->next();
103 }
104
105 if (_internalValue && !_internalValue->marked())
106 _internalValue->mark();
107 if (_scope && !_scope->marked())
108 _scope->mark();
109}
110
111const ClassInfo *ObjectImp::classInfo() const
112{
113 return 0;
114}
115
116bool ObjectImp::inherits(const ClassInfo *info) const
117{
118 if (!info)
119 return false;
120
121 const ClassInfo *ci = classInfo();
122 if (!ci)
123 return false;
124
125 while (ci && ci != info)
126 ci = ci->parentClass;
127
128 return (ci == info);
129}
130
131Type ObjectImp::type() const
132{
133 return ObjectType;
134}
135
136Value ObjectImp::prototype() const
137{
138 return Value(_proto);
139}
140
141void ObjectImp::setPrototype(const Value &proto)
142{
143 _proto = proto.imp();
144}
145
146UString ObjectImp::className() const
147{
148 const ClassInfo *ci = classInfo();
149 if ( ci )
150 return ci->className;
151 return "Object";
152}
153
154Value ObjectImp::get(ExecState *exec, const UString &propertyName) const
155{
156 if (propertyName == "__proto__") {
157 Object proto = Object::dynamicCast(prototype());
158 // non-standard netscape extension
159 if (proto.isNull())
160 return Null();
161 else
162 return proto;
163 }
164
165 ValueImp *imp = getDirect(propertyName);
166 if ( imp )
167 return Value(imp);
168
169 Object proto = Object::dynamicCast(prototype());
170 if (proto.isNull())
171 return Undefined();
172
173 return proto.get(exec,propertyName);
174}
175
176Value ObjectImp::get(ExecState *exec, unsigned propertyName) const
177{
178 return get(exec, UString::from(propertyName));
179}
180
181// This get method only looks at the property map.
182// A bit like hasProperty(recursive=false), this doesn't go to the prototype.
183// This is used e.g. by lookupOrCreateFunction (to cache a function, we don't want
184// to look up in the prototype, it might already exist there)
185ValueImp* ObjectImp::getDirect(const UString& propertyName) const
186{
187 return _prop->get(propertyName);
188}
189
190// ECMA 8.6.2.2
191void ObjectImp::put(ExecState *exec, const UString &propertyName,
192 const Value &value, int attr)
193{
194 assert(!value.isNull());
195 assert(value.type() != ReferenceType);
196 assert(value.type() != CompletionType);
197 assert(value.type() != ListType);
198
199 /* TODO: check for write permissions directly w/o this call */
200 /* Doesn't look very easy with the PropertyMap API - David */
201 // putValue() is used for JS assignemnts. It passes no attribute.
202 // Assume that a C++ implementation knows what it is doing
203 // and let it override the canPut() check.
204 if ((attr == None || attr == DontDelete) && !canPut(exec,propertyName)) {
205#ifdef KJS_VERBOSE
206 fprintf( stderr, "WARNING: canPut %s said NO\n", propertyName.ascii() );
207#endif
208 return;
209 }
210
211 if (propertyName == "__proto__") {
212 // non-standard netscape extension
213 setPrototype(value);
214 return;
215 }
216
217 _prop->put(propertyName,value.imp(),attr);
218}
219
220void ObjectImp::put(ExecState *exec, unsigned propertyName,
221 const Value &value, int attr)
222{
223 put(exec, UString::from(propertyName), value, attr);
224}
225
226// ECMA 8.6.2.3
227bool ObjectImp::canPut(ExecState *, const UString &propertyName) const
228{
229 PropertyMapNode *node = _prop->getNode(propertyName);
230 if (node)
231 return!(node->attr & ReadOnly);
232
233 // Look in the static hashtable of properties
234 const HashEntry* e = findPropertyHashEntry(propertyName);
235 if (e)
236 return !(e->attr & ReadOnly);
237
238 // Don't look in the prototype here. We can always put an override
239 // in the object, even if the prototype has a ReadOnly property.
240 return true;
241}
242
243// ECMA 8.6.2.4
244bool ObjectImp::hasProperty(ExecState *exec, const UString &propertyName) const
245{
246 if (propertyName == "__proto__")
247 return true;
248 if (_prop->get(propertyName))
249 return true;
250
251 // Look in the static hashtable of properties
252 if (findPropertyHashEntry(propertyName))
253 return true;
254
255 // Look in the prototype
256 Object proto = Object::dynamicCast(prototype());
257 return !proto.isNull() && proto.hasProperty(exec,propertyName);
258}
259
260bool ObjectImp::hasProperty(ExecState *exec, unsigned propertyName) const
261{
262 return hasProperty(exec, UString::from(propertyName));
263}
264
265// ECMA 8.6.2.5
266bool ObjectImp::deleteProperty(ExecState */*exec*/, const UString &propertyName)
267{
268 PropertyMapNode *node = _prop->getNode(propertyName);
269 if (node) {
270 if ((node->attr & DontDelete))
271 return false;
272 _prop->remove(propertyName);
273 return true;
274 }
275
276 // Look in the static hashtable of properties
277 const HashEntry* entry = findPropertyHashEntry(propertyName);
278 if (entry && entry->attr & DontDelete)
279 return false; // this builtin property can't be deleted
280 return true;
281}
282
283bool ObjectImp::deleteProperty(ExecState *exec, unsigned propertyName)
284{
285 return deleteProperty(exec, UString::from(propertyName));
286}
287
288void ObjectImp::deleteAllProperties( ExecState * )
289{
290 _prop->clear();
291}
292
293// ECMA 8.6.2.6
294Value ObjectImp::defaultValue(ExecState *exec, Type hint) const
295{
296 if (hint != StringType && hint != NumberType) {
297 /* Prefer String for Date objects */
298 if (_proto == exec->interpreter()->builtinDatePrototype().imp())
299 hint = StringType;
300 else
301 hint = NumberType;
302 }
303
304 Value v;
305 if (hint == StringType)
306 v = get(exec,toStringPropertyName);
307 else
308 v = get(exec,valueOfPropertyName);
309
310 if (v.type() == ObjectType) {
311 Object o = Object(static_cast<ObjectImp*>(v.imp()));
312 if (o.implementsCall()) { // spec says "not primitive type" but ...
313 Object thisObj = Object(const_cast<ObjectImp*>(this));
314 Value def = o.call(exec,thisObj,List::empty());
315 Type defType = def.type();
316 if (defType == UnspecifiedType || defType == UndefinedType ||
317 defType == NullType || defType == BooleanType ||
318 defType == StringType || defType == NumberType) {
319 return def;
320 }
321 }
322 }
323
324 if (hint == StringType)
325 v = get(exec,valueOfPropertyName);
326 else
327 v = get(exec,toStringPropertyName);
328
329 if (v.type() == ObjectType) {
330 Object o = Object(static_cast<ObjectImp*>(v.imp()));
331 if (o.implementsCall()) { // spec says "not primitive type" but ...
332 Object thisObj = Object(const_cast<ObjectImp*>(this));
333 Value def = o.call(exec,thisObj,List::empty());
334 Type defType = def.type();
335 if (defType == UnspecifiedType || defType == UndefinedType ||
336 defType == NullType || defType == BooleanType ||
337 defType == StringType || defType == NumberType) {
338 return def;
339 }
340 }
341 }
342
343 Object err = Error::create(exec, TypeError, I18N_NOOP("No default value"));
344 exec->setException(err);
345 return err;
346}
347
348const HashEntry* ObjectImp::findPropertyHashEntry( const UString& propertyName ) const
349{
350 const ClassInfo *info = classInfo();
351 while (info) {
352 if (info->propHashTable) {
353 const HashEntry *e = Lookup::findEntry(info->propHashTable, propertyName);
354 if (e)
355 return e;
356 }
357 info = info->parentClass;
358 }
359 return 0L;
360}
361
362bool ObjectImp::implementsConstruct() const
363{
364 return false;
365}
366
367Object ObjectImp::construct(ExecState */*exec*/, const List &/*args*/)
368{
369 assert(false);
370 return Object(0);
371}
372
373bool ObjectImp::implementsCall() const
374{
375 return false;
376}
377
378Value ObjectImp::call(ExecState */*exec*/, Object &/*thisObj*/, const List &/*args*/)
379{
380 assert(false);
381 return Object(0);
382}
383
384bool ObjectImp::implementsHasInstance() const
385{
386 return false;
387}
388
389Boolean ObjectImp::hasInstance(ExecState */*exec*/, const Value &/*value*/)
390{
391 assert(false);
392 return Boolean(false);
393}
394
395const List ObjectImp::scope() const
396{
397 return _scope;
398}
399
400void ObjectImp::setScope(const List &s)
401{
402 if (_scope) _scope->setGcAllowed();
403 _scope = static_cast<ListImp*>(s.imp());
404}
405
406List ObjectImp::propList(ExecState *exec, bool recursive)
407{
408 List list;
409 if (_proto && _proto->type() == ObjectType && recursive)
410 list = static_cast<ObjectImp*>(_proto)->propList(exec,recursive);
411
412
413 PropertyMapNode *node = _prop->first();
414 while (node) {
415 if (!(node->attr & DontEnum))
416 list.append(Reference(Object(this), node->name));
417 node = node->next();
418 }
419
420 // Add properties from the static hashtable of properties
421 const ClassInfo *info = classInfo();
422 while (info) {
423 if (info->propHashTable) {
424 int size = info->propHashTable->size;
425 const HashEntry *e = info->propHashTable->entries;
426 for (int i = 0; i < size; ++i, ++e) {
427 if ( e->s && !(e->attr & DontEnum) )
428 list.append(Reference(Object(this), e->s)); /// ######### check for duplicates with the propertymap
429 }
430 }
431 info = info->parentClass;
432 }
433
434 return list;
435}
436
437Value ObjectImp::internalValue() const
438{
439 return Value(_internalValue);
440}
441
442void ObjectImp::setInternalValue(const Value &v)
443{
444 _internalValue = v.imp();
445}
446
447Value ObjectImp::toPrimitive(ExecState *exec, Type preferredType) const
448{
449 return defaultValue(exec,preferredType);
450}
451
452bool ObjectImp::toBoolean(ExecState */*exec*/) const
453{
454 return true;
455}
456
457double ObjectImp::toNumber(ExecState *exec) const
458{
459 Value prim = toPrimitive(exec,NumberType);
460 if (exec->hadException()) // should be picked up soon in nodes.cpp
461 return 0.0;
462 return prim.toNumber(exec);
463}
464
465UString ObjectImp::toString(ExecState *exec) const
466{
467 Value prim = toPrimitive(exec,StringType);
468 if (exec->hadException()) // should be picked up soon in nodes.cpp
469 return "";
470 return prim.toString(exec);
471}
472
473Object ObjectImp::toObject(ExecState */*exec*/) const
474{
475 return Object(const_cast<ObjectImp*>(this));
476}
477
478
479// ------------------------------ Error ----------------------------------------
480
481const char * const errorNamesArr[] = {
482 I18N_NOOP("Error"), // GeneralError
483 I18N_NOOP("Evaluation error"), // EvalError
484 I18N_NOOP("Range error"), // RangeError
485 I18N_NOOP("Reference error"), // ReferenceError
486 I18N_NOOP("Syntax error"), // SyntaxError
487 I18N_NOOP("Type error"), // TypeError
488 I18N_NOOP("URI error"), // URIError
489};
490
491const char * const * const Error::errorNames = errorNamesArr;
492
493Object Error::create(ExecState *exec, ErrorType errtype, const char *message,
494 int lineno, int sourceId)
495{
496 Object cons;
497
498 switch (errtype) {
499 case EvalError:
500 cons = exec->interpreter()->builtinEvalError();
501 break;
502 case RangeError:
503 cons = exec->interpreter()->builtinRangeError();
504 break;
505 case ReferenceError:
506 cons = exec->interpreter()->builtinReferenceError();
507 break;
508 case SyntaxError:
509 cons = exec->interpreter()->builtinSyntaxError();
510 break;
511 case TypeError:
512 cons = exec->interpreter()->builtinTypeError();
513 break;
514 case URIError:
515 cons = exec->interpreter()->builtinURIError();
516 break;
517 default:
518 cons = exec->interpreter()->builtinError();
519 break;
520 }
521
522 if (!message)
523 message = errorNames[errtype];
524 List args;
525 args.append(String(message));
526 Object err = Object::dynamicCast(cons.construct(exec,args));
527
528 if (lineno != -1)
529 err.put(exec, "line", Number(lineno));
530 if (sourceId != -1)
531 err.put(exec, "sourceId", Number(sourceId));
532
533 return err;
534
535/*
536#ifndef NDEBUG
537 const char *msg = err.get("message").toString().value().ascii();
538 if (l >= 0)
539 fprintf(stderr, "KJS: %s at line %d. %s\n", estr, l, msg);
540 else
541 fprintf(stderr, "KJS: %s. %s\n", estr, msg);
542#endif
543
544 return err;
545*/
546}
547
548} // namespace KJS
Note: See TracBrowser for help on using the repository browser.