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___
51 #include "jspropertytree.h"
53 #include "jsstaticcheck.h"
56 /* Headers included for inline implementations used by this header. */
60 #include "jsscopeinlines.h"
63 #include "jsgcinlines.h"
67 JSObject::preventExtensions(JSContext
*cx
, js::AutoIdVector
*props
)
69 JS_ASSERT(isExtensible());
71 if (js::FixOp fix
= getOps()->fix
) {
73 if (!fix(cx
, this, &success
, props
))
76 JS_ReportErrorNumber(cx
, js_GetErrorMessage
, NULL
, JSMSG_CANT_CHANGE_EXTENSIBILITY
);
80 if (!GetPropertyNames(cx
, this, JSITER_HIDDEN
| JSITER_OWNONLY
, props
))
85 extensibleShapeChange(cx
);
87 flags
|= NOT_EXTENSIBLE
;
92 JSObject::brand(JSContext
*cx
)
94 JS_ASSERT(!generic());
95 JS_ASSERT(!branded());
96 JS_ASSERT(isNative());
98 if (js_IsPropertyCacheDisabled(cx
)) // check for rt->shapeGen overflow
105 JSObject::unbrand(JSContext
*cx
)
107 JS_ASSERT(isNative());
109 generateOwnShape(cx
);
110 if (js_IsPropertyCacheDisabled(cx
)) // check for rt->shapeGen overflow
119 JSObject::syncSpecialEquality()
121 if (clasp
->ext
.equality
)
122 flags
|= JSObject::HAS_EQUALITY
;
126 JSObject::finalize(JSContext
*cx
)
128 /* Cope with stillborn objects that have no map. */
132 /* Finalize obj first, in case it needs map and slots. */
133 js::Class
*clasp
= getClass();
135 clasp
->finalize(cx
, this);
137 js::Probes::finalizeObject(this);
143 * Property read barrier for deferred cloning of compiler-created function
144 * objects optimized as typically non-escaping, ad-hoc methods in obj.
146 inline const js::Shape
*
147 JSObject::methodReadBarrier(JSContext
*cx
, const js::Shape
&shape
, js::Value
*vp
)
149 JS_ASSERT(canHaveMethodBarrier());
150 JS_ASSERT(hasMethodBarrier());
151 JS_ASSERT(nativeContains(shape
));
152 JS_ASSERT(shape
.isMethod());
153 JS_ASSERT(&shape
.methodObject() == &vp
->toObject());
154 JS_ASSERT(shape
.writable());
155 JS_ASSERT(shape
.slot
!= SHAPE_INVALID_SLOT
);
156 JS_ASSERT(shape
.hasDefaultSetter() || shape
.setterOp() == js_watch_set
);
157 JS_ASSERT(!isGlobal()); /* i.e. we are not changing the global shape */
159 JSObject
*funobj
= &vp
->toObject();
160 JSFunction
*fun
= funobj
->getFunctionPrivate();
161 JS_ASSERT(fun
== funobj
);
162 JS_ASSERT(FUN_NULL_CLOSURE(fun
));
164 funobj
= CloneFunctionObject(cx
, fun
, funobj
->getParent());
167 funobj
->setMethodObj(*this);
170 * Replace the method property with an ordinary data property. This is
171 * equivalent to this->setProperty(cx, shape.id, vp) except that any
172 * watchpoint on the property is not triggered.
174 uint32 slot
= shape
.slot
;
175 const js::Shape
*newshape
= methodShapeChange(cx
, shape
);
178 JS_ASSERT(!newshape
->isMethod());
179 JS_ASSERT(newshape
->slot
== slot
);
180 vp
->setObject(*funobj
);
181 nativeSetSlot(slot
, *vp
);
184 if (cx
->runtime
->functionMeterFilename
) {
185 JS_FUNCTION_METER(cx
, mreadbarrier
);
187 typedef JSRuntime::FunctionCountMap HM
;
188 HM
&h
= cx
->runtime
->methodReadBarrierCountMap
;
189 HM::AddPtr p
= h
.lookupForAdd(fun
);
193 JS_ASSERT(p
->key
== fun
);
201 static JS_ALWAYS_INLINE
bool
202 ChangesMethodValue(const js::Value
&prev
, const js::Value
&v
)
205 return prev
.isObject() && (prevObj
= &prev
.toObject())->isFunction() &&
206 (!v
.isObject() || &v
.toObject() != prevObj
);
209 inline const js::Shape
*
210 JSObject::methodWriteBarrier(JSContext
*cx
, const js::Shape
&shape
, const js::Value
&v
)
212 if (brandedOrHasMethodBarrier() && shape
.slot
!= SHAPE_INVALID_SLOT
) {
213 const js::Value
&prev
= nativeGetSlot(shape
.slot
);
215 if (ChangesMethodValue(prev
, v
)) {
216 JS_FUNCTION_METER(cx
, mwritebarrier
);
217 return methodShapeChange(cx
, shape
);
224 JSObject::methodWriteBarrier(JSContext
*cx
, uint32 slot
, const js::Value
&v
)
226 if (brandedOrHasMethodBarrier()) {
227 const js::Value
&prev
= nativeGetSlot(slot
);
229 if (ChangesMethodValue(prev
, v
)) {
230 JS_FUNCTION_METER(cx
, mwslotbarrier
);
231 return methodShapeChange(cx
, slot
);
238 JSObject::ensureClassReservedSlots(JSContext
*cx
)
240 return !nativeEmpty() || ensureClassReservedSlotsForEmptyObject(cx
);
244 JSObject::getReservedSlot(uintN index
) const
246 return (index
< numSlots()) ? getSlot(index
) : js::UndefinedValue();
250 JSObject::canHaveMethodBarrier() const
252 return isObject() || isFunction() || isPrimitive() || isDate();
256 JSObject::isPrimitive() const
258 return isNumber() || isString() || isBoolean();
261 inline const js::Value
&
262 JSObject::getPrimitiveThis() const
264 JS_ASSERT(isPrimitive());
265 return getSlot(JSSLOT_PRIMITIVE_THIS
);
269 JSObject::setPrimitiveThis(const js::Value
&pthis
)
271 JS_ASSERT(isPrimitive());
272 setSlot(JSSLOT_PRIMITIVE_THIS
, pthis
);
275 inline /* gc::FinalizeKind */ unsigned
276 JSObject::finalizeKind() const
278 return js::gc::FinalizeKind(arena()->header()->thingKind
);
282 JSObject::numFixedSlots() const
285 return JSObject::FUN_CLASS_RESERVED_SLOTS
;
286 if (!hasSlotsArray())
288 return js::gc::GetGCKindSlots(js::gc::FinalizeKind(finalizeKind()));
292 JSObject::slotsAndStructSize(uint32 nslots
) const
294 bool isFun
= isFunction() && this == (JSObject
*) getPrivate();
296 int ndslots
= hasSlotsArray() ? nslots
: 0;
297 int nfslots
= isFun
? 0 : numFixedSlots();
299 return sizeof(js::Value
) * (ndslots
+ nfslots
)
300 + isFun
? sizeof(JSFunction
) : sizeof(JSObject
);
304 JSObject::getArrayLength() const
306 JS_ASSERT(isArray());
307 return (uint32
)(size_t) getPrivate();
311 JSObject::setArrayLength(uint32 length
)
313 JS_ASSERT(isArray());
314 setPrivate((void*) length
);
318 JSObject::getDenseArrayCapacity()
320 JS_ASSERT(isDenseArray());
325 JSObject::getDenseArrayElements()
327 JS_ASSERT(isDenseArray());
331 inline const js::Value
&
332 JSObject::getDenseArrayElement(uintN idx
)
334 JS_ASSERT(isDenseArray());
339 JSObject::addressOfDenseArrayElement(uintN idx
)
341 JS_ASSERT(isDenseArray());
342 return &getSlotRef(idx
);
346 JSObject::setDenseArrayElement(uintN idx
, const js::Value
&val
)
348 JS_ASSERT(isDenseArray());
353 JSObject::shrinkDenseArrayElements(JSContext
*cx
, uintN cap
)
355 JS_ASSERT(isDenseArray());
356 shrinkSlots(cx
, cap
);
360 JSObject::setArgsLength(uint32 argc
)
362 JS_ASSERT(isArguments());
363 JS_ASSERT(argc
<= JS_ARGS_LENGTH_MAX
);
364 JS_ASSERT(UINT32_MAX
> (uint64(argc
) << ARGS_PACKED_BITS_COUNT
));
365 getSlotRef(JSSLOT_ARGS_LENGTH
).setInt32(argc
<< ARGS_PACKED_BITS_COUNT
);
366 JS_ASSERT(!isArgsLengthOverridden());
370 JSObject::getArgsInitialLength() const
372 JS_ASSERT(isArguments());
373 uint32 argc
= uint32(getSlot(JSSLOT_ARGS_LENGTH
).toInt32()) >> ARGS_PACKED_BITS_COUNT
;
374 JS_ASSERT(argc
<= JS_ARGS_LENGTH_MAX
);
379 JSObject::setArgsLengthOverridden()
381 JS_ASSERT(isArguments());
382 getSlotRef(JSSLOT_ARGS_LENGTH
).getInt32Ref() |= ARGS_LENGTH_OVERRIDDEN_BIT
;
386 JSObject::isArgsLengthOverridden() const
388 JS_ASSERT(isArguments());
389 const js::Value
&v
= getSlot(JSSLOT_ARGS_LENGTH
);
390 return v
.toInt32() & ARGS_LENGTH_OVERRIDDEN_BIT
;
393 inline js::ArgumentsData
*
394 JSObject::getArgsData() const
396 JS_ASSERT(isArguments());
397 return (js::ArgumentsData
*) getSlot(JSSLOT_ARGS_DATA
).toPrivate();
401 JSObject::setArgsData(js::ArgumentsData
*data
)
403 JS_ASSERT(isArguments());
404 getSlotRef(JSSLOT_ARGS_DATA
).setPrivate(data
);
407 inline const js::Value
&
408 JSObject::getArgsCallee() const
410 return getArgsData()->callee
;
414 JSObject::setArgsCallee(const js::Value
&callee
)
416 getArgsData()->callee
= callee
;
419 inline const js::Value
&
420 JSObject::getArgsElement(uint32 i
) const
422 JS_ASSERT(isArguments());
423 JS_ASSERT(i
< getArgsInitialLength());
424 return getArgsData()->slots
[i
];
428 JSObject::getArgsElements() const
430 JS_ASSERT(isArguments());
431 return getArgsData()->slots
;
435 JSObject::addressOfArgsElement(uint32 i
)
437 JS_ASSERT(isArguments());
438 JS_ASSERT(i
< getArgsInitialLength());
439 return &getArgsData()->slots
[i
];
443 JSObject::setArgsElement(uint32 i
, const js::Value
&v
)
445 JS_ASSERT(isArguments());
446 JS_ASSERT(i
< getArgsInitialLength());
447 getArgsData()->slots
[i
] = v
;
451 JSObject::callIsForEval() const
454 JS_ASSERT(getSlot(JSSLOT_CALL_CALLEE
).isObjectOrNull());
455 JS_ASSERT_IF(getSlot(JSSLOT_CALL_CALLEE
).isObject(),
456 getSlot(JSSLOT_CALL_CALLEE
).toObject().isFunction());
457 return getSlot(JSSLOT_CALL_CALLEE
).isNull();
460 inline JSStackFrame
*
461 JSObject::maybeCallObjStackFrame() const
464 return reinterpret_cast<JSStackFrame
*>(getPrivate());
468 JSObject::setCallObjCallee(JSObject
*callee
)
471 JS_ASSERT_IF(callee
, callee
->isFunction());
472 return getSlotRef(JSSLOT_CALL_CALLEE
).setObjectOrNull(callee
);
476 JSObject::getCallObjCallee() const
479 return getSlot(JSSLOT_CALL_CALLEE
).toObjectOrNull();
483 JSObject::getCallObjCalleeFunction() const
486 return getSlot(JSSLOT_CALL_CALLEE
).toObject().getFunctionPrivate();
489 inline const js::Value
&
490 JSObject::getCallObjArguments() const
493 JS_ASSERT(!callIsForEval());
494 return getSlot(JSSLOT_CALL_ARGUMENTS
);
498 JSObject::setCallObjArguments(const js::Value
&v
)
501 JS_ASSERT(!callIsForEval());
502 setSlot(JSSLOT_CALL_ARGUMENTS
, v
);
505 inline const js::Value
&
506 JSObject::callObjArg(uintN i
) const
509 JS_ASSERT(i
< getCallObjCalleeFunction()->nargs
);
510 return getSlot(JSObject::CALL_RESERVED_SLOTS
+ i
);
514 JSObject::callObjArg(uintN i
)
517 JS_ASSERT(i
< getCallObjCalleeFunction()->nargs
);
518 return getSlotRef(JSObject::CALL_RESERVED_SLOTS
+ i
);
521 inline const js::Value
&
522 JSObject::callObjVar(uintN i
) const
524 JSFunction
*fun
= getCallObjCalleeFunction();
525 JS_ASSERT(fun
->nargs
== fun
->script()->bindings
.countArgs());
526 JS_ASSERT(i
< fun
->script()->bindings
.countVars());
527 return getSlot(JSObject::CALL_RESERVED_SLOTS
+ fun
->nargs
+ i
);
531 JSObject::callObjVar(uintN i
)
533 JSFunction
*fun
= getCallObjCalleeFunction();
534 JS_ASSERT(fun
->nargs
== fun
->script()->bindings
.countArgs());
535 JS_ASSERT(i
< fun
->script()->bindings
.countVars());
536 return getSlotRef(JSObject::CALL_RESERVED_SLOTS
+ fun
->nargs
+ i
);
539 inline const js::Value
&
540 JSObject::getDateUTCTime() const
543 return getSlot(JSSLOT_DATE_UTC_TIME
);
547 JSObject::setDateUTCTime(const js::Value
&time
)
550 setSlot(JSSLOT_DATE_UTC_TIME
, time
);
554 JSObject::getFlatClosureUpvars() const
557 JSFunction
*fun
= getFunctionPrivate();
558 JS_ASSERT(fun
->isFlatClosure());
559 JS_ASSERT(fun
->script()->bindings
.countUpvars() == fun
->script()->upvars()->length
);
561 return (js::Value
*) getSlot(JSSLOT_FLAT_CLOSURE_UPVARS
).toPrivate();
565 JSObject::getFlatClosureUpvar(uint32 i
) const
567 JS_ASSERT(i
< getFunctionPrivate()->script()->bindings
.countUpvars());
568 return getFlatClosureUpvars()[i
];
572 JSObject::getFlatClosureUpvar(uint32 i
)
574 JS_ASSERT(i
< getFunctionPrivate()->script()->bindings
.countUpvars());
575 return getFlatClosureUpvars()[i
];
579 JSObject::setFlatClosureUpvars(js::Value
*upvars
)
581 JS_ASSERT(isFunction());
582 JS_ASSERT(FUN_FLAT_CLOSURE(getFunctionPrivate()));
583 getSlotRef(JSSLOT_FLAT_CLOSURE_UPVARS
).setPrivate(upvars
);
587 JSObject::hasMethodObj(const JSObject
& obj
) const
589 return JSSLOT_FUN_METHOD_OBJ
< numSlots() &&
590 getSlot(JSSLOT_FUN_METHOD_OBJ
).isObject() &&
591 &getSlot(JSSLOT_FUN_METHOD_OBJ
).toObject() == &obj
;
595 JSObject::setMethodObj(JSObject
& obj
)
597 getSlotRef(JSSLOT_FUN_METHOD_OBJ
).setObject(obj
);
600 inline js::NativeIterator
*
601 JSObject::getNativeIterator() const
603 return (js::NativeIterator
*) getPrivate();
607 JSObject::setNativeIterator(js::NativeIterator
*ni
)
612 inline JSLinearString
*
613 JSObject::getNamePrefix() const
615 JS_ASSERT(isNamespace() || isQName());
616 const js::Value
&v
= getSlot(JSSLOT_NAME_PREFIX
);
617 return !v
.isUndefined() ? v
.toString()->assertIsLinear() : NULL
;
621 JSObject::getNamePrefixVal() const
623 JS_ASSERT(isNamespace() || isQName());
624 return js::Jsvalify(getSlot(JSSLOT_NAME_PREFIX
));
628 JSObject::setNamePrefix(JSLinearString
*prefix
)
630 JS_ASSERT(isNamespace() || isQName());
631 setSlot(JSSLOT_NAME_PREFIX
, prefix
? js::StringValue(prefix
) : js::UndefinedValue());
635 JSObject::clearNamePrefix()
637 JS_ASSERT(isNamespace() || isQName());
638 setSlot(JSSLOT_NAME_PREFIX
, js::UndefinedValue());
641 inline JSLinearString
*
642 JSObject::getNameURI() const
644 JS_ASSERT(isNamespace() || isQName());
645 const js::Value
&v
= getSlot(JSSLOT_NAME_URI
);
646 return !v
.isUndefined() ? v
.toString()->assertIsLinear() : NULL
;
650 JSObject::getNameURIVal() const
652 JS_ASSERT(isNamespace() || isQName());
653 return js::Jsvalify(getSlot(JSSLOT_NAME_URI
));
657 JSObject::setNameURI(JSLinearString
*uri
)
659 JS_ASSERT(isNamespace() || isQName());
660 setSlot(JSSLOT_NAME_URI
, uri
? js::StringValue(uri
) : js::UndefinedValue());
664 JSObject::getNamespaceDeclared() const
666 JS_ASSERT(isNamespace());
667 return js::Jsvalify(getSlot(JSSLOT_NAMESPACE_DECLARED
));
671 JSObject::setNamespaceDeclared(jsval decl
)
673 JS_ASSERT(isNamespace());
674 setSlot(JSSLOT_NAMESPACE_DECLARED
, js::Valueify(decl
));
677 inline JSLinearString
*
678 JSObject::getQNameLocalName() const
680 JS_ASSERT(isQName());
681 const js::Value
&v
= getSlot(JSSLOT_QNAME_LOCAL_NAME
);
682 return !v
.isUndefined() ? v
.toString()->assertIsLinear() : NULL
;
686 JSObject::getQNameLocalNameVal() const
688 JS_ASSERT(isQName());
689 return js::Jsvalify(getSlot(JSSLOT_QNAME_LOCAL_NAME
));
693 JSObject::setQNameLocalName(JSLinearString
*name
)
695 JS_ASSERT(isQName());
696 setSlot(JSSLOT_QNAME_LOCAL_NAME
, name
? js::StringValue(name
) : js::UndefinedValue());
700 JSObject::getWithThis() const
702 return &getSlot(JSSLOT_WITH_THIS
).toObject();
706 JSObject::setWithThis(JSObject
*thisp
)
708 getSlotRef(JSSLOT_WITH_THIS
).setObject(*thisp
);
712 JSObject::init(JSContext
*cx
, js::Class
*aclasp
, JSObject
*proto
, JSObject
*parent
,
713 void *priv
, bool useHoles
)
720 * NB: objShape must not be set here; rather, the caller must call setMap
721 * or setSharedNonNativeMap after calling init. To defend this requirement
722 * we set map to null in DEBUG builds, and set objShape to a value we then
723 * assert obj->shape() never returns.
726 objShape
= JSObjectMap::INVALID_SHAPE
;
733 slots
= fixedSlots();
736 * Fill the fixed slots with undefined or array holes. This object must
737 * already have its capacity filled in, as by js_NewGCObject.
739 JS_ASSERT(capacity
== numFixedSlots());
740 ClearValueRange(slots
, capacity
, useHoles
);
746 JSObject::finish(JSContext
*cx
)
750 JS_LOCK_RUNTIME_VOID(cx
->runtime
, cx
->runtime
->liveObjectProps
-= propertyCount());
755 cx
->free(emptyShapes
);
759 JSObject::initSharingEmptyShape(JSContext
*cx
,
764 /* js::gc::FinalizeKind */ unsigned kind
)
766 init(cx
, aclasp
, proto
, parent
, privateValue
, false);
768 JS_ASSERT(!isDenseArray());
770 js::EmptyShape
*empty
= proto
->getEmptyShape(cx
, aclasp
, kind
);
779 JSObject::freeSlotsArray(JSContext
*cx
)
781 JS_ASSERT(hasSlotsArray());
786 JSObject::revertToFixedSlots(JSContext
*cx
)
788 JS_ASSERT(hasSlotsArray());
789 size_t fixed
= numFixedSlots();
790 JS_ASSERT(capacity
>= fixed
);
791 memcpy(fixedSlots(), slots
, fixed
* sizeof(js::Value
));
793 slots
= fixedSlots();
798 JSObject::hasProperty(JSContext
*cx
, jsid id
, bool *foundp
, uintN flags
)
802 JSAutoResolveFlags
rf(cx
, flags
);
803 if (!lookupProperty(cx
, id
, &pobj
, &prop
))
810 JSObject::isCallable()
812 return isFunction() || getClass()->call
;
816 js_IsCallable(const js::Value
&v
)
818 return v
.isObject() && v
.toObject().isCallable();
823 class AutoPropDescArrayRooter
: private AutoGCRooter
826 AutoPropDescArrayRooter(JSContext
*cx
)
827 : AutoGCRooter(cx
, DESCRIPTORS
), descriptors(cx
)
831 if (!descriptors
.append(PropDesc()))
833 return &descriptors
.back();
836 PropDesc
& operator[](size_t i
) {
837 JS_ASSERT(i
< descriptors
.length());
838 return descriptors
[i
];
841 friend void AutoGCRooter::trace(JSTracer
*trc
);
844 PropDescArray descriptors
;
847 class AutoPropertyDescriptorRooter
: private AutoGCRooter
, public PropertyDescriptor
850 AutoPropertyDescriptorRooter(JSContext
*cx
) : AutoGCRooter(cx
, DESCRIPTOR
) {
853 getter
= (PropertyOp
) NULL
;
854 setter
= (StrictPropertyOp
) NULL
;
855 value
.setUndefined();
858 AutoPropertyDescriptorRooter(JSContext
*cx
, PropertyDescriptor
*desc
)
859 : AutoGCRooter(cx
, DESCRIPTOR
)
863 getter
= desc
->getter
;
864 setter
= desc
->setter
;
868 friend void AutoGCRooter::trace(JSTracer
*trc
);
872 InitScopeForObject(JSContext
* cx
, JSObject
* obj
, js::Class
*clasp
, JSObject
* proto
,
873 gc::FinalizeKind kind
)
875 JS_ASSERT(clasp
->isNative());
876 JS_ASSERT(proto
== obj
->getProto());
878 /* Share proto's emptyShape only if obj is similar to proto. */
879 js::EmptyShape
*empty
= NULL
;
882 if (proto
->canProvideEmptyShape(clasp
)) {
883 empty
= proto
->getEmptyShape(cx
, clasp
, kind
);
890 empty
= js::EmptyShape::create(cx
, clasp
);
893 uint32 freeslot
= JSSLOT_FREE(clasp
);
894 if (freeslot
> obj
->numSlots() && !obj
->allocSlots(cx
, freeslot
))
902 /* The GC nulls map initially. It should still be null on error. */
903 JS_ASSERT(!obj
->map
);
908 * Helper optimized for creating a native instance of the given class (not the
909 * class's prototype object). Use this in preference to NewObject, but use
910 * NewBuiltinClassInstance if you need the default class prototype as proto,
911 * and its parent global as parent.
913 static inline JSObject
*
914 NewNativeClassInstance(JSContext
*cx
, Class
*clasp
, JSObject
*proto
,
915 JSObject
*parent
, gc::FinalizeKind kind
)
918 JS_ASSERT(proto
->isNative());
922 * Allocate an object from the GC heap and initialize all its fields before
923 * doing any operation that can potentially trigger GC.
925 JSObject
* obj
= js_NewGCObject(cx
, kind
);
929 * Default parent to the parent of the prototype, which was set from
930 * the parent of the prototype's constructor.
932 bool useHoles
= (clasp
== &js_ArrayClass
);
933 obj
->init(cx
, clasp
, proto
, parent
, NULL
, useHoles
);
935 JS_ASSERT(proto
->canProvideEmptyShape(clasp
));
936 js::EmptyShape
*empty
= proto
->getEmptyShape(cx
, clasp
, kind
);
947 static inline JSObject
*
948 NewNativeClassInstance(JSContext
*cx
, Class
*clasp
, JSObject
*proto
, JSObject
*parent
)
950 gc::FinalizeKind kind
= gc::GetGCObjectKind(JSCLASS_RESERVED_SLOTS(clasp
));
951 return NewNativeClassInstance(cx
, clasp
, proto
, parent
, kind
);
955 FindClassPrototype(JSContext
*cx
, JSObject
*scope
, JSProtoKey protoKey
, JSObject
**protop
,
959 * Helper used to create Boolean, Date, RegExp, etc. instances of built-in
960 * classes with class prototypes of the same Class. See, e.g., jsdate.cpp,
961 * jsregexp.cpp, and js_PrimitiveToObject in jsobj.cpp. Use this to get the
962 * right default proto and parent for clasp in cx.
964 static inline JSObject
*
965 NewBuiltinClassInstance(JSContext
*cx
, Class
*clasp
, gc::FinalizeKind kind
)
967 VOUCH_DOES_NOT_REQUIRE_STACK();
969 JSProtoKey protoKey
= JSCLASS_CACHED_PROTO_KEY(clasp
);
970 JS_ASSERT(protoKey
!= JSProto_Null
);
972 /* NB: inline-expanded and specialized version of js_GetClassPrototype. */
975 global
= cx
->globalObject
;
976 OBJ_TO_INNER_OBJECT(cx
, global
);
980 global
= cx
->fp()->scopeChain().getGlobal();
982 JS_ASSERT(global
->isGlobal());
984 const Value
&v
= global
->getReservedSlot(JSProto_LIMIT
+ protoKey
);
987 proto
= &v
.toObject();
988 JS_ASSERT(proto
->getParent() == global
);
990 if (!FindClassPrototype(cx
, global
, protoKey
, &proto
, clasp
))
994 return NewNativeClassInstance(cx
, clasp
, proto
, global
, kind
);
997 static inline JSObject
*
998 NewBuiltinClassInstance(JSContext
*cx
, Class
*clasp
)
1000 gc::FinalizeKind kind
= gc::GetGCObjectKind(JSCLASS_RESERVED_SLOTS(clasp
));
1001 return NewBuiltinClassInstance(cx
, clasp
, kind
);
1004 static inline JSProtoKey
1005 GetClassProtoKey(js::Class
*clasp
)
1007 JSProtoKey key
= JSCLASS_CACHED_PROTO_KEY(clasp
);
1008 if (key
!= JSProto_Null
)
1010 if (clasp
->flags
& JSCLASS_IS_ANONYMOUS
)
1011 return JSProto_Object
;
1012 return JSProto_Null
;
1015 namespace WithProto
{
1023 * Create an instance of any class, native or not, JSFunction-sized or not.
1025 * If withProto is 'Class':
1027 * for a built-in class:
1028 * use the memoized original value of the class constructor .prototype
1031 * the current value of .prototype
1035 * If parent is null, default it to proto->getParent() if proto is non
1036 * null, else to null.
1038 * If withProto is 'Given':
1039 * We allocate an object with exactly the given proto. A null parent
1040 * defaults to proto->getParent() if proto is non-null (else to null).
1042 * If isFunction is true, return a JSFunction-sized object. If isFunction is
1043 * false, return a normal object.
1045 * Note that as a template, there will be lots of instantiations, which means
1046 * the internals will be specialized based on the template parameters.
1048 static JS_ALWAYS_INLINE
bool
1049 FindProto(JSContext
*cx
, js::Class
*clasp
, JSObject
*parent
, JSObject
** proto
)
1051 JSProtoKey protoKey
= GetClassProtoKey(clasp
);
1052 if (!js_GetClassPrototype(cx
, parent
, protoKey
, proto
, clasp
))
1054 if (!(*proto
) && !js_GetClassPrototype(cx
, parent
, JSProto_Object
, proto
))
1062 template <bool withProto
, bool isFunction
>
1063 static JS_ALWAYS_INLINE JSObject
*
1064 NewObject(JSContext
*cx
, js::Class
*clasp
, JSObject
*proto
, JSObject
*parent
,
1065 gc::FinalizeKind kind
)
1067 /* Bootstrap the ur-object, and make it the default prototype object. */
1068 if (withProto
== WithProto::Class
&& !proto
) {
1069 if (!FindProto(cx
, clasp
, parent
, &proto
))
1074 * Allocate an object from the GC heap and initialize all its fields before
1075 * doing any operation that can potentially trigger GC. Functions have a
1076 * larger non-standard allocation size.
1078 * The should be specialized by the template.
1080 JSObject
* obj
= isFunction
? js_NewGCFunction(cx
) : js_NewGCObject(cx
, kind
);
1084 /* This needs to match up with the size of JSFunction::data_padding. */
1085 JS_ASSERT_IF(isFunction
, kind
== gc::FINALIZE_OBJECT2
);
1088 * Default parent to the parent of the prototype, which was set from
1089 * the parent of the prototype's constructor.
1091 obj
->init(cx
, clasp
, proto
,
1092 (!parent
&& proto
) ? proto
->getParent() : parent
,
1093 NULL
, clasp
== &js_ArrayClass
);
1095 if (clasp
->isNative()) {
1096 if (!InitScopeForObject(cx
, obj
, clasp
, proto
, kind
)) {
1101 obj
->setSharedNonNativeMap();
1105 Probes::createObject(cx
, obj
);
1108 } /* namespace detail */
1110 static JS_ALWAYS_INLINE JSObject
*
1111 NewFunction(JSContext
*cx
, JSObject
*parent
)
1113 return detail::NewObject
<WithProto::Class
, true>(cx
, &js_FunctionClass
, NULL
, parent
,
1114 gc::FINALIZE_OBJECT2
);
1117 template <WithProto::e withProto
>
1118 static JS_ALWAYS_INLINE JSObject
*
1119 NewNonFunction(JSContext
*cx
, js::Class
*clasp
, JSObject
*proto
, JSObject
*parent
,
1120 gc::FinalizeKind kind
)
1122 return detail::NewObject
<withProto
, false>(cx
, clasp
, proto
, parent
, kind
);
1125 template <WithProto::e withProto
>
1126 static JS_ALWAYS_INLINE JSObject
*
1127 NewNonFunction(JSContext
*cx
, js::Class
*clasp
, JSObject
*proto
, JSObject
*parent
)
1129 gc::FinalizeKind kind
= gc::GetGCObjectKind(JSCLASS_RESERVED_SLOTS(clasp
));
1130 return detail::NewObject
<withProto
, false>(cx
, clasp
, proto
, parent
, kind
);
1133 template <WithProto::e withProto
>
1134 static JS_ALWAYS_INLINE JSObject
*
1135 NewObject(JSContext
*cx
, js::Class
*clasp
, JSObject
*proto
, JSObject
*parent
,
1136 gc::FinalizeKind kind
)
1138 if (clasp
== &js_FunctionClass
)
1139 return detail::NewObject
<withProto
, true>(cx
, clasp
, proto
, parent
, kind
);
1140 return detail::NewObject
<withProto
, false>(cx
, clasp
, proto
, parent
, kind
);
1143 template <WithProto::e withProto
>
1144 static JS_ALWAYS_INLINE JSObject
*
1145 NewObject(JSContext
*cx
, js::Class
*clasp
, JSObject
*proto
, JSObject
*parent
)
1147 gc::FinalizeKind kind
= gc::GetGCObjectKind(JSCLASS_RESERVED_SLOTS(clasp
));
1148 return NewObject
<withProto
>(cx
, clasp
, proto
, parent
, kind
);
1152 * As for gc::GetGCObjectKind, where numSlots is a guess at the final size of
1153 * the object, zero if the final size is unknown.
1155 static inline gc::FinalizeKind
1156 GuessObjectGCKind(size_t numSlots
, bool isArray
)
1159 return gc::GetGCObjectKind(numSlots
);
1160 return isArray
? gc::FINALIZE_OBJECT8
: gc::FINALIZE_OBJECT4
;
1164 * Get the GC kind to use for scripted 'new' on the given class.
1165 * FIXME bug 547327: estimate the size from the allocation site.
1167 static inline gc::FinalizeKind
1168 NewObjectGCKind(JSContext
*cx
, js::Class
*clasp
)
1170 if (clasp
== &js_ArrayClass
|| clasp
== &js_SlowArrayClass
)
1171 return gc::FINALIZE_OBJECT8
;
1172 if (clasp
== &js_FunctionClass
)
1173 return gc::FINALIZE_OBJECT2
;
1174 return gc::FINALIZE_OBJECT4
;
1177 /* Make an object with pregenerated shape from a NEWOBJECT bytecode. */
1178 static inline JSObject
*
1179 CopyInitializerObject(JSContext
*cx
, JSObject
*baseobj
)
1181 JS_ASSERT(baseobj
->getClass() == &js_ObjectClass
);
1182 JS_ASSERT(!baseobj
->inDictionaryMode());
1184 gc::FinalizeKind kind
= gc::FinalizeKind(baseobj
->finalizeKind());
1185 JSObject
*obj
= NewBuiltinClassInstance(cx
, &js_ObjectClass
, kind
);
1187 if (!obj
|| !obj
->ensureSlots(cx
, baseobj
->numSlots()))
1190 obj
->flags
= baseobj
->flags
;
1191 obj
->lastProp
= baseobj
->lastProp
;
1192 obj
->objShape
= baseobj
->objShape
;
1198 * When we have an object of a builtin class, we don't quite know what its
1199 * valueOf/toString methods are, since these methods may have been overwritten
1200 * or shadowed. However, we can still do better than js_TryMethod by
1201 * hard-coding the necessary properties for us to find the native we expect.
1203 * TODO: a per-thread shape-based cache would be faster and simpler.
1205 static JS_ALWAYS_INLINE
bool
1206 ClassMethodIsNative(JSContext
*cx
, JSObject
*obj
, Class
*clasp
, jsid methodid
,
1209 JS_ASSERT(obj
->getClass() == clasp
);
1211 if (HasNativeMethod(obj
, methodid
, native
))
1214 JSObject
*pobj
= obj
->getProto();
1215 return pobj
&& pobj
->getClass() == clasp
&&
1216 HasNativeMethod(pobj
, methodid
, native
);
1219 } /* namespace js */
1221 #endif /* jsobjinlines_h___ */