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

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

JavaScriptCore:

  • reduced the creation of Value objects and hoisted the property map into Object for another gain of about 6%
  • JavaScriptCore.pbproj/project.pbxproj: Made property_map.h public.
  • kjs/array_object.cpp: (compareWithCompareFunctionForQSort): Don't wrap the ValueImp * in a Value just to add it to a list. (ArrayProtoFuncImp::call): Pass the globalObject directly so we don't have to ref/deref.
  • kjs/function.cpp: (FunctionImp::call): Use a reference for the global object to avoid ref/deref. (GlobalFuncImp::call): Ditto.
  • kjs/internal.cpp: (BooleanImp::toObject): Put the object directly into the list, don't create a Value. (StringImp::toObject): Ditto. (NumberImp::toObject): Ditto. (InterpreterImp::evaluate): Use a reference for the global object.
  • kjs/internal.h: Return a reference for the global object.
  • kjs/interpreter.cpp: (Interpreter::globalObject): Ditto.
  • kjs/interpreter.h: Ditto.
  • kjs/object.cpp: Use _prop directly in the object, not a separate pointer.
  • kjs/object.h: Ditto.
  • kjs/types.cpp: Added List methods that work directly with ValueImp. (List::append): Added a ValueImp version. (List::prepend): Ditto. (List::appendList): Work directly with the ValueImp's. (List::prependList): Ditto. (List::copy): Use appendList. (List::empty): Use a shared global List.
  • kjs/types.h: Update for above changes.

WebCore:

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