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

Last change on this file since 13597 was 13465, checked in by darin, 19 years ago

JavaScriptCore:

Reviewed by Maciej.

  • kjs/object.h: Take function name, as well as source URL and line number, when using the special overloaded construct for making functions.
  • kjs/object.cpp: (KJS::JSObject::construct): Ditto.
  • kjs/function_object.h: Ditto.
  • kjs/function_object.cpp: (FunctionObjectImp::construct): Pass a name when constructing the function rather than null. Use "anonymous" when making a function using the default function constructor.
  • kjs/nodes2string.cpp: (FuncDeclNode::streamTo): Put a line break just before a function declaration.
  • unrelated fix
  • kxmlcore/HashMapPtrSpec.h: Add missing needed friend declaration.

LayoutTests:

  • fast/js/resources/function-names.js: Added.
  • fast/js/function-names.html: Generated.
  • fast/js/function-names-expected.txt: Generated.

WebCore:

Reviewed by Maciej.

Test: fast/js/function-names.html

  • dom/Document.h: Add function name parameter to createHTMLEventListener.
  • dom/Document.cpp: (WebCore::Document::createHTMLEventListener): Pass function name when calling createHTMLEventHandler. (WebCore::Document::setHTMLWindowEventListener): Pass attribute name as function name when calling createHTMLEventListener.
  • html/HTMLElement.cpp: (WebCore::HTMLElement::setHTMLEventListener): Pass attribute name as function name when calling createHTMLEventListener.
  • khtml/ecma/kjs_events.h: Add a function name parameter to JSLazyEventListener.
  • khtml/ecma/kjs_events.cpp: (KJS::JSLazyEventListener::JSLazyEventListener): Take and store a function name. (KJS::JSLazyEventListener::parseCode): Pass function name when constructing the function.
  • khtml/ecma/kjs_proxy.h: Add a function name parameter to createHTMLEventHandler and createSVGEventHandler.
  • khtml/ecma/kjs_proxy.cpp: (WebCore::KJSProxy::createHTMLEventHandler): Pass function name when creating a JSLazyEventListener. (WebCore::KJSProxy::createSVGEventHandler): Ditto.
  • ksvg2/events/JSSVGLazyEventListener.h: Add a function name parameter to JSSVGLazyEventListener.
  • ksvg2/events/JSSVGLazyEventListener.cpp: (WebCore::JSSVGLazyEventListener::JSSVGLazyEventListener): Pass the function name on to the base class constructor.
  • ksvg2/misc/SVGDocumentExtensions.h: Add function name parameter to createSVGEventListener.
  • ksvg2/misc/SVGDocumentExtensions.cpp: (WebCore::SVGDocumentExtensions::createSVGEventListener): Pass function name when calling createSVGEventHandler.
  • ksvg2/svg/SVGElement.cpp: (WebCore::SVGElement::addSVGEventListener):
  • ksvg2/svg/SVGSVGElement.cpp: (WebCore::SVGSVGElement::addSVGWindowEventListner): Pass attribute name as function name when calling createSVGEventListener.
  • WebCore.xcodeproj/project.pbxproj: Moved generation script to the top.
  • Property svn:eol-style set to native
File size: 17.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 * Copyright (C) 2003, 2004, 2005, 2006 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., 51 Franklin Street, Fifth Floor,
21 * Boston, MA 02110-1301, USA.
22 *
23 */
24
25#include "config.h"
26#include "value.h"
27#include "object.h"
28#include "types.h"
29#include "interpreter.h"
30#include "lookup.h"
31#include "reference_list.h"
32
33#include <assert.h>
34#include <math.h>
35#include <stdio.h>
36
37#include "internal.h"
38#include "collector.h"
39#include "operations.h"
40#include "error_object.h"
41#include "nodes.h"
42
43#define JAVASCRIPT_CALL_TRACING 0
44
45#if JAVASCRIPT_CALL_TRACING
46static bool _traceJavaScript = false;
47
48extern "C" {
49 void setTraceJavaScript(bool f)
50 {
51 _traceJavaScript = f;
52 }
53
54 static bool traceJavaScript()
55 {
56 return _traceJavaScript;
57 }
58}
59#endif
60
61namespace KJS {
62
63// ------------------------------ Object ---------------------------------------
64
65JSValue *JSObject::call(ExecState *exec, JSObject *thisObj, const List &args)
66{
67 assert(implementsCall());
68
69#if KJS_MAX_STACK > 0
70 static int depth = 0; // sum of all concurrent interpreters
71
72#if JAVASCRIPT_CALL_TRACING
73 static bool tracing = false;
74 if (traceJavaScript() && !tracing) {
75 tracing = true;
76 for (int i = 0; i < depth; i++)
77 putchar (' ');
78 printf ("*** calling: %s\n", toString(exec).ascii());
79 for (int j = 0; j < args.size(); j++) {
80 for (int i = 0; i < depth; i++)
81 putchar (' ');
82 printf ("*** arg[%d] = %s\n", j, args[j]->toString(exec).ascii());
83 }
84 tracing = false;
85 }
86#endif
87
88 if (++depth > KJS_MAX_STACK) {
89 --depth;
90 return throwError(exec, RangeError, "Maximum call stack size exceeded.");
91 }
92#endif
93
94 JSValue *ret = callAsFunction(exec,thisObj,args);
95
96#if KJS_MAX_STACK > 0
97 --depth;
98#endif
99
100#if JAVASCRIPT_CALL_TRACING
101 if (traceJavaScript() && !tracing) {
102 tracing = true;
103 for (int i = 0; i < depth; i++)
104 putchar (' ');
105 printf ("*** returning: %s\n", ret->toString(exec).ascii());
106 tracing = false;
107 }
108#endif
109
110 return ret;
111}
112
113// ------------------------------ JSObject ------------------------------------
114
115void JSObject::mark()
116{
117 JSCell::mark();
118
119 JSValue *proto = _proto;
120 if (!proto->marked())
121 proto->mark();
122
123 _prop.mark();
124
125 if (_internalValue && !_internalValue->marked())
126 _internalValue->mark();
127
128 _scope.mark();
129}
130
131JSType JSObject::type() const
132{
133 return ObjectType;
134}
135
136const ClassInfo *JSObject::classInfo() const
137{
138 return 0;
139}
140
141UString JSObject::className() const
142{
143 const ClassInfo *ci = classInfo();
144 if ( ci )
145 return ci->className;
146 return "Object";
147}
148
149JSValue *JSObject::get(ExecState *exec, const Identifier &propertyName) const
150{
151 PropertySlot slot;
152
153 if (const_cast<JSObject *>(this)->getPropertySlot(exec, propertyName, slot))
154 return slot.getValue(exec, const_cast<JSObject *>(this), propertyName);
155
156 return jsUndefined();
157}
158
159JSValue *JSObject::get(ExecState *exec, unsigned propertyName) const
160{
161 PropertySlot slot;
162 if (const_cast<JSObject *>(this)->getPropertySlot(exec, propertyName, slot))
163 return slot.getValue(exec, const_cast<JSObject *>(this), propertyName);
164
165 return jsUndefined();
166}
167
168bool JSObject::getPropertySlot(ExecState *exec, unsigned propertyName, PropertySlot& slot)
169{
170 JSObject *imp = this;
171
172 while (true) {
173 if (imp->getOwnPropertySlot(exec, propertyName, slot))
174 return true;
175
176 JSValue *proto = imp->_proto;
177 if (!proto->isObject())
178 break;
179
180 imp = static_cast<JSObject *>(proto);
181 }
182
183 return false;
184}
185
186bool JSObject::getOwnPropertySlot(ExecState *exec, unsigned propertyName, PropertySlot& slot)
187{
188 return getOwnPropertySlot(exec, Identifier::from(propertyName), slot);
189}
190
191static void throwSetterError(ExecState *exec)
192{
193 throwError(exec, TypeError, "setting a property that has only a getter");
194}
195
196// ECMA 8.6.2.2
197void JSObject::put(ExecState *exec, const Identifier &propertyName, JSValue *value, int attr)
198{
199 assert(value);
200
201 // non-standard netscape extension
202 if (propertyName == exec->dynamicInterpreter()->specialPrototypeIdentifier()) {
203 setPrototype(value);
204 return;
205 }
206
207 /* TODO: check for write permissions directly w/o this call */
208 /* Doesn't look very easy with the PropertyMap API - David */
209 // putValue() is used for JS assignemnts. It passes no attribute.
210 // Assume that a C++ implementation knows what it is doing
211 // and let it override the canPut() check.
212 if ((attr == None || attr == DontDelete) && !canPut(exec,propertyName)) {
213#ifdef KJS_VERBOSE
214 fprintf( stderr, "WARNING: canPut %s said NO\n", propertyName.ascii() );
215#endif
216 return;
217 }
218
219 // Check if there are any setters or getters in the prototype chain
220 JSObject *obj = this;
221 bool hasGettersOrSetters = false;
222 while (true) {
223 if (obj->_prop.hasGetterSetterProperties()) {
224 hasGettersOrSetters = true;
225 break;
226 }
227
228 if (!obj->_proto->isObject())
229 break;
230
231 obj = static_cast<JSObject *>(obj->_proto);
232 }
233
234 if (hasGettersOrSetters) {
235 obj = this;
236 while (true) {
237 int attributes;
238 if (JSValue *gs = obj->_prop.get(propertyName, attributes)) {
239 if (attributes & GetterSetter) {
240 JSObject *setterFunc = static_cast<GetterSetterImp *>(gs)->getSetter();
241
242 if (!setterFunc) {
243 throwSetterError(exec);
244 return;
245 }
246
247 List args;
248 args.append(value);
249
250 setterFunc->call(exec, this, args);
251 return;
252 } else {
253 // If there's an existing property on the object or one of its
254 // prototype it should be replaced, so we just break here.
255 break;
256 }
257 }
258
259 if (!obj->_proto->isObject())
260 break;
261
262 obj = static_cast<JSObject *>(obj->_proto);
263 }
264 }
265
266 _prop.put(propertyName,value,attr);
267}
268
269void JSObject::put(ExecState *exec, unsigned propertyName,
270 JSValue *value, int attr)
271{
272 put(exec, Identifier::from(propertyName), value, attr);
273}
274
275// ECMA 8.6.2.3
276bool JSObject::canPut(ExecState *, const Identifier &propertyName) const
277{
278 int attributes;
279
280 // Don't look in the prototype here. We can always put an override
281 // in the object, even if the prototype has a ReadOnly property.
282
283 if (!getPropertyAttributes(propertyName, attributes))
284 return true;
285 else
286 return !(attributes & ReadOnly);
287}
288
289// ECMA 8.6.2.4
290bool JSObject::hasProperty(ExecState *exec, const Identifier &propertyName) const
291{
292 PropertySlot slot;
293 return const_cast<JSObject *>(this)->getPropertySlot(exec, propertyName, slot);
294}
295
296bool JSObject::hasProperty(ExecState *exec, unsigned propertyName) const
297{
298 PropertySlot slot;
299 return const_cast<JSObject *>(this)->getPropertySlot(exec, propertyName, slot);
300}
301
302// ECMA 8.6.2.5
303bool JSObject::deleteProperty(ExecState */*exec*/, const Identifier &propertyName)
304{
305 int attributes;
306 JSValue *v = _prop.get(propertyName, attributes);
307 if (v) {
308 if ((attributes & DontDelete))
309 return false;
310 _prop.remove(propertyName);
311 if (attributes & GetterSetter)
312 _prop.setHasGetterSetterProperties(_prop.containsGettersOrSetters());
313 return true;
314 }
315
316 // Look in the static hashtable of properties
317 const HashEntry* entry = findPropertyHashEntry(propertyName);
318 if (entry && entry->attr & DontDelete)
319 return false; // this builtin property can't be deleted
320 return true;
321}
322
323bool JSObject::deleteProperty(ExecState *exec, unsigned propertyName)
324{
325 return deleteProperty(exec, Identifier::from(propertyName));
326}
327
328static ALWAYS_INLINE JSValue *tryGetAndCallProperty(ExecState *exec, const JSObject *object, const Identifier &propertyName) {
329 JSValue *v = object->get(exec, propertyName);
330 if (v->isObject()) {
331 JSObject *o = static_cast<JSObject*>(v);
332 if (o->implementsCall()) { // spec says "not primitive type" but ...
333 JSObject *thisObj = const_cast<JSObject*>(object);
334 JSValue *def = o->call(exec, thisObj, List::empty());
335 JSType defType = def->type();
336 ASSERT(defType != GetterSetterType);
337 if (defType != ObjectType)
338 return def;
339 }
340 }
341 return NULL;
342}
343
344// ECMA 8.6.2.6
345JSValue *JSObject::defaultValue(ExecState *exec, JSType hint) const
346{
347 Identifier firstPropertyName;
348 Identifier secondPropertyName;
349 /* Prefer String for Date objects */
350 if ((hint == StringType) || (hint != StringType) && (hint != NumberType) && (_proto == exec->lexicalInterpreter()->builtinDatePrototype())) {
351 firstPropertyName = toStringPropertyName;
352 secondPropertyName = valueOfPropertyName;
353 } else {
354 firstPropertyName = valueOfPropertyName;
355 secondPropertyName = toStringPropertyName;
356 }
357
358 JSValue *v;
359 if ((v = tryGetAndCallProperty(exec, this, firstPropertyName)))
360 return v;
361 if ((v = tryGetAndCallProperty(exec, this, secondPropertyName)))
362 return v;
363
364 if (exec->hadException())
365 return exec->exception();
366
367 return throwError(exec, TypeError, "No default value");
368}
369
370const HashEntry* JSObject::findPropertyHashEntry(const Identifier& propertyName) const
371{
372 for (const ClassInfo *info = classInfo(); info; info = info->parentClass) {
373 if (const HashTable *propHashTable = info->propHashTable) {
374 if (const HashEntry *e = Lookup::findEntry(propHashTable, propertyName))
375 return e;
376 }
377 }
378 return 0;
379}
380
381void JSObject::defineGetter(ExecState*, const Identifier& propertyName, JSObject* getterFunc)
382{
383 JSValue *o = getDirect(propertyName);
384 GetterSetterImp *gs;
385
386 if (o && o->type() == GetterSetterType) {
387 gs = static_cast<GetterSetterImp *>(o);
388 } else {
389 gs = new GetterSetterImp;
390 putDirect(propertyName, gs, GetterSetter);
391 }
392
393 _prop.setHasGetterSetterProperties(true);
394 gs->setGetter(getterFunc);
395}
396
397void JSObject::defineSetter(ExecState*, const Identifier& propertyName, JSObject* setterFunc)
398{
399 JSValue *o = getDirect(propertyName);
400 GetterSetterImp *gs;
401
402 if (o && o->type() == GetterSetterType) {
403 gs = static_cast<GetterSetterImp *>(o);
404 } else {
405 gs = new GetterSetterImp;
406 putDirect(propertyName, gs, GetterSetter);
407 }
408
409 _prop.setHasGetterSetterProperties(true);
410 gs->setSetter(setterFunc);
411}
412
413bool JSObject::implementsConstruct() const
414{
415 return false;
416}
417
418JSObject* JSObject::construct(ExecState*, const List& /*args*/)
419{
420 assert(false);
421 return NULL;
422}
423
424JSObject* JSObject::construct(ExecState* exec, const List& args, const Identifier& /*functionName*/, const UString& /*sourceURL*/, int /*lineNumber*/)
425{
426 return construct(exec, args);
427}
428
429bool JSObject::implementsCall() const
430{
431 return false;
432}
433
434JSValue *JSObject::callAsFunction(ExecState */*exec*/, JSObject */*thisObj*/, const List &/*args*/)
435{
436 assert(false);
437 return NULL;
438}
439
440bool JSObject::implementsHasInstance() const
441{
442 return false;
443}
444
445bool JSObject::hasInstance(ExecState *, JSValue *)
446{
447 assert(false);
448 return false;
449}
450
451bool JSObject::propertyIsEnumerable(ExecState*, const Identifier& propertyName) const
452{
453 int attributes;
454
455 if (!getPropertyAttributes(propertyName, attributes))
456 return false;
457 else
458 return !(attributes & DontEnum);
459}
460
461bool JSObject::getPropertyAttributes(const Identifier& propertyName, int& attributes) const
462{
463 if (_prop.get(propertyName, attributes))
464 return true;
465
466 // Look in the static hashtable of properties
467 const HashEntry* e = findPropertyHashEntry(propertyName);
468 if (e) {
469 attributes = e->attr;
470 return true;
471 }
472
473 return false;
474}
475
476ReferenceList JSObject::propList(ExecState *exec, bool recursive)
477{
478 ReferenceList list;
479 if (_proto->isObject() && recursive)
480 list = static_cast<JSObject*>(_proto)->propList(exec,recursive);
481
482 _prop.addEnumerablesToReferenceList(list, this);
483
484 // Add properties from the static hashtable of properties
485 const ClassInfo *info = classInfo();
486 while (info) {
487 if (info->propHashTable) {
488 int size = info->propHashTable->size;
489 const HashEntry *e = info->propHashTable->entries;
490 for (int i = 0; i < size; ++i, ++e) {
491 if ( e->s && !(e->attr & DontEnum) )
492 list.append(Reference(this, e->s)); /// ######### check for duplicates with the propertymap
493 }
494 }
495 info = info->parentClass;
496 }
497
498 return list;
499}
500
501bool JSObject::toBoolean(ExecState */*exec*/) const
502{
503 return true;
504}
505
506double JSObject::toNumber(ExecState *exec) const
507{
508 JSValue *prim = toPrimitive(exec,NumberType);
509 if (exec->hadException()) // should be picked up soon in nodes.cpp
510 return 0.0;
511 return prim->toNumber(exec);
512}
513
514UString JSObject::toString(ExecState *exec) const
515{
516 JSValue *prim = toPrimitive(exec,StringType);
517 if (exec->hadException()) // should be picked up soon in nodes.cpp
518 return "";
519 return prim->toString(exec);
520}
521
522JSObject *JSObject::toObject(ExecState */*exec*/) const
523{
524 return const_cast<JSObject*>(this);
525}
526
527void JSObject::putDirect(const Identifier &propertyName, JSValue *value, int attr)
528{
529 _prop.put(propertyName, value, attr);
530}
531
532void JSObject::putDirect(const Identifier &propertyName, int value, int attr)
533{
534 _prop.put(propertyName, jsNumber(value), attr);
535}
536
537void JSObject::putDirectFunction(InternalFunctionImp* func, int attr)
538{
539 putDirect(func->functionName(), func, attr);
540}
541
542void JSObject::fillGetterPropertySlot(PropertySlot& slot, JSValue **location)
543{
544 GetterSetterImp *gs = static_cast<GetterSetterImp *>(*location);
545 JSObject *getterFunc = gs->getGetter();
546 if (getterFunc)
547 slot.setGetterSlot(this, getterFunc);
548 else
549 slot.setUndefined(this);
550}
551
552// ------------------------------ Error ----------------------------------------
553
554const char * const errorNamesArr[] = {
555 I18N_NOOP("Error"), // GeneralError
556 I18N_NOOP("Evaluation error"), // EvalError
557 I18N_NOOP("Range error"), // RangeError
558 I18N_NOOP("Reference error"), // ReferenceError
559 I18N_NOOP("Syntax error"), // SyntaxError
560 I18N_NOOP("Type error"), // TypeError
561 I18N_NOOP("URI error"), // URIError
562};
563
564const char * const * const Error::errorNames = errorNamesArr;
565
566JSObject *Error::create(ExecState *exec, ErrorType errtype, const UString &message,
567 int lineno, int sourceId, const UString *sourceURL)
568{
569 JSObject *cons;
570 switch (errtype) {
571 case EvalError:
572 cons = exec->lexicalInterpreter()->builtinEvalError();
573 break;
574 case RangeError:
575 cons = exec->lexicalInterpreter()->builtinRangeError();
576 break;
577 case ReferenceError:
578 cons = exec->lexicalInterpreter()->builtinReferenceError();
579 break;
580 case SyntaxError:
581 cons = exec->lexicalInterpreter()->builtinSyntaxError();
582 break;
583 case TypeError:
584 cons = exec->lexicalInterpreter()->builtinTypeError();
585 break;
586 case URIError:
587 cons = exec->lexicalInterpreter()->builtinURIError();
588 break;
589 default:
590 cons = exec->lexicalInterpreter()->builtinError();
591 break;
592 }
593
594 List args;
595 if (message.isEmpty())
596 args.append(jsString(errorNames[errtype]));
597 else
598 args.append(jsString(message));
599 JSObject *err = static_cast<JSObject *>(cons->construct(exec,args));
600
601 if (lineno != -1)
602 err->put(exec, "line", jsNumber(lineno));
603 if (sourceId != -1)
604 err->put(exec, "sourceId", jsNumber(sourceId));
605
606 if(sourceURL)
607 err->put(exec,"sourceURL", jsString(*sourceURL));
608
609 return err;
610
611/*
612#ifndef NDEBUG
613 const char *msg = err->get(messagePropertyName)->toString().value().ascii();
614 if (l >= 0)
615 fprintf(stderr, "KJS: %s at line %d. %s\n", estr, l, msg);
616 else
617 fprintf(stderr, "KJS: %s. %s\n", estr, msg);
618#endif
619
620 return err;
621*/
622}
623
624JSObject *Error::create(ExecState *exec, ErrorType type, const char *message)
625{
626 return create(exec, type, message, -1, -1, NULL);
627}
628
629JSObject *throwError(ExecState *exec, ErrorType type)
630{
631 JSObject *error = Error::create(exec, type, UString(), -1, -1, NULL);
632 exec->setException(error);
633 return error;
634}
635
636JSObject *throwError(ExecState *exec, ErrorType type, const UString &message)
637{
638 JSObject *error = Error::create(exec, type, message, -1, -1, NULL);
639 exec->setException(error);
640 return error;
641}
642
643JSObject *throwError(ExecState *exec, ErrorType type, const char *message)
644{
645 JSObject *error = Error::create(exec, type, message, -1, -1, NULL);
646 exec->setException(error);
647 return error;
648}
649
650JSObject *throwError(ExecState *exec, ErrorType type, const UString &message, int line, int sourceId, const UString *sourceURL)
651{
652 JSObject *error = Error::create(exec, type, message, line, sourceId, sourceURL);
653 exec->setException(error);
654 return error;
655}
656
657} // namespace KJS
Note: See TracBrowser for help on using the repository browser.