source: webkit/trunk/JavaScriptCore/runtime/JSObject.cpp@ 43383

Last change on this file since 43383 was 43153, checked in by [email protected], 16 years ago

JavaScriptCore:

2009-05-02 Geoffrey Garen <[email protected]>

Reviewed by Sam Weinig.

Simplified null-ish JSValues.


Replaced calls to noValue() with calls to JSValue() (which is what
noValue() returned). Removed noValue().


Replaced almost all uses of jsImpossibleValue() with uses of JSValue().
Its one remaining use is for construction of hash table deleted values.
For that specific task, I made a new, private constructor with a special
tag. Removed jsImpossibleValue().


Removed "JSValue()" initialiazers, since default construction happens...
by default.

  • API/JSCallbackObjectFunctions.h: (JSC::::call):
  • bytecompiler/BytecodeGenerator.cpp: (JSC::BytecodeGenerator::emitLoad):
  • bytecompiler/BytecodeGenerator.h:
  • debugger/DebuggerCallFrame.cpp: (JSC::DebuggerCallFrame::evaluate):
  • debugger/DebuggerCallFrame.h: (JSC::DebuggerCallFrame::DebuggerCallFrame):
  • interpreter/CallFrame.h: (JSC::ExecState::clearException):
  • interpreter/Interpreter.cpp: (JSC::Interpreter::privateExecute): (JSC::Interpreter::retrieveLastCaller):
  • interpreter/Register.h: (JSC::Register::Register):
  • jit/JITCall.cpp: (JSC::JIT::unlinkCall): (JSC::JIT::compileOpCallInitializeCallFrame): (JSC::JIT::compileOpCall):
  • jit/JITStubs.cpp: (JSC::JITStubs::cti_op_call_eval): (JSC::JITStubs::cti_vm_throw):
  • profiler/Profiler.cpp: (JSC::Profiler::willExecute): (JSC::Profiler::didExecute):
  • runtime/ArrayPrototype.cpp: (JSC::getProperty):
  • runtime/Completion.cpp: (JSC::evaluate):
  • runtime/Completion.h: (JSC::Completion::Completion):
  • runtime/GetterSetter.cpp: (JSC::GetterSetter::getPrimitiveNumber):
  • runtime/JSArray.cpp: (JSC::JSArray::putSlowCase): (JSC::JSArray::deleteProperty): (JSC::JSArray::increaseVectorLength): (JSC::JSArray::setLength): (JSC::JSArray::pop): (JSC::JSArray::sort): (JSC::JSArray::compactForSorting):
  • runtime/JSCell.cpp: (JSC::JSCell::getJSNumber):
  • runtime/JSCell.h: (JSC::JSValue::getJSNumber):
  • runtime/JSGlobalData.cpp: (JSC::JSGlobalData::JSGlobalData):
  • runtime/JSImmediate.h: (JSC::JSImmediate::fromNumberOutsideIntegerRange): (JSC::JSImmediate::from):
  • runtime/JSNumberCell.cpp: (JSC::jsNumberCell):
  • runtime/JSObject.cpp: (JSC::callDefaultValueFunction):
  • runtime/JSObject.h: (JSC::JSObject::getDirect):
  • runtime/JSPropertyNameIterator.cpp: (JSC::JSPropertyNameIterator::toPrimitive):
  • runtime/JSPropertyNameIterator.h: (JSC::JSPropertyNameIterator::next):
  • runtime/JSValue.h: (JSC::JSValue::): (JSC::JSValueHashTraits::constructDeletedValue): (JSC::JSValueHashTraits::isDeletedValue): (JSC::JSValue::JSValue):
  • runtime/JSWrapperObject.h: (JSC::JSWrapperObject::JSWrapperObject):
  • runtime/Operations.h: (JSC::resolveBase):
  • runtime/PropertySlot.h: (JSC::PropertySlot::clearBase): (JSC::PropertySlot::clearValue):

WebCore:

2009-05-02 Geoffrey Garen <[email protected]>

Reviewed by Sam Weinig.

Simplified null-ish JSValues.


Replaced calls to noValue() with calls to JSValue() (which is what
noValue() returned). Removed noValue().


Removed "JSValue()" initialiazers, since default construction happens...
by default.

  • bindings/js/JSDOMBinding.cpp: (WebCore::setDOMException):
  • bindings/js/JSDOMWindowCustom.cpp: (WebCore::JSDOMWindow::open): (WebCore::JSDOMWindow::showModalDialog):
  • bindings/js/JSEventListener.cpp: (WebCore::JSEventListener::handleEvent):
  • bindings/js/JSJavaScriptCallFrameCustom.cpp: (WebCore::JSJavaScriptCallFrame::evaluate):
  • bindings/js/JSSQLResultSetRowListCustom.cpp: (WebCore::JSSQLResultSetRowList::item):
  • bindings/js/ScriptController.cpp: (WebCore::ScriptController::evaluate):
  • bindings/js/ScriptValue.h: (WebCore::ScriptValue::ScriptValue): (WebCore::ScriptValue::hasNoValue):
  • bindings/js/WorkerScriptController.cpp: (WebCore::WorkerScriptController::evaluate):
  • bridge/jni/jni_instance.cpp: (JavaInstance::invokeMethod):
  • bridge/jni/jni_runtime.cpp: (JavaField::dispatchValueFromInstance): (JavaField::dispatchSetValueToInstance):
  • bridge/runtime.h: (JSC::Bindings::Instance::invokeConstruct):

WebKit/mac:

2009-05-02 Geoffrey Garen <[email protected]>

Reviewed by Sam Weinig.

Simplified null-ish JSValues.


Replaced calls to noValue() with calls to JSValue() (which is what
noValue() returned). Removed noValue().


Removed "JSValue()" initialiazers, since default construction happens...
by default.

  • WebView/WebScriptDebugDelegate.mm: (-[WebScriptCallFrame evaluateWebScript:]):
  • Property svn:eol-style set to native
File size: 16.0 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 <wtf/Assertions.h>
39
40#define JSOBJECT_MARK_TRACING 0
41
42#if JSOBJECT_MARK_TRACING
43
44#define JSOBJECT_MARK_BEGIN() \
45 static int markStackDepth = 0; \
46 for (int i = 0; i < markStackDepth; i++) \
47 putchar('-'); \
48 printf("%s (%p)\n", className().UTF8String().c_str(), this); \
49 markStackDepth++; \
50
51#define JSOBJECT_MARK_END() \
52 markStackDepth--;
53
54#else // JSOBJECT_MARK_TRACING
55
56#define JSOBJECT_MARK_BEGIN()
57#define JSOBJECT_MARK_END()
58
59#endif // JSOBJECT_MARK_TRACING
60
61namespace JSC {
62
63ASSERT_CLASS_FITS_IN_CELL(JSObject);
64
65void JSObject::mark()
66{
67 JSOBJECT_MARK_BEGIN();
68
69 JSCell::mark();
70 m_structure->mark();
71
72 size_t storageSize = m_structure->propertyStorageSize();
73 for (size_t i = 0; i < storageSize; ++i) {
74 JSValue v = m_propertyStorage[i];
75 if (!v.marked())
76 v.mark();
77 }
78
79 JSOBJECT_MARK_END();
80}
81
82UString JSObject::className() const
83{
84 const ClassInfo* info = classInfo();
85 if (info)
86 return info->className;
87 return "Object";
88}
89
90bool JSObject::getOwnPropertySlot(ExecState* exec, unsigned propertyName, PropertySlot& slot)
91{
92 return getOwnPropertySlot(exec, Identifier::from(exec, propertyName), slot);
93}
94
95static void throwSetterError(ExecState* exec)
96{
97 throwError(exec, TypeError, "setting a property that has only a getter");
98}
99
100// ECMA 8.6.2.2
101void JSObject::put(ExecState* exec, const Identifier& propertyName, JSValue value, PutPropertySlot& slot)
102{
103 ASSERT(value);
104 ASSERT(!Heap::heap(value) || Heap::heap(value) == Heap::heap(this));
105
106 if (propertyName == exec->propertyNames().underscoreProto) {
107 // Setting __proto__ to a non-object, non-null value is silently ignored to match Mozilla.
108 if (!value.isObject() && !value.isNull())
109 return;
110
111 JSValue nextPrototypeValue = value;
112 while (nextPrototypeValue && nextPrototypeValue.isObject()) {
113 JSObject* nextPrototype = asObject(nextPrototypeValue)->unwrappedObject();
114 if (nextPrototype == this) {
115 throwError(exec, GeneralError, "cyclic __proto__ value");
116 return;
117 }
118 nextPrototypeValue = nextPrototype->prototype();
119 }
120
121 setPrototype(value);
122 return;
123 }
124
125 // Check if there are any setters or getters in the prototype chain
126 JSValue prototype;
127 for (JSObject* obj = this; !obj->structure()->hasGetterSetterProperties(); obj = asObject(prototype)) {
128 prototype = obj->prototype();
129 if (prototype.isNull()) {
130 putDirect(propertyName, value, 0, true, slot);
131 return;
132 }
133 }
134
135 unsigned attributes;
136 if ((m_structure->get(propertyName, attributes) != WTF::notFound) && attributes & ReadOnly)
137 return;
138
139 for (JSObject* obj = this; ; obj = asObject(prototype)) {
140 if (JSValue gs = obj->getDirect(propertyName)) {
141 if (gs.isGetterSetter()) {
142 JSObject* setterFunc = asGetterSetter(gs)->setter();
143 if (!setterFunc) {
144 throwSetterError(exec);
145 return;
146 }
147
148 CallData callData;
149 CallType callType = setterFunc->getCallData(callData);
150 MarkedArgumentBuffer args;
151 args.append(value);
152 call(exec, setterFunc, callType, callData, this, args);
153 return;
154 }
155
156 // If there's an existing property on the object or one of its
157 // prototypes it should be replaced, so break here.
158 break;
159 }
160
161 prototype = obj->prototype();
162 if (prototype.isNull())
163 break;
164 }
165
166 putDirect(propertyName, value, 0, true, slot);
167 return;
168}
169
170void JSObject::put(ExecState* exec, unsigned propertyName, JSValue value)
171{
172 PutPropertySlot slot;
173 put(exec, Identifier::from(exec, propertyName), value, slot);
174}
175
176void JSObject::putWithAttributes(ExecState*, const Identifier& propertyName, JSValue value, unsigned attributes)
177{
178 putDirect(propertyName, value, attributes);
179}
180
181void JSObject::putWithAttributes(ExecState* exec, unsigned propertyName, JSValue value, unsigned attributes)
182{
183 putWithAttributes(exec, Identifier::from(exec, propertyName), value, attributes);
184}
185
186bool JSObject::hasProperty(ExecState* exec, const Identifier& propertyName) const
187{
188 PropertySlot slot;
189 return const_cast<JSObject*>(this)->getPropertySlot(exec, propertyName, slot);
190}
191
192bool JSObject::hasProperty(ExecState* exec, unsigned propertyName) const
193{
194 PropertySlot slot;
195 return const_cast<JSObject*>(this)->getPropertySlot(exec, propertyName, slot);
196}
197
198// ECMA 8.6.2.5
199bool JSObject::deleteProperty(ExecState* exec, const Identifier& propertyName)
200{
201 unsigned attributes;
202 if (m_structure->get(propertyName, attributes) != WTF::notFound) {
203 if ((attributes & DontDelete))
204 return false;
205 removeDirect(propertyName);
206 return true;
207 }
208
209 // Look in the static hashtable of properties
210 const HashEntry* entry = findPropertyHashEntry(exec, propertyName);
211 if (entry && entry->attributes() & DontDelete)
212 return false; // this builtin property can't be deleted
213
214 // FIXME: Should the code here actually do some deletion?
215 return true;
216}
217
218bool JSObject::hasOwnProperty(ExecState* exec, const Identifier& propertyName) const
219{
220 PropertySlot slot;
221 return const_cast<JSObject*>(this)->getOwnPropertySlot(exec, propertyName, slot);
222}
223
224bool JSObject::deleteProperty(ExecState* exec, unsigned propertyName)
225{
226 return deleteProperty(exec, Identifier::from(exec, propertyName));
227}
228
229static ALWAYS_INLINE JSValue callDefaultValueFunction(ExecState* exec, const JSObject* object, const Identifier& propertyName)
230{
231 JSValue function = object->get(exec, propertyName);
232 CallData callData;
233 CallType callType = function.getCallData(callData);
234 if (callType == CallTypeNone)
235 return exec->exception();
236
237 // Prevent "toString" and "valueOf" from observing execution if an exception
238 // is pending.
239 if (exec->hadException())
240 return exec->exception();
241
242 JSValue result = call(exec, function, callType, callData, const_cast<JSObject*>(object), exec->emptyList());
243 ASSERT(!result.isGetterSetter());
244 if (exec->hadException())
245 return exec->exception();
246 if (result.isObject())
247 return JSValue();
248 return result;
249}
250
251bool JSObject::getPrimitiveNumber(ExecState* exec, double& number, JSValue& result)
252{
253 result = defaultValue(exec, PreferNumber);
254 number = result.toNumber(exec);
255 return !result.isString();
256}
257
258// ECMA 8.6.2.6
259JSValue JSObject::defaultValue(ExecState* exec, PreferredPrimitiveType hint) const
260{
261 // Must call toString first for Date objects.
262 if ((hint == PreferString) || (hint != PreferNumber && prototype() == exec->lexicalGlobalObject()->datePrototype())) {
263 JSValue value = callDefaultValueFunction(exec, this, exec->propertyNames().toString);
264 if (value)
265 return value;
266 value = callDefaultValueFunction(exec, this, exec->propertyNames().valueOf);
267 if (value)
268 return value;
269 } else {
270 JSValue value = callDefaultValueFunction(exec, this, exec->propertyNames().valueOf);
271 if (value)
272 return value;
273 value = callDefaultValueFunction(exec, this, exec->propertyNames().toString);
274 if (value)
275 return value;
276 }
277
278 ASSERT(!exec->hadException());
279
280 return throwError(exec, TypeError, "No default value");
281}
282
283const HashEntry* JSObject::findPropertyHashEntry(ExecState* exec, const Identifier& propertyName) const
284{
285 for (const ClassInfo* info = classInfo(); info; info = info->parentClass) {
286 if (const HashTable* propHashTable = info->propHashTable(exec)) {
287 if (const HashEntry* entry = propHashTable->entry(exec, propertyName))
288 return entry;
289 }
290 }
291 return 0;
292}
293
294void JSObject::defineGetter(ExecState* exec, const Identifier& propertyName, JSObject* getterFunction)
295{
296 JSValue object = getDirect(propertyName);
297 if (object && object.isGetterSetter()) {
298 ASSERT(m_structure->hasGetterSetterProperties());
299 asGetterSetter(object)->setGetter(getterFunction);
300 return;
301 }
302
303 PutPropertySlot slot;
304 GetterSetter* getterSetter = new (exec) GetterSetter;
305 putDirect(propertyName, getterSetter, None, true, slot);
306
307 // putDirect will change our Structure if we add a new property. For
308 // getters and setters, though, we also need to change our Structure
309 // if we override an existing non-getter or non-setter.
310 if (slot.type() != PutPropertySlot::NewProperty) {
311 if (!m_structure->isDictionary()) {
312 RefPtr<Structure> structure = Structure::getterSetterTransition(m_structure);
313 setStructure(structure.release());
314 }
315 }
316
317 m_structure->setHasGetterSetterProperties(true);
318 getterSetter->setGetter(getterFunction);
319}
320
321void JSObject::defineSetter(ExecState* exec, const Identifier& propertyName, JSObject* setterFunction)
322{
323 JSValue object = getDirect(propertyName);
324 if (object && object.isGetterSetter()) {
325 ASSERT(m_structure->hasGetterSetterProperties());
326 asGetterSetter(object)->setSetter(setterFunction);
327 return;
328 }
329
330 PutPropertySlot slot;
331 GetterSetter* getterSetter = new (exec) GetterSetter;
332 putDirect(propertyName, getterSetter, None, true, slot);
333
334 // putDirect will change our Structure if we add a new property. For
335 // getters and setters, though, we also need to change our Structure
336 // if we override an existing non-getter or non-setter.
337 if (slot.type() != PutPropertySlot::NewProperty) {
338 if (!m_structure->isDictionary()) {
339 RefPtr<Structure> structure = Structure::getterSetterTransition(m_structure);
340 setStructure(structure.release());
341 }
342 }
343
344 m_structure->setHasGetterSetterProperties(true);
345 getterSetter->setSetter(setterFunction);
346}
347
348JSValue JSObject::lookupGetter(ExecState*, const Identifier& propertyName)
349{
350 JSObject* object = this;
351 while (true) {
352 if (JSValue value = object->getDirect(propertyName)) {
353 if (!value.isGetterSetter())
354 return jsUndefined();
355 JSObject* functionObject = asGetterSetter(value)->getter();
356 if (!functionObject)
357 return jsUndefined();
358 return functionObject;
359 }
360
361 if (!object->prototype() || !object->prototype().isObject())
362 return jsUndefined();
363 object = asObject(object->prototype());
364 }
365}
366
367JSValue JSObject::lookupSetter(ExecState*, const Identifier& propertyName)
368{
369 JSObject* object = this;
370 while (true) {
371 if (JSValue value = object->getDirect(propertyName)) {
372 if (!value.isGetterSetter())
373 return jsUndefined();
374 JSObject* functionObject = asGetterSetter(value)->setter();
375 if (!functionObject)
376 return jsUndefined();
377 return functionObject;
378 }
379
380 if (!object->prototype() || !object->prototype().isObject())
381 return jsUndefined();
382 object = asObject(object->prototype());
383 }
384}
385
386bool JSObject::hasInstance(ExecState* exec, JSValue value, JSValue proto)
387{
388 if (!proto.isObject()) {
389 throwError(exec, TypeError, "instanceof called on an object with an invalid prototype property.");
390 return false;
391 }
392
393 if (!value.isObject())
394 return false;
395
396 JSObject* object = asObject(value);
397 while ((object = object->prototype().getObject())) {
398 if (proto == object)
399 return true;
400 }
401 return false;
402}
403
404bool JSObject::propertyIsEnumerable(ExecState* exec, const Identifier& propertyName) const
405{
406 unsigned attributes;
407 if (!getPropertyAttributes(exec, propertyName, attributes))
408 return false;
409 return !(attributes & DontEnum);
410}
411
412bool JSObject::getPropertyAttributes(ExecState* exec, const Identifier& propertyName, unsigned& attributes) const
413{
414 if (m_structure->get(propertyName, attributes) != WTF::notFound)
415 return true;
416
417 // Look in the static hashtable of properties
418 const HashEntry* entry = findPropertyHashEntry(exec, propertyName);
419 if (entry) {
420 attributes = entry->attributes();
421 return true;
422 }
423
424 return false;
425}
426
427void JSObject::getPropertyNames(ExecState* exec, PropertyNameArray& propertyNames)
428{
429 m_structure->getEnumerablePropertyNames(exec, propertyNames, this);
430}
431
432bool JSObject::toBoolean(ExecState*) const
433{
434 return true;
435}
436
437double JSObject::toNumber(ExecState* exec) const
438{
439 JSValue primitive = toPrimitive(exec, PreferNumber);
440 if (exec->hadException()) // should be picked up soon in Nodes.cpp
441 return 0.0;
442 return primitive.toNumber(exec);
443}
444
445UString JSObject::toString(ExecState* exec) const
446{
447 JSValue primitive = toPrimitive(exec, PreferString);
448 if (exec->hadException())
449 return "";
450 return primitive.toString(exec);
451}
452
453JSObject* JSObject::toObject(ExecState*) const
454{
455 return const_cast<JSObject*>(this);
456}
457
458JSObject* JSObject::toThisObject(ExecState*) const
459{
460 return const_cast<JSObject*>(this);
461}
462
463JSObject* JSObject::unwrappedObject()
464{
465 return this;
466}
467
468void JSObject::removeDirect(const Identifier& propertyName)
469{
470 size_t offset;
471 if (m_structure->isDictionary()) {
472 offset = m_structure->removePropertyWithoutTransition(propertyName);
473 if (offset != WTF::notFound)
474 m_propertyStorage[offset] = jsUndefined();
475 return;
476 }
477
478 RefPtr<Structure> structure = Structure::removePropertyTransition(m_structure, propertyName, offset);
479 if (offset != WTF::notFound)
480 m_propertyStorage[offset] = jsUndefined();
481 setStructure(structure.release());
482}
483
484void JSObject::putDirectFunction(ExecState* exec, InternalFunction* function, unsigned attr)
485{
486 putDirect(Identifier(exec, function->name(&exec->globalData())), function, attr);
487}
488
489void JSObject::putDirectFunctionWithoutTransition(ExecState* exec, InternalFunction* function, unsigned attr)
490{
491 putDirectWithoutTransition(Identifier(exec, function->name(&exec->globalData())), function, attr);
492}
493
494NEVER_INLINE void JSObject::fillGetterPropertySlot(PropertySlot& slot, JSValue* location)
495{
496 if (JSObject* getterFunction = asGetterSetter(*location)->getter())
497 slot.setGetterSlot(getterFunction);
498 else
499 slot.setUndefined();
500}
501
502Structure* JSObject::createInheritorID()
503{
504 m_inheritorID = JSObject::createStructure(this);
505 return m_inheritorID.get();
506}
507
508void JSObject::allocatePropertyStorage(size_t oldSize, size_t newSize)
509{
510 allocatePropertyStorageInline(oldSize, newSize);
511}
512
513JSObject* constructEmptyObject(ExecState* exec)
514{
515 return new (exec) JSObject(exec->lexicalGlobalObject()->emptyObjectStructure());
516}
517
518} // namespace JSC
Note: See TracBrowser for help on using the repository browser.