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

Last change on this file since 4191 was 4191, checked in by darin, 22 years ago

Reviewed by Maciej.

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