source: webkit/trunk/JavaScriptCore/kjs/JSObject.cpp@ 34876

Last change on this file since 34876 was 34876, checked in by [email protected], 17 years ago

2008-06-29 Sam Weinig <[email protected]>

Rubber-stamped by Cameron Zwarich.

Splits ErrorConstructor, ErrorPrototype, NativeErrorConstructor and
NativeErrorPrototype out of error_object.h/cpp and renames it ErrorInstance.

  • GNUmakefile.am:
  • JavaScriptCore.pri:
  • JavaScriptCore.vcproj/JavaScriptCore/JavaScriptCore.vcproj:
  • JavaScriptCore.xcodeproj/project.pbxproj:
  • JavaScriptCoreSources.bkl:
  • kjs/AllInOneFile.cpp:
  • kjs/ArrayConstructor.cpp:
  • kjs/ArrayPrototype.cpp:
  • kjs/BooleanPrototype.cpp:
  • kjs/DatePrototype.cpp:
  • kjs/ErrorConstructor.cpp: Copied from kjs/error_object.cpp.
  • kjs/ErrorConstructor.h: Copied from kjs/error_object.h.
  • kjs/ErrorInstance.cpp: Copied from kjs/error_object.cpp.
  • kjs/ErrorInstance.h: Copied from kjs/error_object.h.
  • kjs/ErrorPrototype.cpp: Copied from kjs/error_object.cpp.
  • kjs/ErrorPrototype.h: Copied from kjs/error_object.h.
  • kjs/JSGlobalObject.cpp:
  • kjs/JSObject.cpp:
  • kjs/JSValue.cpp:
  • kjs/NativeErrorConstructor.cpp: Copied from kjs/error_object.cpp.
  • kjs/NativeErrorConstructor.h: Copied from kjs/error_object.h.
  • kjs/NativeErrorPrototype.cpp: Copied from kjs/error_object.cpp.
  • kjs/NativeErrorPrototype.h: Copied from kjs/error_object.h.
  • kjs/NumberPrototype.cpp:
  • kjs/RegExpConstructor.cpp:
  • kjs/RegExpObject.cpp:
  • kjs/RegExpPrototype.cpp:
  • kjs/StringPrototype.cpp:
  • kjs/error_object.cpp: Removed.
  • kjs/error_object.h: Removed.
  • kjs/internal.cpp:
  • Property svn:eol-style set to native
File size: 16.6 KB
Line 
1// -*- c-basic-offset: 2 -*-
2/*
3 * Copyright (C) 1999-2001 Harri Porten ([email protected])
4 * Copyright (C) 2001 Peter Kelly ([email protected])
5 * Copyright (C) 2003, 2004, 2005, 2006, 2008 Apple Inc. All rights reserved.
6 * Copyright (C) 2007 Eric Seidel ([email protected])
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 "JSObject.h"
27
28#include "DatePrototype.h"
29#include "ErrorConstructor.h"
30#include "JSGlobalObject.h"
31#include "ObjectPrototype.h"
32#include "PropertyNameArray.h"
33#include "lookup.h"
34#include "nodes.h"
35#include "operations.h"
36#include <math.h>
37#include <profiler/Profiler.h>
38#include <wtf/Assertions.h>
39
40#define JAVASCRIPT_MARK_TRACING 0
41
42namespace KJS {
43
44// ------------------------------ JSObject ------------------------------------
45
46void JSObject::mark()
47{
48 JSCell::mark();
49
50#if JAVASCRIPT_MARK_TRACING
51 static int markStackDepth = 0;
52 markStackDepth++;
53 for (int i = 0; i < markStackDepth; i++)
54 putchar('-');
55
56 printf("%s (%p)\n", className().UTF8String().c_str(), this);
57#endif
58
59 JSValue *proto = _proto;
60 if (!proto->marked())
61 proto->mark();
62
63 _prop.mark();
64
65#if JAVASCRIPT_MARK_TRACING
66 markStackDepth--;
67#endif
68}
69
70JSType JSObject::type() const
71{
72 return ObjectType;
73}
74
75UString JSObject::className() const
76{
77 const ClassInfo *ci = classInfo();
78 if ( ci )
79 return ci->className;
80 return "Object";
81}
82
83bool JSObject::getOwnPropertySlot(ExecState *exec, unsigned propertyName, PropertySlot& slot)
84{
85 return getOwnPropertySlot(exec, Identifier::from(exec, propertyName), slot);
86}
87
88static void throwSetterError(ExecState *exec)
89{
90 throwError(exec, TypeError, "setting a property that has only a getter");
91}
92
93// ECMA 8.6.2.2
94void JSObject::put(ExecState* exec, const Identifier& propertyName, JSValue* value)
95{
96 ASSERT(value);
97 ASSERT(!Heap::heap(value) || Heap::heap(value) == Heap::heap(this));
98
99 if (propertyName == exec->propertyNames().underscoreProto) {
100 JSObject* proto = value->getObject();
101
102 // Setting __proto__ to a non-object, non-null value is silently ignored to match Mozilla.
103 if (!proto && value != jsNull())
104 return;
105
106 while (proto) {
107 if (proto == this) {
108 throwError(exec, GeneralError, "cyclic __proto__ value");
109 return;
110 }
111 proto = proto->prototype() ? proto->prototype()->getObject() : 0;
112 }
113
114 setPrototype(value);
115 return;
116 }
117
118 // Check if there are any setters or getters in the prototype chain
119 JSValue* prototype;
120 for (JSObject* obj = this; !obj->_prop.hasGetterSetterProperties(); obj = static_cast<JSObject*>(prototype)) {
121 prototype = obj->_proto;
122 if (prototype == jsNull()) {
123 _prop.put(propertyName, value, 0, true);
124 return;
125 }
126 }
127
128 unsigned attributes;
129 if (_prop.get(propertyName, attributes) && attributes & ReadOnly)
130 return;
131
132 for (JSObject* obj = this; ; obj = static_cast<JSObject*>(prototype)) {
133 if (JSValue* gs = obj->_prop.get(propertyName, attributes)) {
134 if (attributes & IsGetterSetter) {
135 JSObject* setterFunc = static_cast<GetterSetter*>(gs)->setter();
136 if (!setterFunc) {
137 throwSetterError(exec);
138 return;
139 }
140
141 CallData callData;
142 CallType callType = setterFunc->getCallData(callData);
143 ArgList args;
144 args.append(value);
145 call(exec, setterFunc, callType, callData, this, args);
146 return;
147 }
148
149 // If there's an existing property on the object or one of its
150 // prototypes it should be replaced, so break here.
151 break;
152 }
153
154 prototype = obj->_proto;
155 if (prototype == jsNull())
156 break;
157 }
158
159 _prop.put(propertyName, value, 0, true);
160}
161
162void JSObject::put(ExecState* exec, unsigned propertyName, JSValue* value)
163{
164 put(exec, Identifier::from(exec, propertyName), value);
165}
166
167void JSObject::putWithAttributes(ExecState*, const Identifier& propertyName, JSValue* value, unsigned attributes)
168{
169 putDirect(propertyName, value, attributes);
170}
171
172void JSObject::putWithAttributes(ExecState* exec, unsigned propertyName, JSValue* value, unsigned attributes)
173{
174 putWithAttributes(exec, Identifier::from(exec, propertyName), value, attributes);
175}
176
177bool JSObject::hasProperty(ExecState *exec, const Identifier &propertyName) const
178{
179 PropertySlot slot;
180 return const_cast<JSObject *>(this)->getPropertySlot(exec, propertyName, slot);
181}
182
183bool JSObject::hasProperty(ExecState *exec, unsigned propertyName) const
184{
185 PropertySlot slot;
186 return const_cast<JSObject *>(this)->getPropertySlot(exec, propertyName, slot);
187}
188
189// ECMA 8.6.2.5
190bool JSObject::deleteProperty(ExecState* exec, const Identifier &propertyName)
191{
192 unsigned attributes;
193 JSValue *v = _prop.get(propertyName, attributes);
194 if (v) {
195 if ((attributes & DontDelete))
196 return false;
197 _prop.remove(propertyName);
198 if (attributes & IsGetterSetter)
199 _prop.setHasGetterSetterProperties(_prop.containsGettersOrSetters());
200 return true;
201 }
202
203 // Look in the static hashtable of properties
204 const HashEntry* entry = findPropertyHashEntry(exec, propertyName);
205 if (entry && entry->attributes & DontDelete)
206 return false; // this builtin property can't be deleted
207 // FIXME: Should the code here actually do some deletion?
208 return true;
209}
210
211bool JSObject::hasOwnProperty(ExecState* exec, const Identifier& propertyName) const
212{
213 PropertySlot slot;
214 return const_cast<JSObject*>(this)->getOwnPropertySlot(exec, propertyName, slot);
215}
216
217bool JSObject::deleteProperty(ExecState *exec, unsigned propertyName)
218{
219 return deleteProperty(exec, Identifier::from(exec, propertyName));
220}
221
222static ALWAYS_INLINE JSValue* callDefaultValueFunction(ExecState* exec, const JSObject* object, const Identifier& propertyName)
223{
224 JSValue* function = object->get(exec, propertyName);
225 CallData callData;
226 CallType callType = function->getCallData(callData);
227 if (callType == CallTypeNone)
228 return 0;
229 JSValue* result = call(exec, function, callType, callData, const_cast<JSObject*>(object), exec->emptyList());
230 ASSERT(result->type() != GetterSetterType);
231 if (exec->hadException())
232 return exec->exception();
233 if (result->isObject())
234 return 0;
235 return result;
236}
237
238bool JSObject::getPrimitiveNumber(ExecState* exec, double& number, JSValue*& result)
239{
240 result = defaultValue(exec, NumberType);
241 number = result->toNumber(exec);
242 return !result->isString();
243}
244
245// ECMA 8.6.2.6
246JSValue* JSObject::defaultValue(ExecState* exec, JSType hint) const
247{
248 // We need this check to guard against the case where this object is rhs of
249 // a binary expression where lhs threw an exception in its conversion to
250 // primitive.
251 if (exec->hadException())
252 return exec->exception();
253
254 // Must call toString first for Date objects.
255 if ((hint == StringType) || (hint != NumberType && _proto == exec->lexicalGlobalObject()->datePrototype())) {
256 if (JSValue* value = callDefaultValueFunction(exec, this, exec->propertyNames().toString))
257 return value;
258 if (JSValue* value = callDefaultValueFunction(exec, this, exec->propertyNames().valueOf))
259 return value;
260 } else {
261 if (JSValue* value = callDefaultValueFunction(exec, this, exec->propertyNames().valueOf))
262 return value;
263 if (JSValue* value = callDefaultValueFunction(exec, this, exec->propertyNames().toString))
264 return value;
265 }
266
267 ASSERT(!exec->hadException());
268
269 return throwError(exec, TypeError, "No default value");
270}
271
272const HashEntry* JSObject::findPropertyHashEntry(ExecState* exec, const Identifier& propertyName) const
273{
274 for (const ClassInfo* info = classInfo(); info; info = info->parentClass) {
275 if (const HashTable* propHashTable = info->propHashTable(exec)) {
276 if (const HashEntry* e = propHashTable->entry(exec, propertyName))
277 return e;
278 }
279 }
280 return 0;
281}
282
283void JSObject::defineGetter(ExecState* exec, const Identifier& propertyName, JSObject* getterFunc)
284{
285 JSValue *o = getDirect(propertyName);
286 GetterSetter *gs;
287
288 if (o && o->type() == GetterSetterType) {
289 gs = static_cast<GetterSetter *>(o);
290 } else {
291 gs = new (exec) GetterSetter;
292 putDirect(propertyName, gs, IsGetterSetter);
293 }
294
295 _prop.setHasGetterSetterProperties(true);
296 gs->setGetter(getterFunc);
297}
298
299void JSObject::defineSetter(ExecState* exec, const Identifier& propertyName, JSObject* setterFunc)
300{
301 JSValue *o = getDirect(propertyName);
302 GetterSetter *gs;
303
304 if (o && o->type() == GetterSetterType) {
305 gs = static_cast<GetterSetter *>(o);
306 } else {
307 gs = new (exec) GetterSetter;
308 putDirect(propertyName, gs, IsGetterSetter);
309 }
310
311 _prop.setHasGetterSetterProperties(true);
312 gs->setSetter(setterFunc);
313}
314
315JSValue* JSObject::lookupGetter(ExecState*, const Identifier& propertyName)
316{
317 JSObject* obj = this;
318 while (true) {
319 JSValue* v = obj->getDirect(propertyName);
320 if (v) {
321 if (v->type() != GetterSetterType)
322 return jsUndefined();
323 JSObject* funcObj = static_cast<GetterSetter*>(v)->getter();
324 if (!funcObj)
325 return jsUndefined();
326 return funcObj;
327 }
328
329 if (!obj->prototype() || !obj->prototype()->isObject())
330 return jsUndefined();
331 obj = static_cast<JSObject*>(obj->prototype());
332 }
333}
334
335JSValue* JSObject::lookupSetter(ExecState*, const Identifier& propertyName)
336{
337 JSObject* obj = this;
338 while (true) {
339 JSValue* v = obj->getDirect(propertyName);
340 if (v) {
341 if (v->type() != GetterSetterType)
342 return jsUndefined();
343 JSObject* funcObj = static_cast<GetterSetter*>(v)->setter();
344 if (!funcObj)
345 return jsUndefined();
346 return funcObj;
347 }
348
349 if (!obj->prototype() || !obj->prototype()->isObject())
350 return jsUndefined();
351 obj = static_cast<JSObject*>(obj->prototype());
352 }
353}
354
355bool JSObject::implementsHasInstance() const
356{
357 return false;
358}
359
360bool JSObject::hasInstance(ExecState* exec, JSValue* value)
361{
362 JSValue* proto = get(exec, exec->propertyNames().prototype);
363 if (!proto->isObject()) {
364 throwError(exec, TypeError, "instanceof called on an object with an invalid prototype property.");
365 return false;
366 }
367
368 if (!value->isObject())
369 return false;
370
371 JSObject* o = static_cast<JSObject*>(value);
372 while ((o = o->prototype()->getObject())) {
373 if (o == proto)
374 return true;
375 }
376 return false;
377}
378
379bool JSObject::propertyIsEnumerable(ExecState* exec, const Identifier& propertyName) const
380{
381 unsigned attributes;
382
383 if (!getPropertyAttributes(exec, propertyName, attributes))
384 return false;
385 else
386 return !(attributes & DontEnum);
387}
388
389bool JSObject::getPropertyAttributes(ExecState* exec, const Identifier& propertyName, unsigned& attributes) const
390{
391 if (_prop.get(propertyName, attributes))
392 return true;
393
394 // Look in the static hashtable of properties
395 const HashEntry* e = findPropertyHashEntry(exec, propertyName);
396 if (e) {
397 attributes = e->attributes;
398 return true;
399 }
400
401 return false;
402}
403
404void JSObject::getPropertyNames(ExecState* exec, PropertyNameArray& propertyNames)
405{
406 _prop.getEnumerablePropertyNames(propertyNames);
407
408 // Add properties from the static hashtables of properties
409 for (const ClassInfo* info = classInfo(); info; info = info->parentClass) {
410 const HashTable* table = info->propHashTable(exec);
411 if (!table)
412 continue;
413 table->initializeIfNeeded(exec);
414 ASSERT(table->table);
415 int hashSizeMask = table->hashSizeMask;
416 const HashEntry* e = table->table;
417 for (int i = 0; i <= hashSizeMask; ++i, ++e) {
418 if (e->key && !(e->attributes & DontEnum))
419 propertyNames.add(e->key);
420 }
421 }
422
423 if (_proto->isObject())
424 static_cast<JSObject*>(_proto)->getPropertyNames(exec, propertyNames);
425}
426
427bool JSObject::toBoolean(ExecState*) const
428{
429 return true;
430}
431
432double JSObject::toNumber(ExecState *exec) const
433{
434 JSValue *prim = toPrimitive(exec,NumberType);
435 if (exec->hadException()) // should be picked up soon in nodes.cpp
436 return 0.0;
437 return prim->toNumber(exec);
438}
439
440UString JSObject::toString(ExecState* exec) const
441{
442 JSValue* primitive = toPrimitive(exec, StringType);
443 if (exec->hadException())
444 return "";
445 return primitive->toString(exec);
446}
447
448JSObject *JSObject::toObject(ExecState*) const
449{
450 return const_cast<JSObject*>(this);
451}
452
453JSObject* JSObject::toThisObject(ExecState*) const
454{
455 return const_cast<JSObject*>(this);
456}
457
458JSGlobalObject* JSObject::toGlobalObject(ExecState*) const
459{
460 return 0;
461}
462
463void JSObject::removeDirect(const Identifier &propertyName)
464{
465 _prop.remove(propertyName);
466}
467
468void JSObject::putDirectFunction(InternalFunction* func, int attr)
469{
470 putDirect(func->functionName(), func, attr);
471}
472
473void JSObject::fillGetterPropertySlot(PropertySlot& slot, JSValue** location)
474{
475 if (JSObject* getterFunc = static_cast<GetterSetter*>(*location)->getter())
476 slot.setGetterSlot(getterFunc);
477 else
478 slot.setUndefined();
479}
480
481// ------------------------------ Error ----------------------------------------
482
483JSObject* Error::create(ExecState* exec, ErrorType errtype, const UString& message,
484 int lineno, int sourceId, const UString& sourceURL)
485{
486 JSObject* cons;
487 const char* name;
488 switch (errtype) {
489 case EvalError:
490 cons = exec->lexicalGlobalObject()->evalErrorConstructor();
491 name = "Evaluation error";
492 break;
493 case RangeError:
494 cons = exec->lexicalGlobalObject()->rangeErrorConstructor();
495 name = "Range error";
496 break;
497 case ReferenceError:
498 cons = exec->lexicalGlobalObject()->referenceErrorConstructor();
499 name = "Reference error";
500 break;
501 case SyntaxError:
502 cons = exec->lexicalGlobalObject()->syntaxErrorConstructor();
503 name = "Syntax error";
504 break;
505 case TypeError:
506 cons = exec->lexicalGlobalObject()->typeErrorConstructor();
507 name = "Type error";
508 break;
509 case URIError:
510 cons = exec->lexicalGlobalObject()->URIErrorConstructor();
511 name = "URI error";
512 break;
513 default:
514 cons = exec->lexicalGlobalObject()->errorConstructor();
515 name = "Error";
516 break;
517 }
518
519 ArgList args;
520 if (message.isEmpty())
521 args.append(jsString(exec, name));
522 else
523 args.append(jsString(exec, message));
524 ConstructData constructData;
525 ConstructType constructType = cons->getConstructData(constructData);
526 JSObject* err = construct(exec, cons, constructType, constructData, args);
527
528 if (lineno != -1)
529 err->put(exec, Identifier(exec, "line"), jsNumber(exec, lineno));
530 if (sourceId != -1)
531 err->put(exec, Identifier(exec, "sourceId"), jsNumber(exec, sourceId));
532
533 if(!sourceURL.isNull())
534 err->put(exec, Identifier(exec, "sourceURL"), jsString(exec, sourceURL));
535
536 return err;
537}
538
539JSObject *Error::create(ExecState *exec, ErrorType type, const char *message)
540{
541 return create(exec, type, message, -1, -1, NULL);
542}
543
544JSObject *throwError(ExecState *exec, ErrorType type)
545{
546 JSObject *error = Error::create(exec, type, UString(), -1, -1, NULL);
547 exec->setException(error);
548 return error;
549}
550
551JSObject *throwError(ExecState *exec, ErrorType type, const UString &message)
552{
553 JSObject *error = Error::create(exec, type, message, -1, -1, NULL);
554 exec->setException(error);
555 return error;
556}
557
558JSObject *throwError(ExecState *exec, ErrorType type, const char *message)
559{
560 JSObject *error = Error::create(exec, type, message, -1, -1, NULL);
561 exec->setException(error);
562 return error;
563}
564
565JSObject *throwError(ExecState *exec, ErrorType type, const UString &message, int line, int sourceId, const UString &sourceURL)
566{
567 JSObject *error = Error::create(exec, type, message, line, sourceId, sourceURL);
568 exec->setException(error);
569 return error;
570}
571
572JSObject* constructEmptyObject(ExecState* exec)
573{
574 return new (exec) JSObject(exec->lexicalGlobalObject()->objectPrototype());
575}
576
577} // namespace KJS
Note: See TracBrowser for help on using the repository browser.