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

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

JavaScriptCore:

2008-07-04 Sam Weinig <[email protected]>

Rubber-stamped by Dan Bernstein.

Split Error and GetterSetter out of JSObject.h.

  • API/JSCallbackObjectFunctions.h:
  • GNUmakefile.am:
  • JavaScriptCore.pri:
  • JavaScriptCore.vcproj/JavaScriptCore/JavaScriptCore.vcproj:
  • JavaScriptCore.xcodeproj/project.pbxproj:
  • JavaScriptCoreSources.bkl:
  • kjs/AllInOneFile.cpp:
  • kjs/ClassInfo.h: Copied from JavaScriptCore/kjs/JSObject.h.
  • kjs/Error.cpp: Copied from JavaScriptCore/kjs/JSObject.cpp.
  • kjs/Error.h: Copied from JavaScriptCore/kjs/JSObject.h.
  • kjs/GetterSetter.cpp:
  • kjs/GetterSetter.h: Copied from JavaScriptCore/kjs/JSObject.h.
  • kjs/JSObject.cpp:
  • kjs/JSObject.h:
  • kjs/nodes.h:

JavaScriptGlue:

2008-07-04 Sam Weinig <[email protected]>

Rubber-stamped by Dan Bernstein.

  • JSObject.h: Rename the header guard as it now conflicts with the JSObject in JavaScriptCore.

WebCore:

2008-07-04 Sam Weinig <[email protected]>

Rubber-stamped by Dan Bernstein.

Split Error and GetterSetter out of JSObject.h.

  • ForwardingHeaders/kjs/Error.h: Added.
  • bindings/js/JSCanvasRenderingContext2DCustom.cpp:
  • bindings/js/JSClipboardCustom.cpp:
  • bindings/js/JSDOMWindowBase.cpp:
  • bindings/js/JSEventTargetBase.cpp:
  • bindings/js/JSHTMLDocumentCustom.cpp:
  • bindings/js/JSXMLHttpRequestCustom.cpp:
  • bindings/scripts/CodeGeneratorJS.pm:
  • bridge/NP_jsobject.cpp:
  • bridge/jni/jni_instance.cpp:
  • bridge/jni/jni_runtime.cpp:
  • bridge/objc/objc_instance.mm:
  • bridge/objc/objc_runtime.mm:
  • bridge/objc/objc_utility.h:
  • bridge/runtime_array.cpp:
  • bridge/runtime_method.cpp:
  • bridge/runtime_object.cpp:
  • Property svn:eol-style set to native
File size: 13.8 KB
Line 
1/*
2 * Copyright (C) 1999-2001 Harri Porten ([email protected])
3 * Copyright (C) 2001 Peter Kelly ([email protected])
4 * Copyright (C) 2003, 2004, 2005, 2006, 2008 Apple Inc. All rights reserved.
5 * Copyright (C) 2007 Eric Seidel ([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., 51 Franklin Street, Fifth Floor,
20 * Boston, MA 02110-1301, USA.
21 *
22 */
23
24#include "config.h"
25#include "JSObject.h"
26
27#include "DatePrototype.h"
28#include "ErrorConstructor.h"
29#include "GetterSetter.h"
30#include "JSGlobalObject.h"
31#include "NativeErrorConstructor.h"
32#include "ObjectPrototype.h"
33#include "PropertyNameArray.h"
34#include "lookup.h"
35#include "nodes.h"
36#include "operations.h"
37#include <math.h>
38#include <profiler/Profiler.h>
39#include <wtf/Assertions.h>
40
41#define JAVASCRIPT_MARK_TRACING 0
42
43namespace KJS {
44
45void JSObject::mark()
46{
47 JSCell::mark();
48
49#if JAVASCRIPT_MARK_TRACING
50 static int markStackDepth = 0;
51 markStackDepth++;
52 for (int i = 0; i < markStackDepth; i++)
53 putchar('-');
54
55 printf("%s (%p)\n", className().UTF8String().c_str(), this);
56#endif
57
58 JSValue *proto = _proto;
59 if (!proto->marked())
60 proto->mark();
61
62 _prop.mark();
63
64#if JAVASCRIPT_MARK_TRACING
65 markStackDepth--;
66#endif
67}
68
69JSType JSObject::type() const
70{
71 return ObjectType;
72}
73
74UString JSObject::className() const
75{
76 const ClassInfo *ci = classInfo();
77 if ( ci )
78 return ci->className;
79 return "Object";
80}
81
82bool JSObject::getOwnPropertySlot(ExecState *exec, unsigned propertyName, PropertySlot& slot)
83{
84 return getOwnPropertySlot(exec, Identifier::from(exec, propertyName), slot);
85}
86
87static void throwSetterError(ExecState *exec)
88{
89 throwError(exec, TypeError, "setting a property that has only a getter");
90}
91
92// ECMA 8.6.2.2
93void JSObject::put(ExecState* exec, const Identifier& propertyName, JSValue* value)
94{
95 ASSERT(value);
96 ASSERT(!Heap::heap(value) || Heap::heap(value) == Heap::heap(this));
97
98 if (propertyName == exec->propertyNames().underscoreProto) {
99 JSObject* proto = value->getObject();
100
101 // Setting __proto__ to a non-object, non-null value is silently ignored to match Mozilla.
102 if (!proto && value != jsNull())
103 return;
104
105 while (proto) {
106 if (proto == this) {
107 throwError(exec, GeneralError, "cyclic __proto__ value");
108 return;
109 }
110 proto = proto->prototype() ? proto->prototype()->getObject() : 0;
111 }
112
113 setPrototype(value);
114 return;
115 }
116
117 // Check if there are any setters or getters in the prototype chain
118 JSValue* prototype;
119 for (JSObject* obj = this; !obj->_prop.hasGetterSetterProperties(); obj = static_cast<JSObject*>(prototype)) {
120 prototype = obj->_proto;
121 if (prototype == jsNull()) {
122 _prop.put(propertyName, value, 0, true);
123 return;
124 }
125 }
126
127 unsigned attributes;
128 if (_prop.get(propertyName, attributes) && attributes & ReadOnly)
129 return;
130
131 for (JSObject* obj = this; ; obj = static_cast<JSObject*>(prototype)) {
132 if (JSValue* gs = obj->_prop.get(propertyName, attributes)) {
133 if (attributes & IsGetterSetter) {
134 JSObject* setterFunc = static_cast<GetterSetter*>(gs)->setter();
135 if (!setterFunc) {
136 throwSetterError(exec);
137 return;
138 }
139
140 CallData callData;
141 CallType callType = setterFunc->getCallData(callData);
142 ArgList args;
143 args.append(value);
144 call(exec, setterFunc, callType, callData, this, args);
145 return;
146 }
147
148 // If there's an existing property on the object or one of its
149 // prototypes it should be replaced, so break here.
150 break;
151 }
152
153 prototype = obj->_proto;
154 if (prototype == jsNull())
155 break;
156 }
157
158 _prop.put(propertyName, value, 0, true);
159}
160
161void JSObject::put(ExecState* exec, unsigned propertyName, JSValue* value)
162{
163 put(exec, Identifier::from(exec, propertyName), value);
164}
165
166void JSObject::putWithAttributes(ExecState*, const Identifier& propertyName, JSValue* value, unsigned attributes)
167{
168 putDirect(propertyName, value, attributes);
169}
170
171void JSObject::putWithAttributes(ExecState* exec, unsigned propertyName, JSValue* value, unsigned attributes)
172{
173 putWithAttributes(exec, Identifier::from(exec, propertyName), value, attributes);
174}
175
176bool JSObject::hasProperty(ExecState *exec, const Identifier &propertyName) const
177{
178 PropertySlot slot;
179 return const_cast<JSObject *>(this)->getPropertySlot(exec, propertyName, slot);
180}
181
182bool JSObject::hasProperty(ExecState *exec, unsigned propertyName) const
183{
184 PropertySlot slot;
185 return const_cast<JSObject *>(this)->getPropertySlot(exec, propertyName, slot);
186}
187
188// ECMA 8.6.2.5
189bool JSObject::deleteProperty(ExecState* exec, const Identifier &propertyName)
190{
191 unsigned attributes;
192 JSValue *v = _prop.get(propertyName, attributes);
193 if (v) {
194 if ((attributes & DontDelete))
195 return false;
196 _prop.remove(propertyName);
197 if (attributes & IsGetterSetter)
198 _prop.setHasGetterSetterProperties(_prop.containsGettersOrSetters());
199 return true;
200 }
201
202 // Look in the static hashtable of properties
203 const HashEntry* entry = findPropertyHashEntry(exec, propertyName);
204 if (entry && entry->attributes & DontDelete)
205 return false; // this builtin property can't be deleted
206 // FIXME: Should the code here actually do some deletion?
207 return true;
208}
209
210bool JSObject::hasOwnProperty(ExecState* exec, const Identifier& propertyName) const
211{
212 PropertySlot slot;
213 return const_cast<JSObject*>(this)->getOwnPropertySlot(exec, propertyName, slot);
214}
215
216bool JSObject::deleteProperty(ExecState *exec, unsigned propertyName)
217{
218 return deleteProperty(exec, Identifier::from(exec, propertyName));
219}
220
221static ALWAYS_INLINE JSValue* callDefaultValueFunction(ExecState* exec, const JSObject* object, const Identifier& propertyName)
222{
223 JSValue* function = object->get(exec, propertyName);
224 CallData callData;
225 CallType callType = function->getCallData(callData);
226 if (callType == CallTypeNone)
227 return exec->exception();
228
229 // Prevent "toString" and "valueOf" from observing execution if an exception
230 // is pending.
231 if (exec->hadException())
232 return exec->exception();
233
234 JSValue* result = call(exec, function, callType, callData, const_cast<JSObject*>(object), exec->emptyList());
235 ASSERT(result->type() != GetterSetterType);
236 if (exec->hadException())
237 return exec->exception();
238 if (result->isObject())
239 return 0;
240 return result;
241}
242
243bool JSObject::getPrimitiveNumber(ExecState* exec, double& number, JSValue*& result)
244{
245 result = defaultValue(exec, NumberType);
246 number = result->toNumber(exec);
247 return !result->isString();
248}
249
250// ECMA 8.6.2.6
251JSValue* JSObject::defaultValue(ExecState* exec, JSType hint) const
252{
253 // Must call toString first for Date objects.
254 if ((hint == StringType) || (hint != NumberType && _proto == exec->lexicalGlobalObject()->datePrototype())) {
255 if (JSValue* value = callDefaultValueFunction(exec, this, exec->propertyNames().toString))
256 return value;
257 if (JSValue* value = callDefaultValueFunction(exec, this, exec->propertyNames().valueOf))
258 return value;
259 } else {
260 if (JSValue* value = callDefaultValueFunction(exec, this, exec->propertyNames().valueOf))
261 return value;
262 if (JSValue* value = callDefaultValueFunction(exec, this, exec->propertyNames().toString))
263 return value;
264 }
265
266 ASSERT(!exec->hadException());
267
268 return throwError(exec, TypeError, "No default value");
269}
270
271const HashEntry* JSObject::findPropertyHashEntry(ExecState* exec, const Identifier& propertyName) const
272{
273 for (const ClassInfo* info = classInfo(); info; info = info->parentClass) {
274 if (const HashTable* propHashTable = info->propHashTable(exec)) {
275 if (const HashEntry* e = propHashTable->entry(exec, propertyName))
276 return e;
277 }
278 }
279 return 0;
280}
281
282void JSObject::defineGetter(ExecState* exec, const Identifier& propertyName, JSObject* getterFunc)
283{
284 JSValue *o = getDirect(propertyName);
285 GetterSetter *gs;
286
287 if (o && o->type() == GetterSetterType) {
288 gs = static_cast<GetterSetter *>(o);
289 } else {
290 gs = new (exec) GetterSetter;
291 putDirect(propertyName, gs, IsGetterSetter);
292 }
293
294 _prop.setHasGetterSetterProperties(true);
295 gs->setGetter(getterFunc);
296}
297
298void JSObject::defineSetter(ExecState* exec, const Identifier& propertyName, JSObject* setterFunc)
299{
300 JSValue *o = getDirect(propertyName);
301 GetterSetter *gs;
302
303 if (o && o->type() == GetterSetterType) {
304 gs = static_cast<GetterSetter *>(o);
305 } else {
306 gs = new (exec) GetterSetter;
307 putDirect(propertyName, gs, IsGetterSetter);
308 }
309
310 _prop.setHasGetterSetterProperties(true);
311 gs->setSetter(setterFunc);
312}
313
314JSValue* JSObject::lookupGetter(ExecState*, const Identifier& propertyName)
315{
316 JSObject* obj = this;
317 while (true) {
318 JSValue* v = obj->getDirect(propertyName);
319 if (v) {
320 if (v->type() != GetterSetterType)
321 return jsUndefined();
322 JSObject* funcObj = static_cast<GetterSetter*>(v)->getter();
323 if (!funcObj)
324 return jsUndefined();
325 return funcObj;
326 }
327
328 if (!obj->prototype() || !obj->prototype()->isObject())
329 return jsUndefined();
330 obj = static_cast<JSObject*>(obj->prototype());
331 }
332}
333
334JSValue* JSObject::lookupSetter(ExecState*, const Identifier& propertyName)
335{
336 JSObject* obj = this;
337 while (true) {
338 JSValue* v = obj->getDirect(propertyName);
339 if (v) {
340 if (v->type() != GetterSetterType)
341 return jsUndefined();
342 JSObject* funcObj = static_cast<GetterSetter*>(v)->setter();
343 if (!funcObj)
344 return jsUndefined();
345 return funcObj;
346 }
347
348 if (!obj->prototype() || !obj->prototype()->isObject())
349 return jsUndefined();
350 obj = static_cast<JSObject*>(obj->prototype());
351 }
352}
353
354bool JSObject::implementsHasInstance() const
355{
356 return false;
357}
358
359bool JSObject::hasInstance(ExecState* exec, JSValue* value)
360{
361 JSValue* proto = get(exec, exec->propertyNames().prototype);
362 if (!proto->isObject()) {
363 throwError(exec, TypeError, "instanceof called on an object with an invalid prototype property.");
364 return false;
365 }
366
367 if (!value->isObject())
368 return false;
369
370 JSObject* o = static_cast<JSObject*>(value);
371 while ((o = o->prototype()->getObject())) {
372 if (o == proto)
373 return true;
374 }
375 return false;
376}
377
378bool JSObject::propertyIsEnumerable(ExecState* exec, const Identifier& propertyName) const
379{
380 unsigned attributes;
381
382 if (!getPropertyAttributes(exec, propertyName, attributes))
383 return false;
384 else
385 return !(attributes & DontEnum);
386}
387
388bool JSObject::getPropertyAttributes(ExecState* exec, const Identifier& propertyName, unsigned& attributes) const
389{
390 if (_prop.get(propertyName, attributes))
391 return true;
392
393 // Look in the static hashtable of properties
394 const HashEntry* e = findPropertyHashEntry(exec, propertyName);
395 if (e) {
396 attributes = e->attributes;
397 return true;
398 }
399
400 return false;
401}
402
403void JSObject::getPropertyNames(ExecState* exec, PropertyNameArray& propertyNames)
404{
405 _prop.getEnumerablePropertyNames(propertyNames);
406
407 // Add properties from the static hashtables of properties
408 for (const ClassInfo* info = classInfo(); info; info = info->parentClass) {
409 const HashTable* table = info->propHashTable(exec);
410 if (!table)
411 continue;
412 table->initializeIfNeeded(exec);
413 ASSERT(table->table);
414 int hashSizeMask = table->hashSizeMask;
415 const HashEntry* e = table->table;
416 for (int i = 0; i <= hashSizeMask; ++i, ++e) {
417 if (e->key && !(e->attributes & DontEnum))
418 propertyNames.add(e->key);
419 }
420 }
421
422 if (_proto->isObject())
423 static_cast<JSObject*>(_proto)->getPropertyNames(exec, propertyNames);
424}
425
426bool JSObject::toBoolean(ExecState*) const
427{
428 return true;
429}
430
431double JSObject::toNumber(ExecState *exec) const
432{
433 JSValue *prim = toPrimitive(exec,NumberType);
434 if (exec->hadException()) // should be picked up soon in nodes.cpp
435 return 0.0;
436 return prim->toNumber(exec);
437}
438
439UString JSObject::toString(ExecState* exec) const
440{
441 JSValue* primitive = toPrimitive(exec, StringType);
442 if (exec->hadException())
443 return "";
444 return primitive->toString(exec);
445}
446
447JSObject *JSObject::toObject(ExecState*) const
448{
449 return const_cast<JSObject*>(this);
450}
451
452JSObject* JSObject::toThisObject(ExecState*) const
453{
454 return const_cast<JSObject*>(this);
455}
456
457JSGlobalObject* JSObject::toGlobalObject(ExecState*) const
458{
459 return 0;
460}
461
462void JSObject::removeDirect(const Identifier &propertyName)
463{
464 _prop.remove(propertyName);
465}
466
467void JSObject::putDirectFunction(InternalFunction* func, int attr)
468{
469 putDirect(func->functionName(), func, attr);
470}
471
472void JSObject::fillGetterPropertySlot(PropertySlot& slot, JSValue** location)
473{
474 if (JSObject* getterFunc = static_cast<GetterSetter*>(*location)->getter())
475 slot.setGetterSlot(getterFunc);
476 else
477 slot.setUndefined();
478}
479
480JSObject* constructEmptyObject(ExecState* exec)
481{
482 return new (exec) JSObject(exec->lexicalGlobalObject()->objectPrototype());
483}
484
485} // namespace KJS
Note: See TracBrowser for help on using the repository browser.