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
17 * The Original Code is Mozilla Communicator client code, released
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.
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___
50 #ifdef INCLUDE_MOZILLA_DTRACE
51 #include "jsdtracef.h"
54 #include "jsscopeinlines.h"
57 JSObject::getSlotMT(JSContext
*cx
, uintN slot
)
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
69 OBJ_CHECK_SLOT(this, slot
);
70 return (scope()->title
.ownercx
== cx
)
71 ? this->lockedGetSlot(slot
)
72 : js_GetSlotThreadSafe(cx
, this, slot
);
74 return this->lockedGetSlot(slot
);
79 JSObject::setSlotMT(JSContext
*cx
, uintN slot
, jsval value
)
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
);
87 js_SetSlotThreadSafe(cx
, this, slot
, value
);
89 this->lockedSetSlot(slot
, value
);
94 JSObject::isPrimitive() const
96 return isNumber() || isString() || isBoolean();
100 JSObject::getPrimitiveThis() const
102 JS_ASSERT(isPrimitive());
103 return fslots
[JSSLOT_PRIMITIVE_THIS
];
107 JSObject::setPrimitiveThis(jsval pthis
)
109 JS_ASSERT(isPrimitive());
110 fslots
[JSSLOT_PRIMITIVE_THIS
] = pthis
;
114 JSObject::staticAssertArrayLengthIsInPrivateSlot()
116 JS_STATIC_ASSERT(JSSLOT_ARRAY_LENGTH
== JSSLOT_PRIVATE
);
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);
136 JSObject::uncheckedGetArrayLength() const
138 return uint32(fslots
[JSSLOT_ARRAY_LENGTH
]);
142 JSObject::getArrayLength() const
144 JS_ASSERT(isArray());
145 JS_ASSERT_IF(isDenseArray(), isDenseArrayMinLenCapOk());
146 return uncheckedGetArrayLength();
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
);
159 JSObject::setSlowArrayLength(uint32 length
)
161 JS_ASSERT(isSlowArray());
162 fslots
[JSSLOT_ARRAY_LENGTH
] = length
;
166 JSObject::getDenseArrayCount() const
168 JS_ASSERT(isDenseArray());
169 return uint32(fslots
[JSSLOT_DENSE_ARRAY_COUNT
]);
173 JSObject::setDenseArrayCount(uint32 count
)
175 JS_ASSERT(isDenseArray());
176 fslots
[JSSLOT_DENSE_ARRAY_COUNT
] = count
;
180 JSObject::incDenseArrayCountBy(uint32 posDelta
)
182 JS_ASSERT(isDenseArray());
183 fslots
[JSSLOT_DENSE_ARRAY_COUNT
] += posDelta
;
187 JSObject::decDenseArrayCountBy(uint32 negDelta
)
189 JS_ASSERT(isDenseArray());
190 fslots
[JSSLOT_DENSE_ARRAY_COUNT
] -= negDelta
;
194 JSObject::uncheckedGetDenseArrayCapacity() const
196 return dslots
? uint32(dslots
[-1]) : 0;
200 JSObject::getDenseArrayCapacity() const
202 JS_ASSERT(isDenseArray());
203 JS_ASSERT(isDenseArrayMinLenCapOk(/* strictAboutLength = */false));
204 return uncheckedGetDenseArrayCapacity();
208 JSObject::setDenseArrayCapacity(uint32 capacity
)
210 JS_ASSERT(isDenseArray());
212 dslots
[-1] = capacity
;
213 uint32 length
= uncheckedGetArrayLength();
214 fslots
[JSSLOT_DENSE_ARRAY_MINLENCAP
] = JS_MIN(length
, capacity
);
218 JSObject::getDenseArrayElement(uint32 i
) const
220 JS_ASSERT(isDenseArray());
221 JS_ASSERT(i
< getDenseArrayCapacity());
226 JSObject::addressOfDenseArrayElement(uint32 i
)
228 JS_ASSERT(isDenseArray());
229 JS_ASSERT(i
< getDenseArrayCapacity());
234 JSObject::setDenseArrayElement(uint32 i
, jsval v
)
236 JS_ASSERT(isDenseArray());
237 JS_ASSERT(i
< getDenseArrayCapacity());
242 JSObject::getDenseArrayElements() const
244 JS_ASSERT(isDenseArray());
249 JSObject::freeDenseArrayElements(JSContext
*cx
)
251 JS_ASSERT(isDenseArray());
253 cx
->free(dslots
- 1);
256 fslots
[JSSLOT_DENSE_ARRAY_MINLENCAP
] = 0;
257 JS_ASSERT(isDenseArrayMinLenCapOk());
261 JSObject::voidDenseOnlyArraySlots()
263 JS_ASSERT(isDenseArray());
264 fslots
[JSSLOT_DENSE_ARRAY_COUNT
] = JSVAL_VOID
;
265 fslots
[JSSLOT_DENSE_ARRAY_MINLENCAP
] = JSVAL_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());
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
);
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
;
297 JSObject::isArgsLengthOverridden() const
299 JS_ASSERT(isArguments());
300 jsval v
= fslots
[JSSLOT_ARGS_LENGTH
];
301 return (JSVAL_TO_INT(v
) & 1) != 0;
305 JSObject::getArgsCallee() const
307 JS_ASSERT(isArguments());
308 return fslots
[JSSLOT_ARGS_CALLEE
];
312 JSObject::setArgsCallee(jsval callee
)
314 JS_ASSERT(isArguments());
315 fslots
[JSSLOT_ARGS_CALLEE
] = callee
;
319 JSObject::getArgsElement(uint32 i
) const
321 JS_ASSERT(isArguments());
322 JS_ASSERT(i
< numSlots() - JS_INITIAL_NSLOTS
);
327 JSObject::setArgsElement(uint32 i
, jsval v
)
329 JS_ASSERT(isArguments());
330 JS_ASSERT(i
< numSlots() - JS_INITIAL_NSLOTS
);
335 JSObject::getDateLocalTime() const
338 return fslots
[JSSLOT_DATE_LOCAL_TIME
];
342 JSObject::addressOfDateLocalTime()
345 return &fslots
[JSSLOT_DATE_LOCAL_TIME
];
349 JSObject::setDateLocalTime(jsval time
)
352 fslots
[JSSLOT_DATE_LOCAL_TIME
] = time
;
356 JSObject::getDateUTCTime() const
359 return fslots
[JSSLOT_DATE_UTC_TIME
];
363 JSObject::addressOfDateUTCTime()
366 return &fslots
[JSSLOT_DATE_UTC_TIME
];
370 JSObject::setDateUTCTime(jsval time
)
373 fslots
[JSSLOT_DATE_UTC_TIME
] = time
;
377 JSObject::getRegExpLastIndex() const
379 JS_ASSERT(isRegExp());
380 return fslots
[JSSLOT_REGEXP_LAST_INDEX
];
384 JSObject::addressOfRegExpLastIndex()
386 JS_ASSERT(isRegExp());
387 return &fslots
[JSSLOT_REGEXP_LAST_INDEX
];
391 JSObject::zeroRegExpLastIndex()
393 JS_ASSERT(isRegExp());
394 fslots
[JSSLOT_REGEXP_LAST_INDEX
] = JSVAL_ZERO
;
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
);
410 JSObject::freeSlotsArray(JSContext
*cx
)
412 JS_ASSERT(hasSlotsArray());
413 JS_ASSERT(size_t(dslots
[-1]) > JS_INITIAL_NSLOTS
);
414 cx
->free(dslots
- 1);
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);
426 JS_UNLOCK_OBJ(cx
, this);
431 JS_UNLOCK_SCOPE(cx
, scope
);
438 typedef Vector
<PropertyDescriptor
, 1> PropertyDescriptorArray
;
440 class AutoDescriptorArray
: private AutoGCRooter
443 AutoDescriptorArray(JSContext
*cx
)
444 : AutoGCRooter(cx
, DESCRIPTORS
), descriptors(cx
)
447 PropertyDescriptor
*append() {
448 if (!descriptors
.append(PropertyDescriptor()))
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
);
461 PropertyDescriptorArray descriptors
;
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
);
483 JS_UNLOCK_SCOPE(cx
, scope
);
489 scope
= JSScope::create(cx
, ops
, clasp
, obj
, js_GenerateShape(cx
, false));
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
)) {
506 /* The GC nulls map initially. It should still be null on error. */
507 JS_ASSERT(!obj
->map
);
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
);
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
)
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.
535 if (clasp
== &js_FunctionClass
&& !objectSize
) {
536 obj
= (JSObject
*) js_NewGCFunction(cx
);
539 memset((uint8
*) obj
+ sizeof(JSObject
), JS_FREE_PATTERN
,
540 sizeof(JSFunction
) - sizeof(JSObject
));
544 JS_ASSERT(!objectSize
|| objectSize
== sizeof(JSObject
));
545 obj
= (clasp
== &js_IteratorClass
)
547 : js_NewGCObject(cx
);
553 * Default parent to the parent of the prototype, which was set from
554 * the parent of the prototype's constructor.
558 (!parent
&& proto
) ? proto
->getParent() : parent
,
559 JSObject::defaultPrivate(clasp
));
561 if (ops
->isNative()) {
562 if (!InitScopeForObject(cx
, obj
, clasp
, proto
, ops
)) {
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
;
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
);
593 static inline JSProtoKey
594 GetClassProtoKey(JSClass
*clasp
)
596 JSProtoKey key
= JSCLASS_CACHED_PROTO_KEY(clasp
);
597 if (key
!= JSProto_Null
)
599 if (clasp
->flags
& JSCLASS_IS_ANONYMOUS
)
600 return JSProto_Object
;
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. */
610 JSProtoKey protoKey
= GetClassProtoKey(clasp
);
611 if (!js_GetClassPrototype(cx
, parent
, protoKey
, &proto
, clasp
))
614 !js_GetClassPrototype(cx
, parent
, JSProto_Object
, &proto
)) {
619 return NewObjectWithGivenProto(cx
, clasp
, proto
, parent
, objectSize
);
624 #endif /* jsobjinlines_h___ */