Bug 551763: Fix deletion of arguments ident. (r=Waldo)
[mozilla-central.git] / js / src / jsobjinlines.h
blob83695c945f4771683f0520eec0e14ff6e3dfcca9
1 /* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
2 * vim: set ts=8 sw=4 et tw=99:
4 * ***** BEGIN LICENSE BLOCK *****
5 * Version: MPL 1.1/GPL 2.0/LGPL 2.1
7 * The contents of this file are subject to the Mozilla Public License Version
8 * 1.1 (the "License"); you may not use this file except in compliance with
9 * the License. You may obtain a copy of the License at
10 * http://www.mozilla.org/MPL/
12 * Software distributed under the License is distributed on an "AS IS" basis,
13 * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
14 * for the specific language governing rights and limitations under the
15 * License.
17 * The Original Code is Mozilla Communicator client code, released
18 * March 31, 1998.
20 * The Initial Developer of the Original Code is
21 * Netscape Communications Corporation.
22 * Portions created by the Initial Developer are Copyright (C) 1998
23 * the Initial Developer. All Rights Reserved.
25 * Contributor(s):
27 * Alternatively, the contents of this file may be used under the terms of
28 * either of the GNU General Public License Version 2 or later (the "GPL"),
29 * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
30 * in which case the provisions of the GPL or the LGPL are applicable instead
31 * of those above. If you wish to allow use of your version of this file only
32 * under the terms of either the GPL or the LGPL, and not to allow others to
33 * use your version of this file under the terms of the MPL, indicate your
34 * decision by deleting the provisions above and replace them with the notice
35 * and other provisions required by the GPL or the LGPL. If you do not delete
36 * the provisions above, a recipient may use your version of this file under
37 * the terms of any one of the MPL, the GPL or the LGPL.
39 * ***** END LICENSE BLOCK ***** */
41 #ifndef jsobjinlines_h___
42 #define jsobjinlines_h___
44 #include "jsbool.h"
45 #include "jsdate.h"
46 #include "jsiter.h"
47 #include "jsobj.h"
48 #include "jsscope.h"
50 #ifdef INCLUDE_MOZILLA_DTRACE
51 #include "jsdtracef.h"
52 #endif
54 #include "jsscopeinlines.h"
56 inline jsval
57 JSObject::getSlotMT(JSContext *cx, uintN slot)
59 #ifdef JS_THREADSAFE
61 * If thread-safe, define a getSlotMT() that bypasses, for a native
62 * object, the lock-free "fast path" test of
63 * (obj->scope()->ownercx == cx), to avoid needlessly switching from
64 * lock-free to lock-full scope when doing GC on a different context
65 * from the last one to own the scope. The caller in this case is
66 * probably a JSClass.mark function, e.g., fun_mark, or maybe a
67 * finalizer.
69 OBJ_CHECK_SLOT(this, slot);
70 return (scope()->title.ownercx == cx)
71 ? this->lockedGetSlot(slot)
72 : js_GetSlotThreadSafe(cx, this, slot);
73 #else
74 return this->lockedGetSlot(slot);
75 #endif
78 inline void
79 JSObject::setSlotMT(JSContext *cx, uintN slot, jsval value)
81 #ifdef JS_THREADSAFE
82 /* Thread-safe way to set a slot. */
83 OBJ_CHECK_SLOT(this, slot);
84 if (scope()->title.ownercx == cx)
85 this->lockedSetSlot(slot, value);
86 else
87 js_SetSlotThreadSafe(cx, this, slot, value);
88 #else
89 this->lockedSetSlot(slot, value);
90 #endif
93 inline bool
94 JSObject::isPrimitive() const
96 return isNumber() || isString() || isBoolean();
99 inline jsval
100 JSObject::getPrimitiveThis() const
102 JS_ASSERT(isPrimitive());
103 return fslots[JSSLOT_PRIMITIVE_THIS];
106 inline void
107 JSObject::setPrimitiveThis(jsval pthis)
109 JS_ASSERT(isPrimitive());
110 fslots[JSSLOT_PRIMITIVE_THIS] = pthis;
113 inline void
114 JSObject::staticAssertArrayLengthIsInPrivateSlot()
116 JS_STATIC_ASSERT(JSSLOT_ARRAY_LENGTH == JSSLOT_PRIVATE);
119 inline bool
120 JSObject::isDenseArrayMinLenCapOk(bool strictAboutLength) const
122 JS_ASSERT(isDenseArray());
123 uint32 length = uncheckedGetArrayLength();
124 uint32 capacity = uncheckedGetDenseArrayCapacity();
125 uint32 minLenCap = uint32(fslots[JSSLOT_DENSE_ARRAY_MINLENCAP]);
127 // This function can be called while the LENGTH and MINLENCAP slots are
128 // still set to JSVAL_VOID and there are no dslots (ie. the capacity is
129 // zero). If 'strictAboutLength' is false we allow this.
130 return minLenCap == JS_MIN(length, capacity) ||
131 (!strictAboutLength && minLenCap == uint32(JSVAL_VOID) &&
132 length == uint32(JSVAL_VOID) && capacity == 0);
135 inline uint32
136 JSObject::uncheckedGetArrayLength() const
138 return uint32(fslots[JSSLOT_ARRAY_LENGTH]);
141 inline uint32
142 JSObject::getArrayLength() const
144 JS_ASSERT(isArray());
145 JS_ASSERT_IF(isDenseArray(), isDenseArrayMinLenCapOk());
146 return uncheckedGetArrayLength();
149 inline void
150 JSObject::setDenseArrayLength(uint32 length)
152 JS_ASSERT(isDenseArray());
153 fslots[JSSLOT_ARRAY_LENGTH] = length;
154 uint32 capacity = uncheckedGetDenseArrayCapacity();
155 fslots[JSSLOT_DENSE_ARRAY_MINLENCAP] = JS_MIN(length, capacity);
158 inline void
159 JSObject::setSlowArrayLength(uint32 length)
161 JS_ASSERT(isSlowArray());
162 fslots[JSSLOT_ARRAY_LENGTH] = length;
165 inline uint32
166 JSObject::getDenseArrayCount() const
168 JS_ASSERT(isDenseArray());
169 return uint32(fslots[JSSLOT_DENSE_ARRAY_COUNT]);
172 inline void
173 JSObject::setDenseArrayCount(uint32 count)
175 JS_ASSERT(isDenseArray());
176 fslots[JSSLOT_DENSE_ARRAY_COUNT] = count;
179 inline void
180 JSObject::incDenseArrayCountBy(uint32 posDelta)
182 JS_ASSERT(isDenseArray());
183 fslots[JSSLOT_DENSE_ARRAY_COUNT] += posDelta;
186 inline void
187 JSObject::decDenseArrayCountBy(uint32 negDelta)
189 JS_ASSERT(isDenseArray());
190 fslots[JSSLOT_DENSE_ARRAY_COUNT] -= negDelta;
193 inline uint32
194 JSObject::uncheckedGetDenseArrayCapacity() const
196 return dslots ? uint32(dslots[-1]) : 0;
199 inline uint32
200 JSObject::getDenseArrayCapacity() const
202 JS_ASSERT(isDenseArray());
203 JS_ASSERT(isDenseArrayMinLenCapOk(/* strictAboutLength = */false));
204 return uncheckedGetDenseArrayCapacity();
207 inline void
208 JSObject::setDenseArrayCapacity(uint32 capacity)
210 JS_ASSERT(isDenseArray());
211 JS_ASSERT(dslots);
212 dslots[-1] = capacity;
213 uint32 length = uncheckedGetArrayLength();
214 fslots[JSSLOT_DENSE_ARRAY_MINLENCAP] = JS_MIN(length, capacity);
217 inline jsval
218 JSObject::getDenseArrayElement(uint32 i) const
220 JS_ASSERT(isDenseArray());
221 JS_ASSERT(i < getDenseArrayCapacity());
222 return dslots[i];
225 inline jsval *
226 JSObject::addressOfDenseArrayElement(uint32 i)
228 JS_ASSERT(isDenseArray());
229 JS_ASSERT(i < getDenseArrayCapacity());
230 return &dslots[i];
233 inline void
234 JSObject::setDenseArrayElement(uint32 i, jsval v)
236 JS_ASSERT(isDenseArray());
237 JS_ASSERT(i < getDenseArrayCapacity());
238 dslots[i] = v;
241 inline jsval *
242 JSObject::getDenseArrayElements() const
244 JS_ASSERT(isDenseArray());
245 return dslots;
248 inline void
249 JSObject::freeDenseArrayElements(JSContext *cx)
251 JS_ASSERT(isDenseArray());
252 if (dslots) {
253 cx->free(dslots - 1);
254 dslots = NULL;
256 fslots[JSSLOT_DENSE_ARRAY_MINLENCAP] = 0;
257 JS_ASSERT(isDenseArrayMinLenCapOk());
260 inline void
261 JSObject::voidDenseOnlyArraySlots()
263 JS_ASSERT(isDenseArray());
264 fslots[JSSLOT_DENSE_ARRAY_COUNT] = JSVAL_VOID;
265 fslots[JSSLOT_DENSE_ARRAY_MINLENCAP] = JSVAL_VOID;
268 inline void
269 JSObject::setArgsLength(uint32 argc)
271 JS_ASSERT(isArguments());
272 JS_ASSERT(argc <= JS_ARGS_LENGTH_MAX);
273 fslots[JSSLOT_ARGS_LENGTH] = INT_TO_JSVAL(argc << 1);
274 JS_ASSERT(!isArgsLengthOverridden());
277 inline uint32
278 JSObject::getArgsLength() const
280 JS_ASSERT(isArguments());
281 uint32 argc = uint32(JSVAL_TO_INT(fslots[JSSLOT_ARGS_LENGTH])) >> 1;
282 JS_ASSERT(argc <= JS_ARGS_LENGTH_MAX);
283 return argc;
286 inline void
287 JSObject::setArgsLengthOverridden()
289 JS_ASSERT(isArguments());
290 jsval v = fslots[JSSLOT_ARGS_LENGTH];
291 v = INT_TO_JSVAL(JSVAL_TO_INT(v) | 1);
292 JS_ASSERT(JSVAL_IS_INT(v));
293 fslots[JSSLOT_ARGS_LENGTH] = v;
296 inline bool
297 JSObject::isArgsLengthOverridden() const
299 JS_ASSERT(isArguments());
300 jsval v = fslots[JSSLOT_ARGS_LENGTH];
301 return (JSVAL_TO_INT(v) & 1) != 0;
304 inline jsval
305 JSObject::getArgsCallee() const
307 JS_ASSERT(isArguments());
308 return fslots[JSSLOT_ARGS_CALLEE];
311 inline void
312 JSObject::setArgsCallee(jsval callee)
314 JS_ASSERT(isArguments());
315 fslots[JSSLOT_ARGS_CALLEE] = callee;
318 inline jsval
319 JSObject::getArgsElement(uint32 i) const
321 JS_ASSERT(isArguments());
322 JS_ASSERT(i < numSlots() - JS_INITIAL_NSLOTS);
323 return dslots[i];
326 inline void
327 JSObject::setArgsElement(uint32 i, jsval v)
329 JS_ASSERT(isArguments());
330 JS_ASSERT(i < numSlots() - JS_INITIAL_NSLOTS);
331 dslots[i] = v;
334 inline jsval
335 JSObject::getDateLocalTime() const
337 JS_ASSERT(isDate());
338 return fslots[JSSLOT_DATE_LOCAL_TIME];
341 inline jsval *
342 JSObject::addressOfDateLocalTime()
344 JS_ASSERT(isDate());
345 return &fslots[JSSLOT_DATE_LOCAL_TIME];
348 inline void
349 JSObject::setDateLocalTime(jsval time)
351 JS_ASSERT(isDate());
352 fslots[JSSLOT_DATE_LOCAL_TIME] = time;
355 inline jsval
356 JSObject::getDateUTCTime() const
358 JS_ASSERT(isDate());
359 return fslots[JSSLOT_DATE_UTC_TIME];
362 inline jsval *
363 JSObject::addressOfDateUTCTime()
365 JS_ASSERT(isDate());
366 return &fslots[JSSLOT_DATE_UTC_TIME];
369 inline void
370 JSObject::setDateUTCTime(jsval time)
372 JS_ASSERT(isDate());
373 fslots[JSSLOT_DATE_UTC_TIME] = time;
376 inline jsval
377 JSObject::getRegExpLastIndex() const
379 JS_ASSERT(isRegExp());
380 return fslots[JSSLOT_REGEXP_LAST_INDEX];
383 inline jsval *
384 JSObject::addressOfRegExpLastIndex()
386 JS_ASSERT(isRegExp());
387 return &fslots[JSSLOT_REGEXP_LAST_INDEX];
390 inline void
391 JSObject::zeroRegExpLastIndex()
393 JS_ASSERT(isRegExp());
394 fslots[JSSLOT_REGEXP_LAST_INDEX] = JSVAL_ZERO;
397 inline void
398 JSObject::initSharingEmptyScope(JSClass *clasp, JSObject *proto, JSObject *parent,
399 jsval privateSlotValue)
401 init(clasp, proto, parent, privateSlotValue);
403 JSEmptyScope *emptyScope = proto->scope()->emptyScope;
404 JS_ASSERT(emptyScope->clasp == clasp);
405 emptyScope->hold();
406 map = emptyScope;
409 inline void
410 JSObject::freeSlotsArray(JSContext *cx)
412 JS_ASSERT(hasSlotsArray());
413 JS_ASSERT(size_t(dslots[-1]) > JS_INITIAL_NSLOTS);
414 cx->free(dslots - 1);
417 inline bool
418 JSObject::unbrand(JSContext *cx)
420 if (this->isNative()) {
421 JS_LOCK_OBJ(cx, this);
422 JSScope *scope = this->scope();
423 if (scope->isSharedEmpty()) {
424 scope = js_GetMutableScope(cx, this);
425 if (!scope) {
426 JS_UNLOCK_OBJ(cx, this);
427 return false;
430 scope->setGeneric();
431 JS_UNLOCK_SCOPE(cx, scope);
433 return true;
436 namespace js {
438 typedef Vector<PropertyDescriptor, 1> PropertyDescriptorArray;
440 class AutoDescriptorArray : private AutoGCRooter
442 public:
443 AutoDescriptorArray(JSContext *cx)
444 : AutoGCRooter(cx, DESCRIPTORS), descriptors(cx)
447 PropertyDescriptor *append() {
448 if (!descriptors.append(PropertyDescriptor()))
449 return NULL;
450 return &descriptors.back();
453 PropertyDescriptor& operator[](size_t i) {
454 JS_ASSERT(i < descriptors.length());
455 return descriptors[i];
458 friend void AutoGCRooter::trace(JSTracer *trc);
460 private:
461 PropertyDescriptorArray descriptors;
464 static inline bool
465 InitScopeForObject(JSContext* cx, JSObject* obj, JSClass *clasp, JSObject* proto, JSObjectOps* ops)
467 JS_ASSERT(ops->isNative());
468 JS_ASSERT(proto == obj->getProto());
470 /* Share proto's emptyScope only if obj is similar to proto. */
471 JSScope *scope = NULL;
473 if (proto && proto->isNative()) {
474 JS_LOCK_OBJ(cx, proto);
475 scope = proto->scope();
476 if (scope->canProvideEmptyScope(ops, clasp)) {
477 JSScope *emptyScope = scope->getEmptyScope(cx, clasp);
478 JS_UNLOCK_SCOPE(cx, scope);
479 if (!emptyScope)
480 goto bad;
481 scope = emptyScope;
482 } else {
483 JS_UNLOCK_SCOPE(cx, scope);
484 scope = NULL;
488 if (!scope) {
489 scope = JSScope::create(cx, ops, clasp, obj, js_GenerateShape(cx, false));
490 if (!scope)
491 goto bad;
493 /* Let JSScope::create set freeslot so as to reserve slots. */
494 JS_ASSERT(scope->freeslot >= JSSLOT_PRIVATE);
495 if (scope->freeslot > JS_INITIAL_NSLOTS &&
496 !obj->allocSlots(cx, scope->freeslot)) {
497 scope->destroy(cx);
498 goto bad;
502 obj->map = scope;
503 return true;
505 bad:
506 /* The GC nulls map initially. It should still be null on error. */
507 JS_ASSERT(!obj->map);
508 return false;
511 static inline JSObject *
512 NewObjectWithGivenProto(JSContext *cx, JSClass *clasp, JSObject *proto,
513 JSObject *parent, size_t objectSize = 0)
515 #ifdef INCLUDE_MOZILLA_DTRACE
516 if (JAVASCRIPT_OBJECT_CREATE_START_ENABLED())
517 jsdtrace_object_create_start(cx->fp, clasp);
518 #endif
520 /* Assert that the class is a proper class. */
521 JS_ASSERT_IF(clasp->flags & JSCLASS_IS_EXTENDED,
522 ((JSExtendedClass *)clasp)->equality);
524 /* Always call the class's getObjectOps hook if it has one. */
525 JSObjectOps *ops = clasp->getObjectOps
526 ? clasp->getObjectOps(cx, clasp)
527 : &js_ObjectOps;
530 * Allocate an object from the GC heap and initialize all its fields before
531 * doing any operation that can potentially trigger GC. Functions have a
532 * larger non-standard allocation size.
534 JSObject* obj;
535 if (clasp == &js_FunctionClass && !objectSize) {
536 obj = (JSObject*) js_NewGCFunction(cx);
537 #ifdef DEBUG
538 if (obj) {
539 memset((uint8 *) obj + sizeof(JSObject), JS_FREE_PATTERN,
540 sizeof(JSFunction) - sizeof(JSObject));
542 #endif
543 } else {
544 JS_ASSERT(!objectSize || objectSize == sizeof(JSObject));
545 obj = (clasp == &js_IteratorClass)
546 ? js_NewGCIter(cx)
547 : js_NewGCObject(cx);
549 if (!obj)
550 goto out;
553 * Default parent to the parent of the prototype, which was set from
554 * the parent of the prototype's constructor.
556 obj->init(clasp,
557 proto,
558 (!parent && proto) ? proto->getParent() : parent,
559 JSObject::defaultPrivate(clasp));
561 if (ops->isNative()) {
562 if (!InitScopeForObject(cx, obj, clasp, proto, ops)) {
563 obj = NULL;
564 goto out;
566 } else {
567 JS_ASSERT(ops->objectMap->ops == ops);
568 obj->map = const_cast<JSObjectMap *>(ops->objectMap);
572 * Do not call debug hooks on trace, because we might be in a non-_FAIL
573 * builtin. See bug 481444.
575 if (cx->debugHooks->objectHook && !JS_ON_TRACE(cx)) {
576 AutoValueRooter tvr(cx, obj);
577 AutoKeepAtoms keep(cx->runtime);
578 cx->debugHooks->objectHook(cx, obj, JS_TRUE,
579 cx->debugHooks->objectHookData);
580 cx->weakRoots.finalizableNewborns[FINALIZE_OBJECT] = obj;
583 out:
584 #ifdef INCLUDE_MOZILLA_DTRACE
585 if (JAVASCRIPT_OBJECT_CREATE_ENABLED())
586 jsdtrace_object_create(cx, clasp, obj);
587 if (JAVASCRIPT_OBJECT_CREATE_DONE_ENABLED())
588 jsdtrace_object_create_done(cx->fp, clasp);
589 #endif
590 return obj;
593 static inline JSProtoKey
594 GetClassProtoKey(JSClass *clasp)
596 JSProtoKey key = JSCLASS_CACHED_PROTO_KEY(clasp);
597 if (key != JSProto_Null)
598 return key;
599 if (clasp->flags & JSCLASS_IS_ANONYMOUS)
600 return JSProto_Object;
601 return JSProto_Null;
604 static inline JSObject *
605 NewObject(JSContext *cx, JSClass *clasp, JSObject *proto,
606 JSObject *parent, size_t objectSize = 0)
608 /* Bootstrap the ur-object, and make it the default prototype object. */
609 if (!proto) {
610 JSProtoKey protoKey = GetClassProtoKey(clasp);
611 if (!js_GetClassPrototype(cx, parent, protoKey, &proto, clasp))
612 return NULL;
613 if (!proto &&
614 !js_GetClassPrototype(cx, parent, JSProto_Object, &proto)) {
615 return NULL;
619 return NewObjectWithGivenProto(cx, clasp, proto, parent, objectSize);
624 #endif /* jsobjinlines_h___ */