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

Last change on this file since 7787 was 7787, checked in by rjw, 21 years ago

Fixed build error.

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