1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
2 * vim: set ts=8 sts=4 et sw=4 tw=99:
3 * This Source Code Form is subject to the terms of the Mozilla Public
4 * License, v. 2.0. If a copy of the MPL was not distributed with this
5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
8 * JS object implementation.
11 #include "jsobjinlines.h"
13 #include "mozilla/ArrayUtils.h"
14 #include "mozilla/CheckedInt.h"
15 #include "mozilla/MathAlgorithms.h"
16 #include "mozilla/MemoryReporting.h"
17 #include "mozilla/TemplateLib.h"
25 #include "jsfriendapi.h"
37 #include "jswatchpoint.h"
38 #include "jswrapper.h"
40 #include "asmjs/AsmJSModule.h"
41 #include "builtin/Eval.h"
42 #include "builtin/Object.h"
43 #include "builtin/SymbolObject.h"
44 #include "frontend/BytecodeCompiler.h"
45 #include "gc/Marking.h"
46 #include "jit/BaselineJIT.h"
47 #include "js/MemoryMetrics.h"
48 #include "js/OldDebugAPI.h"
49 #include "vm/ArgumentsObject.h"
50 #include "vm/Interpreter.h"
51 #include "vm/ProxyObject.h"
52 #include "vm/RegExpStaticsObject.h"
55 #include "jsatominlines.h"
56 #include "jsboolinlines.h"
57 #include "jscntxtinlines.h"
58 #include "jscompartmentinlines.h"
60 #include "vm/ArrayObject-inl.h"
61 #include "vm/BooleanObject-inl.h"
62 #include "vm/NumberObject-inl.h"
63 #include "vm/ObjectImpl-inl.h"
64 #include "vm/Runtime-inl.h"
65 #include "vm/Shape-inl.h"
66 #include "vm/StringObject-inl.h"
69 using namespace js::gc
;
70 using namespace js::types
;
73 using mozilla::RoundUpPow2
;
75 JS_STATIC_ASSERT(int32_t((JSObject::NELEMENTS_LIMIT
- 1) * sizeof(Value
)) == int64_t((JSObject::NELEMENTS_LIMIT
- 1) * sizeof(Value
)));
78 CreateObjectConstructor(JSContext
*cx
, JSProtoKey key
)
80 Rooted
<GlobalObject
*> self(cx
, cx
->global());
81 if (!GlobalObject::ensureConstructor(cx
, self
, JSProto_Function
))
84 RootedObject
functionProto(cx
, &self
->getPrototype(JSProto_Function
).toObject());
86 /* Create the Object function now that we have a [[Prototype]] for it. */
87 RootedObject
ctor(cx
, NewObjectWithGivenProto(cx
, &JSFunction::class_
, functionProto
,
88 self
, SingletonObject
));
91 return NewFunction(cx
, ctor
, obj_construct
, 1, JSFunction::NATIVE_CTOR
, self
,
92 HandlePropertyName(cx
->names().Object
));
96 CreateObjectPrototype(JSContext
*cx
, JSProtoKey key
)
98 Rooted
<GlobalObject
*> self(cx
, cx
->global());
100 JS_ASSERT(!cx
->runtime()->isAtomsCompartment(cx
->compartment()));
101 JS_ASSERT(self
->isNative());
104 * Create |Object.prototype| first, mirroring CreateBlankProto but for the
105 * prototype of the created object.
107 RootedObject
objectProto(cx
, NewObjectWithGivenProto(cx
, &JSObject::class_
, nullptr,
108 self
, SingletonObject
));
113 * The default 'new' type of Object.prototype is required by type inference
114 * to have unknown properties, to simplify handling of e.g. heterogenous
115 * objects in JSON and script literals.
117 if (!JSObject::setNewTypeUnknown(cx
, &JSObject::class_
, objectProto
))
124 FinishObjectClassInit(JSContext
*cx
, JS::HandleObject ctor
, JS::HandleObject proto
)
126 Rooted
<GlobalObject
*> self(cx
, cx
->global());
129 RootedId
evalId(cx
, NameToId(cx
->names().eval
));
130 JSObject
*evalobj
= DefineFunction(cx
, self
, evalId
, IndirectEval
, 1, JSFUN_STUB_GSOPS
);
133 self
->setOriginalEval(evalobj
);
135 RootedObject
intrinsicsHolder(cx
);
136 if (cx
->runtime()->isSelfHostingGlobal(self
)) {
137 intrinsicsHolder
= self
;
139 intrinsicsHolder
= NewObjectWithGivenProto(cx
, &JSObject::class_
, proto
, self
,
141 if (!intrinsicsHolder
)
144 self
->setIntrinsicsHolder(intrinsicsHolder
);
145 /* Define a property 'global' with the current global as its value. */
146 RootedValue
global(cx
, ObjectValue(*self
));
147 if (!JSObject::defineProperty(cx
, intrinsicsHolder
, cx
->names().global
,
148 global
, JS_PropertyStub
, JS_StrictPropertyStub
,
149 JSPROP_PERMANENT
| JSPROP_READONLY
))
155 * Define self-hosted functions after setting the intrinsics holder
156 * (which is needed to define self-hosted functions)
158 if (!JS_DefineFunctions(cx
, ctor
, object_static_selfhosted_methods
))
162 * The global object should have |Object.prototype| as its [[Prototype]].
163 * Eventually we'd like to have standard classes be there from the start,
164 * and thus we would know we were always setting what had previously been a
165 * null [[Prototype]], but right now some code assumes it can set the
166 * [[Prototype]] before standard classes have been initialized. For now,
167 * only set the [[Prototype]] if it hasn't already been set.
169 Rooted
<TaggedProto
> tagged(cx
, TaggedProto(proto
));
170 if (self
->shouldSplicePrototype(cx
) && !self
->splicePrototype(cx
, self
->getClass(), tagged
))
176 const Class
JSObject::class_
= {
178 JSCLASS_HAS_CACHED_PROTO(JSProto_Object
),
179 JS_PropertyStub
, /* addProperty */
180 JS_DeletePropertyStub
, /* delProperty */
181 JS_PropertyStub
, /* getProperty */
182 JS_StrictPropertyStub
, /* setProperty */
186 nullptr, /* finalize */
188 nullptr, /* hasInstance */
189 nullptr, /* construct */
192 CreateObjectConstructor
,
193 CreateObjectPrototype
,
194 object_static_methods
,
197 FinishObjectClassInit
201 const Class
* const js::ObjectClassPtr
= &JSObject::class_
;
203 JS_FRIEND_API(JSObject
*)
204 JS_ObjectToInnerObject(JSContext
*cx
, HandleObject obj
)
207 JS_ReportErrorNumber(cx
, js_GetErrorMessage
, nullptr, JSMSG_INACTIVE
);
210 return GetInnerObject(obj
);
213 JS_FRIEND_API(JSObject
*)
214 JS_ObjectToOuterObject(JSContext
*cx
, HandleObject obj
)
216 assertSameCompartment(cx
, obj
);
217 return GetOuterObject(cx
, obj
);
221 js::NonNullObject(JSContext
*cx
, const Value
&v
)
223 if (v
.isPrimitive()) {
224 JS_ReportErrorNumber(cx
, js_GetErrorMessage
, nullptr, JSMSG_NOT_NONNULL_OBJECT
);
227 return &v
.toObject();
231 js::InformalValueTypeName(const Value
&v
)
234 return v
.toObject().getClass()->name
;
251 js::NewPropertyDescriptorObject(JSContext
*cx
, Handle
<PropertyDescriptor
> desc
,
252 MutableHandleValue vp
)
254 if (!desc
.object()) {
259 Rooted
<PropDesc
> d(cx
);
261 d
.initFromPropertyDescriptor(desc
);
262 RootedObject
descObj(cx
);
263 if (!d
.makeObject(cx
, &descObj
))
265 vp
.setObject(*descObj
);
270 PropDesc::initFromPropertyDescriptor(Handle
<PropertyDescriptor
> desc
)
272 MOZ_ASSERT(isUndefined());
277 isUndefined_
= false;
278 attrs
= uint8_t(desc
.attributes());
279 JS_ASSERT_IF(attrs
& JSPROP_READONLY
, !(attrs
& (JSPROP_GETTER
| JSPROP_SETTER
)));
280 if (desc
.hasGetterOrSetterObject()) {
282 get_
= desc
.hasGetterObject() && desc
.getterObject()
283 ? ObjectValue(*desc
.getterObject())
286 set_
= desc
.hasSetterObject() && desc
.setterObject()
287 ? ObjectValue(*desc
.setterObject())
290 value_
.setUndefined();
291 hasWritable_
= false;
297 hasValue_
= !(desc
.attributes() & JSPROP_IGNORE_VALUE
);
298 value_
= hasValue_
? desc
.value() : UndefinedValue();
299 hasWritable_
= !(desc
.attributes() & JSPROP_IGNORE_READONLY
);
301 hasEnumerable_
= !(desc
.attributes() & JSPROP_IGNORE_ENUMERATE
);
302 hasConfigurable_
= !(desc
.attributes() & JSPROP_IGNORE_PERMANENT
);
306 PropDesc::populatePropertyDescriptor(HandleObject obj
, MutableHandle
<PropertyDescriptor
> desc
) const
309 desc
.object().set(nullptr);
313 desc
.value().set(hasValue() ? value() : UndefinedValue());
314 desc
.setGetter(getter());
315 desc
.setSetter(setter());
317 // Make sure we honor the "has" notions in some way.
318 unsigned attrs
= attributes();
319 if (!hasEnumerable())
320 attrs
|= JSPROP_IGNORE_ENUMERATE
;
322 attrs
|= JSPROP_IGNORE_READONLY
;
323 if (!hasConfigurable())
324 attrs
|= JSPROP_IGNORE_PERMANENT
;
326 attrs
|= JSPROP_IGNORE_VALUE
;
327 desc
.setAttributes(attrs
);
329 desc
.object().set(obj
);
333 PropDesc::makeObject(JSContext
*cx
, MutableHandleObject obj
)
335 MOZ_ASSERT(!isUndefined());
337 obj
.set(NewBuiltinClassInstance(cx
, &JSObject::class_
));
341 const JSAtomState
&names
= cx
->names();
342 RootedValue
configurableVal(cx
, BooleanValue((attrs
& JSPROP_PERMANENT
) == 0));
343 RootedValue
enumerableVal(cx
, BooleanValue((attrs
& JSPROP_ENUMERATE
) != 0));
344 RootedValue
writableVal(cx
, BooleanValue((attrs
& JSPROP_READONLY
) == 0));
345 if ((hasConfigurable() &&
346 !JSObject::defineProperty(cx
, obj
, names
.configurable
, configurableVal
)) ||
348 !JSObject::defineProperty(cx
, obj
, names
.enumerable
, enumerableVal
)) ||
350 !JSObject::defineProperty(cx
, obj
, names
.get
, getterValue())) ||
352 !JSObject::defineProperty(cx
, obj
, names
.set
, setterValue())) ||
354 !JSObject::defineProperty(cx
, obj
, names
.value
, value())) ||
356 !JSObject::defineProperty(cx
, obj
, names
.writable
, writableVal
)))
365 js::GetOwnPropertyDescriptor(JSContext
*cx
, HandleObject obj
, HandleId id
,
366 MutableHandle
<PropertyDescriptor
> desc
)
368 if (obj
->is
<ProxyObject
>())
369 return Proxy::getOwnPropertyDescriptor(cx
, obj
, id
, desc
);
371 RootedObject
pobj(cx
);
372 RootedShape
shape(cx
);
373 if (!HasOwnProperty
<CanGC
>(cx
, obj
->getOps()->lookupGeneric
, obj
, id
, &pobj
, &shape
))
376 desc
.object().set(nullptr);
381 if (pobj
->isNative()) {
382 desc
.setAttributes(GetShapeAttributes(pobj
, shape
));
383 if (desc
.hasGetterOrSetterObject()) {
384 MOZ_ASSERT(desc
.isShared());
386 if (desc
.hasGetterObject())
387 desc
.setGetterObject(shape
->getterObject());
388 if (desc
.hasSetterObject())
389 desc
.setSetterObject(shape
->setterObject());
391 // This is either a straight-up data property or (rarely) a
392 // property with a JSPropertyOp getter/setter. The latter must be
393 // reported to the caller as a plain data property, so don't
394 // populate desc.getter/setter, and mask away the SHARED bit.
395 desc
.attributesRef() &= ~JSPROP_SHARED
;
398 if (!JSObject::getGenericAttributes(cx
, pobj
, id
, &desc
.attributesRef()))
402 RootedValue
value(cx
);
403 if (doGet
&& !JSObject::getGeneric(cx
, obj
, obj
, id
, &value
))
406 desc
.value().set(value
);
407 desc
.object().set(obj
);
412 js::GetOwnPropertyDescriptor(JSContext
*cx
, HandleObject obj
, HandleId id
, MutableHandleValue vp
)
414 Rooted
<PropertyDescriptor
> desc(cx
);
415 return GetOwnPropertyDescriptor(cx
, obj
, id
, &desc
) &&
416 NewPropertyDescriptorObject(cx
, desc
, vp
);
420 js::GetFirstArgumentAsObject(JSContext
*cx
, const CallArgs
&args
, const char *method
,
421 MutableHandleObject objp
)
423 if (args
.length() == 0) {
424 JS_ReportErrorNumber(cx
, js_GetErrorMessage
, nullptr, JSMSG_MORE_ARGS_NEEDED
,
429 HandleValue v
= args
[0];
431 char *bytes
= DecompileValueGenerator(cx
, JSDVG_SEARCH_STACK
, v
, NullPtr());
434 JS_ReportErrorNumber(cx
, js_GetErrorMessage
, nullptr, JSMSG_UNEXPECTED_TYPE
,
435 bytes
, "not an object");
440 objp
.set(&v
.toObject());
445 HasProperty(JSContext
*cx
, HandleObject obj
, HandleId id
, MutableHandleValue vp
, bool *foundp
)
447 if (!JSObject::hasProperty(cx
, obj
, id
, foundp
))
455 * We must go through the method read barrier in case id is 'get' or 'set'.
456 * There is no obvious way to defer cloning a joined function object whose
457 * identity will be used by DefinePropertyOnObject, e.g., or reflected via
458 * js::GetOwnPropertyDescriptor, as the getter or setter callable object.
460 return !!JSObject::getGeneric(cx
, obj
, obj
, id
, vp
);
464 PropDesc::initialize(JSContext
*cx
, const Value
&origval
, bool checkAccessors
)
466 MOZ_ASSERT(isUndefined());
468 RootedValue
v(cx
, origval
);
471 if (v
.isPrimitive()) {
472 JS_ReportErrorNumber(cx
, js_GetErrorMessage
, nullptr, JSMSG_NOT_NONNULL_OBJECT
);
475 RootedObject
desc(cx
, &v
.toObject());
477 isUndefined_
= false;
480 * Start with the proper defaults. XXX shouldn't be necessary when we get
481 * rid of PropDesc::attributes()
483 attrs
= JSPROP_PERMANENT
| JSPROP_READONLY
;
489 id
= NameToId(cx
->names().enumerable
);
490 if (!HasProperty(cx
, desc
, id
, &v
, &found
))
493 hasEnumerable_
= true;
495 attrs
|= JSPROP_ENUMERATE
;
499 id
= NameToId(cx
->names().configurable
);
500 if (!HasProperty(cx
, desc
, id
, &v
, &found
))
503 hasConfigurable_
= true;
505 attrs
&= ~JSPROP_PERMANENT
;
509 id
= NameToId(cx
->names().value
);
510 if (!HasProperty(cx
, desc
, id
, &v
, &found
))
518 id
= NameToId(cx
->names().writable
);
519 if (!HasProperty(cx
, desc
, id
, &v
, &found
))
524 attrs
&= ~JSPROP_READONLY
;
528 id
= NameToId(cx
->names().get
);
529 if (!HasProperty(cx
, desc
, id
, &v
, &found
))
534 attrs
|= JSPROP_GETTER
| JSPROP_SHARED
;
535 attrs
&= ~JSPROP_READONLY
;
536 if (checkAccessors
&& !checkGetter(cx
))
541 id
= NameToId(cx
->names().set
);
542 if (!HasProperty(cx
, desc
, id
, &v
, &found
))
547 attrs
|= JSPROP_SETTER
| JSPROP_SHARED
;
548 attrs
&= ~JSPROP_READONLY
;
549 if (checkAccessors
&& !checkSetter(cx
))
554 if ((hasGet() || hasSet()) && (hasValue() || hasWritable())) {
555 JS_ReportErrorNumber(cx
, js_GetErrorMessage
, nullptr, JSMSG_INVALID_DESCRIPTOR
);
559 JS_ASSERT_IF(attrs
& JSPROP_READONLY
, !(attrs
& (JSPROP_GETTER
| JSPROP_SETTER
)));
567 MOZ_ASSERT(!isUndefined());
569 if (isGenericDescriptor() || isDataDescriptor()) {
572 value_
.setUndefined();
576 attrs
|= JSPROP_READONLY
;
588 if (!hasEnumerable_
) {
589 hasEnumerable_
= true;
590 attrs
&= ~JSPROP_ENUMERATE
;
592 if (!hasConfigurable_
) {
593 hasConfigurable_
= true;
594 attrs
|= JSPROP_PERMANENT
;
599 js::Throw(JSContext
*cx
, jsid id
, unsigned errorNumber
)
601 JS_ASSERT(js_ErrorFormatString
[errorNumber
].argCount
== 1);
603 JSString
*idstr
= IdToString(cx
, id
);
606 JSAutoByteString
bytes(cx
, idstr
);
609 JS_ReportErrorNumber(cx
, js_GetErrorMessage
, nullptr, errorNumber
, bytes
.ptr());
614 js::Throw(JSContext
*cx
, JSObject
*obj
, unsigned errorNumber
)
616 if (js_ErrorFormatString
[errorNumber
].argCount
== 1) {
617 RootedValue
val(cx
, ObjectValue(*obj
));
618 js_ReportValueErrorFlags(cx
, JSREPORT_ERROR
, errorNumber
,
619 JSDVG_IGNORE_STACK
, val
, NullPtr(),
622 JS_ASSERT(js_ErrorFormatString
[errorNumber
].argCount
== 0);
623 JS_ReportErrorNumber(cx
, js_GetErrorMessage
, nullptr, errorNumber
);
629 Reject(JSContext
*cx
, unsigned errorNumber
, bool throwError
, jsid id
, bool *rval
)
632 return Throw(cx
, id
, errorNumber
);
639 Reject(JSContext
*cx
, JSObject
*obj
, unsigned errorNumber
, bool throwError
, bool *rval
)
642 return Throw(cx
, obj
, errorNumber
);
649 Reject(JSContext
*cx
, HandleId id
, unsigned errorNumber
, bool throwError
, bool *rval
)
652 return Throw(cx
, id
, errorNumber
);
659 ApplyAttributes(unsigned attrs
, bool enumerable
, bool writable
, bool configurable
)
662 * Respect the fact that some callers may want to preserve existing attributes as much as
663 * possible, or install defaults otherwise.
665 if (attrs
& JSPROP_IGNORE_ENUMERATE
) {
666 attrs
&= ~JSPROP_IGNORE_ENUMERATE
;
668 attrs
|= JSPROP_ENUMERATE
;
670 attrs
&= ~JSPROP_ENUMERATE
;
672 if (attrs
& JSPROP_IGNORE_READONLY
) {
673 attrs
&= ~JSPROP_IGNORE_READONLY
;
674 // Only update the writability if it's relevant
675 if (!(attrs
& (JSPROP_GETTER
| JSPROP_SETTER
))) {
677 attrs
|= JSPROP_READONLY
;
679 attrs
&= ~JSPROP_READONLY
;
682 if (attrs
& JSPROP_IGNORE_PERMANENT
) {
683 attrs
&= ~JSPROP_IGNORE_PERMANENT
;
685 attrs
|= JSPROP_PERMANENT
;
687 attrs
&= ~JSPROP_PERMANENT
;
693 ApplyOrDefaultAttributes(unsigned attrs
, const Shape
*shape
= nullptr)
695 bool enumerable
= shape
? shape
->enumerable() : false;
696 bool writable
= shape
? shape
->writable() : false;
697 bool configurable
= shape
? shape
->configurable() : false;
698 return ApplyAttributes(attrs
, enumerable
, writable
, configurable
);
702 ApplyOrDefaultAttributes(unsigned attrs
, Handle
<PropertyDescriptor
> desc
)
704 bool present
= !!desc
.object();
705 bool enumerable
= present
? desc
.isEnumerable() : false;
706 bool writable
= present
? !desc
.isReadonly() : false;
707 bool configurable
= present
? !desc
.isPermanent() : false;
708 return ApplyAttributes(attrs
, enumerable
, writable
, configurable
);
711 // See comments on CheckDefineProperty in jsfriendapi.h.
713 // DefinePropertyOnObject has its own implementation of these checks.
716 js::CheckDefineProperty(JSContext
*cx
, HandleObject obj
, HandleId id
, HandleValue value
,
717 unsigned attrs
, PropertyOp getter
, StrictPropertyOp setter
)
719 if (!obj
->isNative())
722 // ES5 8.12.9 Step 1. Even though we know obj is native, we use generic
723 // APIs for shorter, more readable code.
724 Rooted
<PropertyDescriptor
> desc(cx
);
725 if (!GetOwnPropertyDescriptor(cx
, obj
, id
, &desc
))
728 // Appropriately handle the potential for ignored attributes. Since the proxy code calls us
729 // directly, these might flow in legitimately. Ensure that we compare against the values that
731 attrs
= ApplyOrDefaultAttributes(attrs
, desc
) & ~JSPROP_IGNORE_VALUE
;
733 // This does not have to check obj's extensibility when !desc.obj (steps
734 // 2-3) because the low-level methods JSObject::{add,put}Property check
736 if (desc
.object() && desc
.isPermanent()) {
737 // Steps 6-11, skipping step 10.a.ii. Prohibit redefining a permanent
738 // property with different metadata, except to make a writable property
740 if ((getter
!= desc
.getter() && !(getter
== JS_PropertyStub
&& !desc
.getter())) ||
741 (setter
!= desc
.setter() && !(setter
== JS_StrictPropertyStub
&& !desc
.setter())) ||
742 (attrs
!= desc
.attributes() && attrs
!= (desc
.attributes() | JSPROP_READONLY
)))
744 return Throw(cx
, id
, JSMSG_CANT_REDEFINE_PROP
);
747 // Step 10.a.ii. Prohibit changing the value of a non-configurable,
748 // non-writable data property.
749 if ((desc
.attributes() & (JSPROP_GETTER
| JSPROP_SETTER
| JSPROP_READONLY
)) == JSPROP_READONLY
) {
751 if (!SameValue(cx
, value
, desc
.value(), &same
))
754 return JSObject::reportReadOnly(cx
, id
);
761 DefinePropertyOnObject(JSContext
*cx
, HandleObject obj
, HandleId id
, const PropDesc
&desc
,
762 bool throwError
, bool *rval
)
765 RootedShape
shape(cx
);
766 RootedObject
obj2(cx
);
767 JS_ASSERT(!obj
->getOps()->lookupGeneric
);
768 if (!HasOwnProperty
<CanGC
>(cx
, nullptr, obj
, id
, &obj2
, &shape
))
771 JS_ASSERT(!obj
->getOps()->defineProperty
);
773 /* 8.12.9 steps 2-4. */
776 if (!JSObject::isExtensible(cx
, obj
, &extensible
))
779 return Reject(cx
, obj
, JSMSG_OBJECT_NOT_EXTENSIBLE
, throwError
, rval
);
783 if (desc
.isGenericDescriptor() || desc
.isDataDescriptor()) {
784 JS_ASSERT(!obj
->getOps()->defineProperty
);
785 RootedValue
v(cx
, desc
.hasValue() ? desc
.value() : UndefinedValue());
786 return baseops::DefineGeneric(cx
, obj
, id
, v
,
787 JS_PropertyStub
, JS_StrictPropertyStub
,
791 JS_ASSERT(desc
.isAccessorDescriptor());
793 return baseops::DefineGeneric(cx
, obj
, id
, UndefinedHandleValue
,
794 desc
.getter(), desc
.setter(), desc
.attributes());
797 /* 8.12.9 steps 5-6 (note 5 is merely a special case of 6). */
800 JS_ASSERT(obj
== obj2
);
802 bool shapeDataDescriptor
= true,
803 shapeAccessorDescriptor
= false,
804 shapeWritable
= true,
805 shapeConfigurable
= true,
806 shapeEnumerable
= true,
807 shapeHasDefaultGetter
= true,
808 shapeHasDefaultSetter
= true,
809 shapeHasGetterValue
= false,
810 shapeHasSetterValue
= false;
811 uint8_t shapeAttributes
= GetShapeAttributes(obj
, shape
);
812 if (!IsImplicitDenseOrTypedArrayElement(shape
)) {
813 shapeDataDescriptor
= shape
->isDataDescriptor();
814 shapeAccessorDescriptor
= shape
->isAccessorDescriptor();
815 shapeWritable
= shape
->writable();
816 shapeConfigurable
= shape
->configurable();
817 shapeEnumerable
= shape
->enumerable();
818 shapeHasDefaultGetter
= shape
->hasDefaultGetter();
819 shapeHasDefaultSetter
= shape
->hasDefaultSetter();
820 shapeHasGetterValue
= shape
->hasGetterValue();
821 shapeHasSetterValue
= shape
->hasSetterValue();
822 shapeAttributes
= shape
->attributes();
826 if (desc
.isAccessorDescriptor()) {
827 if (!shapeAccessorDescriptor
)
832 if (!SameValue(cx
, desc
.getterValue(), shape
->getterOrUndefined(), &same
))
840 if (!SameValue(cx
, desc
.setterValue(), shape
->setterOrUndefined(), &same
))
847 * Determine the current value of the property once, if the current
848 * value might actually need to be used or preserved later. NB: we
849 * guard on whether the current property is a data descriptor to
850 * avoid calling a getter; we won't need the value if it's not a
853 if (IsImplicitDenseOrTypedArrayElement(shape
)) {
854 v
= obj
->getDenseOrTypedArrayElement(JSID_TO_INT(id
));
855 } else if (shape
->isDataDescriptor()) {
857 * We must rule out a non-configurable js::PropertyOp-guarded
858 * property becoming a writable unguarded data property, since
859 * such a property can have its value changed to one the getter
860 * and setter preclude.
862 * A desc lacking writable but with value is a data descriptor
863 * and we must reject it as if it had writable: true if current
866 if (!shape
->configurable() &&
867 (!shape
->hasDefaultGetter() || !shape
->hasDefaultSetter()) &&
868 desc
.isDataDescriptor() &&
869 (desc
.hasWritable() ? desc
.writable() : shape
->writable()))
871 return Reject(cx
, JSMSG_CANT_REDEFINE_PROP
, throwError
, id
, rval
);
874 if (!NativeGet(cx
, obj
, obj2
, shape
, &v
))
878 if (desc
.isDataDescriptor()) {
879 if (!shapeDataDescriptor
)
883 if (desc
.hasValue()) {
884 if (!SameValue(cx
, desc
.value(), v
, &same
))
888 * Insist that a non-configurable js::PropertyOp data
889 * property is frozen at exactly the last-got value.
891 * Duplicate the first part of the big conjunction that
892 * we tested above, rather than add a local bool flag.
893 * Likewise, don't try to keep shape->writable() in a
894 * flag we veto from true to false for non-configurable
895 * PropertyOp-based data properties and test before the
896 * SameValue check later on in order to re-use that "if
897 * (!SameValue) Reject" logic.
899 * This function is large and complex enough that it
900 * seems best to repeat a small bit of code and return
901 * Reject(...) ASAP, instead of being clever.
903 if (!shapeConfigurable
&&
904 (!shape
->hasDefaultGetter() || !shape
->hasDefaultSetter()))
906 return Reject(cx
, JSMSG_CANT_REDEFINE_PROP
, throwError
, id
, rval
);
911 if (desc
.hasWritable() && desc
.writable() != shapeWritable
)
914 /* The only fields in desc will be handled below. */
915 JS_ASSERT(desc
.isGenericDescriptor());
919 if (desc
.hasConfigurable() && desc
.configurable() != shapeConfigurable
)
921 if (desc
.hasEnumerable() && desc
.enumerable() != shapeEnumerable
)
924 /* The conditions imposed by step 5 or step 6 apply. */
930 if (!shapeConfigurable
) {
931 if ((desc
.hasConfigurable() && desc
.configurable()) ||
932 (desc
.hasEnumerable() && desc
.enumerable() != shape
->enumerable())) {
933 return Reject(cx
, JSMSG_CANT_REDEFINE_PROP
, throwError
, id
, rval
);
937 bool callDelProperty
= false;
939 if (desc
.isGenericDescriptor()) {
940 /* 8.12.9 step 8, no validation required */
941 } else if (desc
.isDataDescriptor() != shapeDataDescriptor
) {
943 if (!shapeConfigurable
)
944 return Reject(cx
, JSMSG_CANT_REDEFINE_PROP
, throwError
, id
, rval
);
945 } else if (desc
.isDataDescriptor()) {
946 /* 8.12.9 step 10. */
947 JS_ASSERT(shapeDataDescriptor
);
948 if (!shapeConfigurable
&& !shape
->writable()) {
949 if (desc
.hasWritable() && desc
.writable())
950 return Reject(cx
, JSMSG_CANT_REDEFINE_PROP
, throwError
, id
, rval
);
951 if (desc
.hasValue()) {
953 if (!SameValue(cx
, desc
.value(), v
, &same
))
956 return Reject(cx
, JSMSG_CANT_REDEFINE_PROP
, throwError
, id
, rval
);
960 callDelProperty
= !shapeHasDefaultGetter
|| !shapeHasDefaultSetter
;
962 /* 8.12.9 step 11. */
963 JS_ASSERT(desc
.isAccessorDescriptor() && shape
->isAccessorDescriptor());
964 if (!shape
->configurable()) {
967 if (!SameValue(cx
, desc
.setterValue(), shape
->setterOrUndefined(), &same
))
970 return Reject(cx
, JSMSG_CANT_REDEFINE_PROP
, throwError
, id
, rval
);
975 if (!SameValue(cx
, desc
.getterValue(), shape
->getterOrUndefined(), &same
))
978 return Reject(cx
, JSMSG_CANT_REDEFINE_PROP
, throwError
, id
, rval
);
983 /* 8.12.9 step 12. */
986 StrictPropertyOp setter
;
987 if (desc
.isGenericDescriptor()) {
988 unsigned changed
= 0;
989 if (desc
.hasConfigurable())
990 changed
|= JSPROP_PERMANENT
;
991 if (desc
.hasEnumerable())
992 changed
|= JSPROP_ENUMERATE
;
994 attrs
= (shapeAttributes
& ~changed
) | (desc
.attributes() & changed
);
995 getter
= IsImplicitDenseOrTypedArrayElement(shape
) ? JS_PropertyStub
: shape
->getter();
996 setter
= IsImplicitDenseOrTypedArrayElement(shape
) ? JS_StrictPropertyStub
: shape
->setter();
997 } else if (desc
.isDataDescriptor()) {
998 unsigned unchanged
= 0;
999 if (!desc
.hasConfigurable())
1000 unchanged
|= JSPROP_PERMANENT
;
1001 if (!desc
.hasEnumerable())
1002 unchanged
|= JSPROP_ENUMERATE
;
1003 /* Watch out for accessor -> data transformations here. */
1004 if (!desc
.hasWritable() && shapeDataDescriptor
)
1005 unchanged
|= JSPROP_READONLY
;
1007 if (desc
.hasValue())
1009 attrs
= (desc
.attributes() & ~unchanged
) | (shapeAttributes
& unchanged
);
1010 getter
= JS_PropertyStub
;
1011 setter
= JS_StrictPropertyStub
;
1013 JS_ASSERT(desc
.isAccessorDescriptor());
1015 /* 8.12.9 step 12. */
1016 unsigned changed
= 0;
1017 if (desc
.hasConfigurable())
1018 changed
|= JSPROP_PERMANENT
;
1019 if (desc
.hasEnumerable())
1020 changed
|= JSPROP_ENUMERATE
;
1022 changed
|= JSPROP_GETTER
| JSPROP_SHARED
| JSPROP_READONLY
;
1024 changed
|= JSPROP_SETTER
| JSPROP_SHARED
| JSPROP_READONLY
;
1026 attrs
= (desc
.attributes() & changed
) | (shapeAttributes
& ~changed
);
1027 if (desc
.hasGet()) {
1028 getter
= desc
.getter();
1030 getter
= (shapeHasDefaultGetter
&& !shapeHasGetterValue
)
1034 if (desc
.hasSet()) {
1035 setter
= desc
.setter();
1037 setter
= (shapeHasDefaultSetter
&& !shapeHasSetterValue
)
1038 ? JS_StrictPropertyStub
1046 * Since "data" properties implemented using native C functions may rely on
1047 * side effects during setting, we must make them aware that they have been
1048 * "assigned"; deleting the property before redefining it does the trick.
1049 * See bug 539766, where we ran into problems when we redefined
1050 * arguments.length without making the property aware that its value had
1051 * been changed (which would have happened if we had deleted it before
1052 * redefining it or we had invoked its setter to change its value).
1054 if (callDelProperty
) {
1056 if (!CallJSDeletePropertyOp(cx
, obj2
->getClass()->delProperty
, obj2
, id
, &succeeded
))
1060 return baseops::DefineGeneric(cx
, obj
, id
, v
, getter
, setter
, attrs
);
1063 /* ES6 20130308 draft 8.4.2.1 [[DefineOwnProperty]] */
1065 DefinePropertyOnArray(JSContext
*cx
, Handle
<ArrayObject
*> arr
, HandleId id
, const PropDesc
&desc
,
1066 bool throwError
, bool *rval
)
1069 if (id
== NameToId(cx
->names().length
)) {
1070 // Canonicalize value, if necessary, before proceeding any further. It
1071 // would be better if this were always/only done by ArraySetLength.
1072 // But canonicalization may throw a RangeError (or other exception, if
1073 // the value is an object with user-defined conversion semantics)
1074 // before other attributes are checked. So as long as our internal
1075 // defineProperty hook doesn't match the ECMA one, this duplicate
1076 // checking can't be helped.
1078 if (desc
.hasValue()) {
1080 if (!CanonicalizeArrayLengthValue
<SequentialExecution
>(cx
, desc
.value(), &newLen
))
1082 v
.setNumber(newLen
);
1084 v
.setNumber(arr
->length());
1087 if (desc
.hasConfigurable() && desc
.configurable())
1088 return Reject(cx
, id
, JSMSG_CANT_REDEFINE_PROP
, throwError
, rval
);
1089 if (desc
.hasEnumerable() && desc
.enumerable())
1090 return Reject(cx
, id
, JSMSG_CANT_REDEFINE_PROP
, throwError
, rval
);
1092 if (desc
.isAccessorDescriptor())
1093 return Reject(cx
, id
, JSMSG_CANT_REDEFINE_PROP
, throwError
, rval
);
1095 unsigned attrs
= arr
->nativeLookup(cx
, id
)->attributes();
1096 if (!arr
->lengthIsWritable()) {
1097 if (desc
.hasWritable() && desc
.writable())
1098 return Reject(cx
, id
, JSMSG_CANT_REDEFINE_PROP
, throwError
, rval
);
1100 if (desc
.hasWritable() && !desc
.writable())
1101 attrs
= attrs
| JSPROP_READONLY
;
1104 return ArraySetLength
<SequentialExecution
>(cx
, arr
, id
, attrs
, v
, throwError
);
1109 if (js_IdIsIndex(id
, &index
)) {
1111 uint32_t oldLen
= arr
->length();
1114 if (index
>= oldLen
&& !arr
->lengthIsWritable())
1115 return Reject(cx
, arr
, JSMSG_CANT_APPEND_TO_ARRAY
, throwError
, rval
);
1118 return DefinePropertyOnObject(cx
, arr
, id
, desc
, throwError
, rval
);
1122 return DefinePropertyOnObject(cx
, arr
, id
, desc
, throwError
, rval
);
1126 js::DefineProperty(JSContext
*cx
, HandleObject obj
, HandleId id
, const PropDesc
&desc
,
1127 bool throwError
, bool *rval
)
1129 if (obj
->is
<ArrayObject
>()) {
1130 Rooted
<ArrayObject
*> arr(cx
, &obj
->as
<ArrayObject
>());
1131 return DefinePropertyOnArray(cx
, arr
, id
, desc
, throwError
, rval
);
1134 if (obj
->getOps()->lookupGeneric
) {
1135 if (obj
->is
<ProxyObject
>()) {
1136 Rooted
<PropertyDescriptor
> pd(cx
);
1137 desc
.populatePropertyDescriptor(obj
, &pd
);
1138 pd
.object().set(obj
);
1139 return Proxy::defineProperty(cx
, obj
, id
, &pd
);
1141 return Reject(cx
, obj
, JSMSG_OBJECT_NOT_EXTENSIBLE
, throwError
, rval
);
1144 return DefinePropertyOnObject(cx
, obj
, id
, desc
, throwError
, rval
);
1148 js::DefineOwnProperty(JSContext
*cx
, HandleObject obj
, HandleId id
, HandleValue descriptor
,
1151 Rooted
<PropDesc
> desc(cx
);
1152 if (!desc
.initialize(cx
, descriptor
))
1156 if (!DefineProperty(cx
, obj
, id
, desc
, true, &rval
))
1163 js::DefineOwnProperty(JSContext
*cx
, HandleObject obj
, HandleId id
,
1164 Handle
<PropertyDescriptor
> descriptor
, bool *bp
)
1166 Rooted
<PropDesc
> desc(cx
);
1168 desc
.initFromPropertyDescriptor(descriptor
);
1171 if (!DefineProperty(cx
, obj
, id
, desc
, true, &rval
))
1179 js::ReadPropertyDescriptors(JSContext
*cx
, HandleObject props
, bool checkAccessors
,
1180 AutoIdVector
*ids
, AutoPropDescVector
*descs
)
1182 if (!GetPropertyNames(cx
, props
, JSITER_OWNONLY
| JSITER_SYMBOLS
, ids
))
1186 for (size_t i
= 0, len
= ids
->length(); i
< len
; i
++) {
1188 Rooted
<PropDesc
> desc(cx
);
1190 if (!JSObject::getGeneric(cx
, props
, props
, id
, &v
) ||
1191 !desc
.initialize(cx
, v
, checkAccessors
) ||
1192 !descs
->append(desc
))
1201 js::DefineProperties(JSContext
*cx
, HandleObject obj
, HandleObject props
)
1203 AutoIdVector
ids(cx
);
1204 AutoPropDescVector
descs(cx
);
1205 if (!ReadPropertyDescriptors(cx
, props
, true, &ids
, &descs
))
1208 if (obj
->is
<ArrayObject
>()) {
1210 Rooted
<ArrayObject
*> arr(cx
, &obj
->as
<ArrayObject
>());
1211 for (size_t i
= 0, len
= ids
.length(); i
< len
; i
++) {
1212 if (!DefinePropertyOnArray(cx
, arr
, ids
[i
], descs
[i
], true, &dummy
))
1218 if (obj
->getOps()->lookupGeneric
) {
1219 if (obj
->is
<ProxyObject
>()) {
1220 Rooted
<PropertyDescriptor
> pd(cx
);
1221 for (size_t i
= 0, len
= ids
.length(); i
< len
; i
++) {
1222 descs
[i
].populatePropertyDescriptor(obj
, &pd
);
1223 if (!Proxy::defineProperty(cx
, obj
, ids
[i
], &pd
))
1229 return Reject(cx
, obj
, JSMSG_OBJECT_NOT_EXTENSIBLE
, true, &dummy
);
1233 for (size_t i
= 0, len
= ids
.length(); i
< len
; i
++) {
1234 if (!DefinePropertyOnObject(cx
, obj
, ids
[i
], descs
[i
], true, &dummy
))
1242 js_PopulateObject(JSContext
*cx
, HandleObject newborn
, HandleObject props
)
1244 return DefineProperties(cx
, newborn
, props
);
1247 js::types::TypeObject
*
1248 JSObject::uninlinedGetType(JSContext
*cx
)
1254 JSObject::uninlinedSetType(js::types::TypeObject
*newType
)
1259 /* static */ inline unsigned
1260 JSObject::getSealedOrFrozenAttributes(unsigned attrs
, ImmutabilityType it
)
1262 /* Make all attributes permanent; if freezing, make data attributes read-only. */
1263 if (it
== FREEZE
&& !(attrs
& (JSPROP_GETTER
| JSPROP_SETTER
)))
1264 return JSPROP_PERMANENT
| JSPROP_READONLY
;
1265 return JSPROP_PERMANENT
;
1269 JSObject::sealOrFreeze(JSContext
*cx
, HandleObject obj
, ImmutabilityType it
)
1271 assertSameCompartment(cx
, obj
);
1272 JS_ASSERT(it
== SEAL
|| it
== FREEZE
);
1275 if (!JSObject::isExtensible(cx
, obj
, &extensible
))
1277 if (extensible
&& !JSObject::preventExtensions(cx
, obj
))
1280 AutoIdVector
props(cx
);
1281 if (!GetPropertyNames(cx
, obj
, JSITER_HIDDEN
| JSITER_OWNONLY
| JSITER_SYMBOLS
, &props
))
1284 /* preventExtensions must sparsify dense objects, so we can assign to holes without checks. */
1285 JS_ASSERT_IF(obj
->isNative(), obj
->getDenseCapacity() == 0);
1287 if (obj
->isNative() && !obj
->inDictionaryMode() && !obj
->is
<TypedArrayObject
>()) {
1289 * Seal/freeze non-dictionary objects by constructing a new shape
1290 * hierarchy mirroring the original one, which can be shared if many
1291 * objects with the same structure are sealed/frozen. If we use the
1292 * generic path below then any non-empty object will be converted to
1295 RootedShape
last(cx
, EmptyShape::getInitialShape(cx
, obj
->getClass(),
1296 obj
->getTaggedProto(),
1299 obj
->numFixedSlots(),
1300 obj
->lastProperty()->getObjectFlags()));
1304 /* Get an in order list of the shapes in this object. */
1305 AutoShapeVector
shapes(cx
);
1306 for (Shape::Range
<NoGC
> r(obj
->lastProperty()); !r
.empty(); r
.popFront()) {
1307 if (!shapes
.append(&r
.front()))
1310 Reverse(shapes
.begin(), shapes
.end());
1312 for (size_t i
= 0; i
< shapes
.length(); i
++) {
1313 StackShape
unrootedChild(shapes
[i
]);
1314 RootedGeneric
<StackShape
*> child(cx
, &unrootedChild
);
1315 child
->attrs
|= getSealedOrFrozenAttributes(child
->attrs
, it
);
1317 if (!JSID_IS_EMPTY(child
->propid
) && it
== FREEZE
)
1318 MarkTypePropertyNonWritable(cx
, obj
, child
->propid
);
1320 last
= cx
->compartment()->propertyTree
.getChild(cx
, last
, *child
);
1325 JS_ASSERT(obj
->lastProperty()->slotSpan() == last
->slotSpan());
1326 JS_ALWAYS_TRUE(setLastProperty(cx
, obj
, last
));
1329 for (size_t i
= 0; i
< props
.length(); i
++) {
1333 if (!getGenericAttributes(cx
, obj
, id
, &attrs
))
1336 unsigned new_attrs
= getSealedOrFrozenAttributes(attrs
, it
);
1338 /* If we already have the attributes we need, skip the setAttributes call. */
1339 if ((attrs
| new_attrs
) == attrs
)
1343 if (!setGenericAttributes(cx
, obj
, id
, &attrs
))
1348 // Ordinarily ArraySetLength handles this, but we're going behind its back
1349 // right now, so we must do this manually. Neither the custom property
1350 // tree mutations nor the setGenericAttributes call in the above code will
1353 // ArraySetLength also implements the capacity <= length invariant for
1354 // arrays with non-writable length. We don't need to do anything special
1355 // for that, because capacity was zeroed out by preventExtensions. (See
1356 // the assertion before the if-else above.)
1357 if (it
== FREEZE
&& obj
->is
<ArrayObject
>()) {
1358 if (!obj
->maybeCopyElementsForWrite(cx
))
1360 obj
->getElementsHeader()->setNonwritableArrayLength();
1367 JSObject::isSealedOrFrozen(JSContext
*cx
, HandleObject obj
, ImmutabilityType it
, bool *resultp
)
1370 if (!JSObject::isExtensible(cx
, obj
, &extensible
))
1377 if (obj
->is
<TypedArrayObject
>()) {
1379 // Typed arrays are always sealed.
1382 // Typed arrays cannot be frozen, but an empty typed array is
1383 // trivially frozen.
1384 *resultp
= (obj
->as
<TypedArrayObject
>().length() == 0);
1389 AutoIdVector
props(cx
);
1390 if (!GetPropertyNames(cx
, obj
, JSITER_HIDDEN
| JSITER_OWNONLY
| JSITER_SYMBOLS
, &props
))
1394 for (size_t i
= 0, len
= props
.length(); i
< len
; i
++) {
1398 if (!getGenericAttributes(cx
, obj
, id
, &attrs
))
1402 * If the property is configurable, this object is neither sealed nor
1403 * frozen. If the property is a writable data property, this object is
1406 if (!(attrs
& JSPROP_PERMANENT
) ||
1407 (it
== FREEZE
&& !(attrs
& (JSPROP_READONLY
| JSPROP_GETTER
| JSPROP_SETTER
))))
1414 /* All properties checked out. This object is sealed/frozen. */
1421 JSObject::className(JSContext
*cx
, HandleObject obj
)
1423 assertSameCompartment(cx
, obj
);
1425 if (obj
->is
<ProxyObject
>())
1426 return Proxy::className(cx
, obj
);
1428 return obj
->getClass()->name
;
1432 * Get the GC kind to use for scripted 'new' on the given class.
1433 * FIXME bug 547327: estimate the size from the allocation site.
1435 static inline gc::AllocKind
1436 NewObjectGCKind(const js::Class
*clasp
)
1438 if (clasp
== &ArrayObject::class_
)
1439 return gc::FINALIZE_OBJECT8
;
1440 if (clasp
== &JSFunction::class_
)
1441 return gc::FINALIZE_OBJECT2
;
1442 return gc::FINALIZE_OBJECT4
;
1445 static inline JSObject
*
1446 NewObject(ExclusiveContext
*cx
, types::TypeObject
*type_
, JSObject
*parent
, gc::AllocKind kind
,
1447 NewObjectKind newKind
)
1449 const Class
*clasp
= type_
->clasp();
1451 JS_ASSERT(clasp
!= &ArrayObject::class_
);
1452 JS_ASSERT_IF(clasp
== &JSFunction::class_
,
1453 kind
== JSFunction::FinalizeKind
|| kind
== JSFunction::ExtendedFinalizeKind
);
1454 JS_ASSERT_IF(parent
, &parent
->global() == cx
->global());
1456 RootedTypeObject
type(cx
, type_
);
1458 JSObject
*metadata
= nullptr;
1459 if (!NewObjectMetadata(cx
, &metadata
))
1462 // For objects which can have fixed data following the object, only use
1463 // enough fixed slots to cover the number of reserved slots in the object,
1464 // regardless of the allocation kind specified.
1465 size_t nfixed
= ClassCanHaveFixedData(clasp
)
1466 ? GetGCKindSlots(gc::GetGCObjectKind(clasp
), clasp
)
1467 : GetGCKindSlots(kind
, clasp
);
1469 RootedShape
shape(cx
, EmptyShape::getInitialShape(cx
, clasp
, type
->proto(),
1470 parent
, metadata
, nfixed
));
1474 gc::InitialHeap heap
= GetInitialHeap(newKind
, clasp
);
1475 JSObject
*obj
= JSObject::create(cx
, kind
, heap
, shape
, type
);
1479 if (newKind
== SingletonObject
) {
1480 RootedObject
nobj(cx
, obj
);
1481 if (!JSObject::setSingletonType(cx
, nobj
))
1487 * This will cancel an already-running incremental GC from doing any more
1488 * slices, and it will prevent any future incremental GCs.
1490 bool globalWithoutCustomTrace
= clasp
->trace
== JS_GlobalObjectTraceHook
&&
1491 !cx
->compartment()->options().getTrace();
1493 !globalWithoutCustomTrace
&&
1494 !(clasp
->flags
& JSCLASS_IMPLEMENTS_BARRIERS
))
1496 if (!cx
->shouldBeJSContext())
1498 JSRuntime
*rt
= cx
->asJSContext()->runtime();
1499 rt
->gc
.disallowIncrementalGC();
1502 if (rt
->gc
.gcMode() == JSGC_MODE_INCREMENTAL
) {
1504 "The class %s has a trace hook but does not declare the\n"
1505 "JSCLASS_IMPLEMENTS_BARRIERS flag. Please ensure that it correctly\n"
1506 "implements write barriers and then set the flag.\n",
1513 probes::CreateObject(cx
, obj
);
1518 NewObjectCache::fillProto(EntryIndex entry
, const Class
*clasp
, js::TaggedProto proto
,
1519 gc::AllocKind kind
, JSObject
*obj
)
1521 JS_ASSERT_IF(proto
.isObject(), !proto
.toObject()->is
<GlobalObject
>());
1522 JS_ASSERT(obj
->getTaggedProto() == proto
);
1523 return fill(entry
, clasp
, proto
.raw(), kind
, obj
);
1527 js::NewObjectWithGivenProto(ExclusiveContext
*cxArg
, const js::Class
*clasp
,
1528 js::TaggedProto protoArg
, JSObject
*parentArg
,
1529 gc::AllocKind allocKind
, NewObjectKind newKind
)
1531 if (CanBeFinalizedInBackground(allocKind
, clasp
))
1532 allocKind
= GetBackgroundAllocKind(allocKind
);
1534 NewObjectCache::EntryIndex entry
= -1;
1535 uint64_t gcNumber
= 0;
1536 if (JSContext
*cx
= cxArg
->maybeJSContext()) {
1537 JSRuntime
*rt
= cx
->runtime();
1538 NewObjectCache
&cache
= rt
->newObjectCache
;
1539 if (protoArg
.isObject() &&
1540 newKind
== GenericObject
&&
1541 !cx
->compartment()->hasObjectMetadataCallback() &&
1542 (!parentArg
|| parentArg
== protoArg
.toObject()->getParent()) &&
1543 !protoArg
.toObject()->is
<GlobalObject
>())
1545 if (cache
.lookupProto(clasp
, protoArg
.toObject(), allocKind
, &entry
)) {
1546 JSObject
*obj
= cache
.newObjectFromHit
<NoGC
>(cx
, entry
, GetInitialHeap(newKind
, clasp
));
1550 Rooted
<TaggedProto
> proto(cxArg
, protoArg
);
1551 RootedObject
parent(cxArg
, parentArg
);
1552 obj
= cache
.newObjectFromHit
<CanGC
>(cx
, entry
, GetInitialHeap(newKind
, clasp
));
1558 gcNumber
= rt
->gc
.gcNumber();
1563 Rooted
<TaggedProto
> proto(cxArg
, protoArg
);
1564 RootedObject
parent(cxArg
, parentArg
);
1566 types::TypeObject
*type
= cxArg
->getNewType(clasp
, proto
, nullptr);
1571 * Default parent to the parent of the prototype, which was set from
1572 * the parent of the prototype's constructor.
1574 if (!parent
&& proto
.isObject())
1575 parent
= proto
.toObject()->getParent();
1577 RootedObject
obj(cxArg
, NewObject(cxArg
, type
, parent
, allocKind
, newKind
));
1581 if (entry
!= -1 && !obj
->hasDynamicSlots() &&
1582 cxArg
->asJSContext()->runtime()->gc
.gcNumber() == gcNumber
)
1584 cxArg
->asJSContext()->runtime()->newObjectCache
.fillProto(entry
, clasp
,
1585 proto
, allocKind
, obj
);
1592 ClassProtoKeyOrAnonymousOrNull(const js::Class
*clasp
)
1594 JSProtoKey key
= JSCLASS_CACHED_PROTO_KEY(clasp
);
1595 if (key
!= JSProto_Null
)
1597 if (clasp
->flags
& JSCLASS_IS_ANONYMOUS
)
1598 return JSProto_Object
;
1599 return JSProto_Null
;
1603 js::NewObjectWithClassProtoCommon(ExclusiveContext
*cxArg
,
1604 const js::Class
*clasp
, JSObject
*protoArg
, JSObject
*parentArg
,
1605 gc::AllocKind allocKind
, NewObjectKind newKind
)
1608 return NewObjectWithGivenProto(cxArg
, clasp
, TaggedProto(protoArg
), parentArg
, allocKind
, newKind
);
1610 if (CanBeFinalizedInBackground(allocKind
, clasp
))
1611 allocKind
= GetBackgroundAllocKind(allocKind
);
1614 parentArg
= cxArg
->global();
1617 * Use the object cache, except for classes without a cached proto key.
1618 * On these objects, FindProto will do a dynamic property lookup to get
1619 * global[className].prototype, where changes to either the className or
1620 * prototype property would render the cached lookup incorrect. For classes
1621 * with a proto key, the prototype created during class initialization is
1622 * stored in an immutable slot on the global (except for ClearScope, which
1623 * will flush the new object cache).
1625 JSProtoKey protoKey
= ClassProtoKeyOrAnonymousOrNull(clasp
);
1627 NewObjectCache::EntryIndex entry
= -1;
1628 if (JSContext
*cx
= cxArg
->maybeJSContext()) {
1629 NewObjectCache
&cache
= cx
->runtime()->newObjectCache
;
1630 if (parentArg
->is
<GlobalObject
>() &&
1631 protoKey
!= JSProto_Null
&&
1632 newKind
== GenericObject
&&
1633 !cx
->compartment()->hasObjectMetadataCallback())
1635 if (cache
.lookupGlobal(clasp
, &parentArg
->as
<GlobalObject
>(), allocKind
, &entry
)) {
1636 JSObject
*obj
= cache
.newObjectFromHit
<NoGC
>(cx
, entry
, GetInitialHeap(newKind
, clasp
));
1640 RootedObject
parent(cxArg
, parentArg
);
1641 RootedObject
proto(cxArg
, protoArg
);
1642 obj
= cache
.newObjectFromHit
<CanGC
>(cx
, entry
, GetInitialHeap(newKind
, clasp
));
1651 RootedObject
parent(cxArg
, parentArg
);
1652 RootedObject
proto(cxArg
, protoArg
);
1654 if (!FindProto(cxArg
, clasp
, &proto
))
1657 Rooted
<TaggedProto
> taggedProto(cxArg
, TaggedProto(proto
));
1658 types::TypeObject
*type
= cxArg
->getNewType(clasp
, taggedProto
);
1662 JSObject
*obj
= NewObject(cxArg
, type
, parent
, allocKind
, newKind
);
1666 if (entry
!= -1 && !obj
->hasDynamicSlots()) {
1667 cxArg
->asJSContext()->runtime()->newObjectCache
.fillGlobal(entry
, clasp
,
1668 &parent
->as
<GlobalObject
>(),
1676 * Create a plain object with the specified type. This bypasses getNewType to
1677 * avoid losing creation site information for objects made by scripted 'new'.
1680 js::NewObjectWithType(JSContext
*cx
, HandleTypeObject type
, JSObject
*parent
, gc::AllocKind allocKind
,
1681 NewObjectKind newKind
)
1685 JS_ASSERT(allocKind
<= gc::FINALIZE_OBJECT_LAST
);
1686 if (CanBeFinalizedInBackground(allocKind
, type
->clasp()))
1687 allocKind
= GetBackgroundAllocKind(allocKind
);
1689 NewObjectCache
&cache
= cx
->runtime()->newObjectCache
;
1691 NewObjectCache::EntryIndex entry
= -1;
1692 if (parent
== type
->proto().toObject()->getParent() &&
1693 newKind
== GenericObject
&&
1694 !cx
->compartment()->hasObjectMetadataCallback())
1696 if (cache
.lookupType(type
, allocKind
, &entry
)) {
1697 JSObject
*obj
= cache
.newObjectFromHit
<NoGC
>(cx
, entry
, GetInitialHeap(newKind
, type
->clasp()));
1701 obj
= cache
.newObjectFromHit
<CanGC
>(cx
, entry
, GetInitialHeap(newKind
, type
->clasp()));
1702 parent
= type
->proto().toObject()->getParent();
1707 JSObject
*obj
= NewObject(cx
, type
, parent
, allocKind
, newKind
);
1711 if (entry
!= -1 && !obj
->hasDynamicSlots())
1712 cache
.fillType(entry
, type
, allocKind
, obj
);
1718 js::NewObjectScriptedCall(JSContext
*cx
, MutableHandleObject pobj
)
1721 RootedScript
script(cx
, cx
->currentScript(&pc
));
1722 gc::AllocKind allocKind
= NewObjectGCKind(&JSObject::class_
);
1723 NewObjectKind newKind
= script
1724 ? UseNewTypeForInitializer(script
, pc
, &JSObject::class_
)
1726 RootedObject
obj(cx
, NewBuiltinClassInstance(cx
, &JSObject::class_
, allocKind
, newKind
));
1731 /* Try to specialize the type of the object to the scripted call site. */
1732 if (!types::SetInitializerObjectType(cx
, script
, pc
, obj
, newKind
))
1741 js::CreateThis(JSContext
*cx
, const Class
*newclasp
, HandleObject callee
)
1743 RootedValue
protov(cx
);
1744 if (!JSObject::getProperty(cx
, callee
, callee
, cx
->names().prototype
, &protov
))
1747 JSObject
*proto
= protov
.isObjectOrNull() ? protov
.toObjectOrNull() : nullptr;
1748 JSObject
*parent
= callee
->getParent();
1749 gc::AllocKind kind
= NewObjectGCKind(newclasp
);
1750 return NewObjectWithClassProto(cx
, newclasp
, proto
, parent
, kind
);
1753 static inline JSObject
*
1754 CreateThisForFunctionWithType(JSContext
*cx
, HandleTypeObject type
, JSObject
*parent
,
1755 NewObjectKind newKind
)
1757 if (type
->newScript()) {
1759 * Make an object with the type's associated finalize kind and shape,
1760 * which reflects any properties that will definitely be added to the
1761 * object before it is read from.
1763 RootedObject
templateObject(cx
, type
->newScript()->templateObject
);
1764 JS_ASSERT(templateObject
->type() == type
);
1766 RootedObject
res(cx
, CopyInitializerObject(cx
, templateObject
, newKind
));
1769 if (newKind
== SingletonObject
) {
1770 Rooted
<TaggedProto
> proto(cx
, TaggedProto(templateObject
->getProto()));
1771 if (!res
->splicePrototype(cx
, &JSObject::class_
, proto
))
1779 gc::AllocKind allocKind
= NewObjectGCKind(&JSObject::class_
);
1780 return NewObjectWithType(cx
, type
, parent
, allocKind
, newKind
);
1784 js::CreateThisForFunctionWithProto(JSContext
*cx
, HandleObject callee
, JSObject
*proto
,
1785 NewObjectKind newKind
/* = GenericObject */)
1787 RootedObject
res(cx
);
1790 RootedTypeObject
type(cx
, cx
->getNewType(&JSObject::class_
, TaggedProto(proto
), &callee
->as
<JSFunction
>()));
1793 res
= CreateThisForFunctionWithType(cx
, type
, callee
->getParent(), newKind
);
1795 gc::AllocKind allocKind
= NewObjectGCKind(&JSObject::class_
);
1796 res
= NewObjectWithClassProto(cx
, &JSObject::class_
, proto
, callee
->getParent(), allocKind
, newKind
);
1800 JSScript
*script
= callee
->as
<JSFunction
>().getOrCreateScript(cx
);
1803 TypeScript::SetThis(cx
, script
, types::Type::ObjectType(res
));
1810 js::CreateThisForFunction(JSContext
*cx
, HandleObject callee
, NewObjectKind newKind
)
1812 RootedValue
protov(cx
);
1813 if (!JSObject::getProperty(cx
, callee
, callee
, cx
->names().prototype
, &protov
))
1816 if (protov
.isObject())
1817 proto
= &protov
.toObject();
1820 JSObject
*obj
= CreateThisForFunctionWithProto(cx
, callee
, proto
, newKind
);
1822 if (obj
&& newKind
== SingletonObject
) {
1823 RootedObject
nobj(cx
, obj
);
1825 /* Reshape the singleton before passing it as the 'this' value. */
1826 JSObject::clear(cx
, nobj
);
1828 JSScript
*calleeScript
= callee
->as
<JSFunction
>().nonLazyScript();
1829 TypeScript::SetThis(cx
, calleeScript
, types::Type::ObjectType(nobj
));
1838 * Given pc pointing after a property accessing bytecode, return true if the
1839 * access is "object-detecting" in the sense used by web scripts, e.g., when
1840 * checking whether document.all is defined.
1843 Detecting(JSContext
*cx
, JSScript
*script
, jsbytecode
*pc
)
1845 JS_ASSERT(script
->containsPC(pc
));
1847 /* General case: a branch or equality op follows the access. */
1848 JSOp op
= JSOp(*pc
);
1849 if (js_CodeSpec
[op
].format
& JOF_DETECTING
)
1852 jsbytecode
*endpc
= script
->codeEnd();
1854 if (op
== JSOP_NULL
) {
1856 * Special case #1: handle (document.all == null). Don't sweat
1857 * about JS1.2's revision of the equality operators here.
1861 return op
== JSOP_EQ
|| op
== JSOP_NE
;
1866 if (op
== JSOP_GETGNAME
|| op
== JSOP_NAME
) {
1868 * Special case #2: handle (document.all == undefined). Don't worry
1869 * about a local variable named |undefined| shadowing the immutable
1870 * global binding...because, really?
1872 JSAtom
*atom
= script
->getAtom(GET_UINT32_INDEX(pc
));
1873 if (atom
== cx
->names().undefined
&&
1874 (pc
+= js_CodeSpec
[op
].length
) < endpc
) {
1876 return op
== JSOP_EQ
|| op
== JSOP_NE
|| op
== JSOP_STRICTEQ
|| op
== JSOP_STRICTNE
;
1884 JSObject::nonNativeSetProperty(JSContext
*cx
, HandleObject obj
,
1885 HandleId id
, MutableHandleValue vp
, bool strict
)
1887 if (MOZ_UNLIKELY(obj
->watched())) {
1888 WatchpointMap
*wpmap
= cx
->compartment()->watchpointMap
;
1889 if (wpmap
&& !wpmap
->triggerWatchpoint(cx
, obj
, id
, vp
))
1892 return obj
->getOps()->setGeneric(cx
, obj
, id
, vp
, strict
);
1896 JSObject::nonNativeSetElement(JSContext
*cx
, HandleObject obj
,
1897 uint32_t index
, MutableHandleValue vp
, bool strict
)
1899 if (MOZ_UNLIKELY(obj
->watched())) {
1901 if (!IndexToId(cx
, index
, &id
))
1904 WatchpointMap
*wpmap
= cx
->compartment()->watchpointMap
;
1905 if (wpmap
&& !wpmap
->triggerWatchpoint(cx
, obj
, id
, vp
))
1908 return obj
->getOps()->setElement(cx
, obj
, index
, vp
, strict
);
1912 JS_CopyPropertyFrom(JSContext
*cx
, HandleId id
, HandleObject target
,
1915 // |obj| and |cx| are generally not same-compartment with |target| here.
1916 assertSameCompartment(cx
, obj
, id
);
1917 Rooted
<JSPropertyDescriptor
> desc(cx
);
1919 if (!GetOwnPropertyDescriptor(cx
, obj
, id
, &desc
))
1921 MOZ_ASSERT(desc
.object());
1923 // Silently skip JSPropertyOp-implemented accessors.
1924 if (desc
.getter() && !desc
.hasGetterObject())
1926 if (desc
.setter() && !desc
.hasSetterObject())
1929 JSAutoCompartment
ac(cx
, target
);
1930 RootedId
wrappedId(cx
, id
);
1931 if (!cx
->compartment()->wrap(cx
, &desc
))
1935 return DefineOwnProperty(cx
, target
, wrappedId
, desc
, &ignored
);
1939 JS_CopyPropertiesFrom(JSContext
*cx
, HandleObject target
, HandleObject obj
)
1941 JSAutoCompartment
ac(cx
, obj
);
1943 AutoIdVector
props(cx
);
1944 if (!GetPropertyNames(cx
, obj
, JSITER_OWNONLY
| JSITER_HIDDEN
| JSITER_SYMBOLS
, &props
))
1947 for (size_t i
= 0; i
< props
.length(); ++i
) {
1948 if (!JS_CopyPropertyFrom(cx
, props
[i
], target
, obj
))
1956 CopySlots(JSContext
*cx
, HandleObject from
, HandleObject to
)
1958 JS_ASSERT(!from
->isNative() && !to
->isNative());
1959 JS_ASSERT(from
->getClass() == to
->getClass());
1962 if (from
->is
<WrapperObject
>() &&
1963 (Wrapper::wrapperHandler(from
)->flags() &
1964 Wrapper::CROSS_COMPARTMENT
)) {
1965 to
->setSlot(0, from
->getSlot(0));
1966 to
->setSlot(1, from
->getSlot(1));
1970 size_t span
= JSCLASS_RESERVED_SLOTS(from
->getClass());
1972 for (; n
< span
; ++n
) {
1973 v
= from
->getSlot(n
);
1974 if (!cx
->compartment()->wrap(cx
, &v
))
1982 js::CloneObject(JSContext
*cx
, HandleObject obj
, Handle
<js::TaggedProto
> proto
, HandleObject parent
)
1984 if (!obj
->isNative() && !obj
->is
<ProxyObject
>()) {
1985 JS_ReportErrorNumber(cx
, js_GetErrorMessage
, nullptr,
1986 JSMSG_CANT_CLONE_OBJECT
);
1990 RootedObject
clone(cx
, NewObjectWithGivenProto(cx
, obj
->getClass(), proto
, parent
));
1993 if (obj
->isNative()) {
1994 if (clone
->is
<JSFunction
>() && (obj
->compartment() != clone
->compartment())) {
1995 JS_ReportErrorNumber(cx
, js_GetErrorMessage
, nullptr,
1996 JSMSG_CANT_CLONE_OBJECT
);
2000 if (obj
->hasPrivate())
2001 clone
->setPrivate(obj
->getPrivate());
2003 JS_ASSERT(obj
->is
<ProxyObject
>());
2004 if (!CopySlots(cx
, obj
, clone
))
2012 js::DeepCloneObjectLiteral(JSContext
*cx
, HandleObject obj
, NewObjectKind newKind
)
2014 /* NB: Keep this in sync with XDRObjectLiteral. */
2015 JS_ASSERT_IF(obj
->hasSingletonType(),
2016 JS::CompartmentOptionsRef(cx
).getSingletonsAsTemplates());
2017 JS_ASSERT(obj
->is
<JSObject
>() || obj
->is
<ArrayObject
>());
2019 // Result of the clone function.
2020 RootedObject
clone(cx
);
2022 // Temporary element/slot which would be stored in the cloned object.
2024 RootedObject
deepObj(cx
);
2026 if (obj
->is
<ArrayObject
>()) {
2027 clone
= NewDenseUnallocatedArray(cx
, obj
->as
<ArrayObject
>().length(), nullptr, newKind
);
2029 // Object literals are tenured by default as holded by the JSScript.
2030 JS_ASSERT(obj
->isTenured());
2031 AllocKind kind
= obj
->tenuredGetAllocKind();
2032 Rooted
<TypeObject
*> typeObj(cx
, obj
->getType(cx
));
2035 RootedObject
parent(cx
, obj
->getParent());
2036 clone
= NewObjectWithGivenProto(cx
, &JSObject::class_
, TaggedProto(typeObj
->proto().toObject()),
2037 parent
, kind
, newKind
);
2040 // Allocate the same number of slots.
2041 if (!clone
|| !clone
->ensureElements(cx
, obj
->getDenseCapacity()))
2044 // Copy the number of initialized elements.
2045 uint32_t initialized
= obj
->getDenseInitializedLength();
2047 clone
->setDenseInitializedLength(initialized
);
2049 // Recursive copy of dense element.
2050 for (uint32_t i
= 0; i
< initialized
; ++i
) {
2051 v
= obj
->getDenseElement(i
);
2053 deepObj
= &v
.toObject();
2054 deepObj
= js::DeepCloneObjectLiteral(cx
, deepObj
, newKind
);
2056 JS_ReportOutOfMemory(cx
);
2059 v
.setObject(*deepObj
);
2061 clone
->initDenseElement(i
, v
);
2064 JS_ASSERT(obj
->compartment() == clone
->compartment());
2065 JS_ASSERT(!obj
->hasPrivate());
2066 RootedShape
shape(cx
, obj
->lastProperty());
2067 size_t span
= shape
->slotSpan();
2068 clone
->setLastProperty(cx
, clone
, shape
);
2069 for (size_t i
= 0; i
< span
; i
++) {
2070 v
= obj
->getSlot(i
);
2072 deepObj
= &v
.toObject();
2073 deepObj
= js::DeepCloneObjectLiteral(cx
, deepObj
, newKind
);
2076 v
.setObject(*deepObj
);
2078 clone
->setSlot(i
, v
);
2081 if (obj
->hasSingletonType()) {
2082 if (!JSObject::setSingletonType(cx
, clone
))
2084 } else if (obj
->getClass() == &ArrayObject::class_
) {
2085 FixArrayType(cx
, clone
);
2087 FixObjectType(cx
, clone
);
2090 if (obj
->is
<ArrayObject
>() && obj
->denseElementsAreCopyOnWrite()) {
2091 if (!ObjectElements::MakeElementsCopyOnWrite(cx
, clone
))
2098 template<XDRMode mode
>
2100 js::XDRObjectLiteral(XDRState
<mode
> *xdr
, MutableHandleObject obj
)
2102 /* NB: Keep this in sync with DeepCloneObjectLiteral. */
2104 JSContext
*cx
= xdr
->cx();
2105 JS_ASSERT_IF(mode
== XDR_ENCODE
&& obj
->hasSingletonType(),
2106 JS::CompartmentOptionsRef(cx
).getSingletonsAsTemplates());
2108 // Distinguish between objects and array classes.
2109 uint32_t isArray
= 0;
2111 if (mode
== XDR_ENCODE
) {
2112 JS_ASSERT(obj
->is
<JSObject
>() || obj
->is
<ArrayObject
>());
2113 isArray
= obj
->getClass() == &ArrayObject::class_
? 1 : 0;
2116 if (!xdr
->codeUint32(&isArray
))
2123 if (mode
== XDR_ENCODE
)
2124 length
= obj
->as
<ArrayObject
>().length();
2126 if (!xdr
->codeUint32(&length
))
2129 if (mode
== XDR_DECODE
)
2130 obj
.set(NewDenseUnallocatedArray(cx
, length
, NULL
, js::MaybeSingletonObject
));
2133 // Code the alloc kind of the object.
2136 if (mode
== XDR_ENCODE
) {
2137 JS_ASSERT(obj
->getClass() == &JSObject::class_
);
2138 JS_ASSERT(obj
->isTenured());
2139 kind
= obj
->tenuredGetAllocKind();
2142 if (!xdr
->codeEnum32(&kind
))
2145 if (mode
== XDR_DECODE
)
2146 obj
.set(NewBuiltinClassInstance(cx
, &JSObject::class_
, kind
, js::MaybeSingletonObject
));
2152 if (mode
== XDR_ENCODE
)
2153 capacity
= obj
->getDenseCapacity();
2154 if (!xdr
->codeUint32(&capacity
))
2156 if (mode
== XDR_DECODE
) {
2157 if (!obj
->ensureElements(cx
, capacity
)) {
2158 JS_ReportOutOfMemory(cx
);
2164 uint32_t initialized
;
2166 if (mode
== XDR_ENCODE
)
2167 initialized
= obj
->getDenseInitializedLength();
2168 if (!xdr
->codeUint32(&initialized
))
2170 if (mode
== XDR_DECODE
) {
2172 obj
->setDenseInitializedLength(initialized
);
2176 RootedValue
tmpValue(cx
);
2178 // Recursively copy dense elements.
2180 for (unsigned i
= 0; i
< initialized
; i
++) {
2181 if (mode
== XDR_ENCODE
)
2182 tmpValue
= obj
->getDenseElement(i
);
2184 if (!xdr
->codeConstValue(&tmpValue
))
2187 if (mode
== XDR_DECODE
)
2188 obj
->initDenseElement(i
, tmpValue
);
2192 JS_ASSERT(!obj
->hasPrivate());
2193 RootedShape
shape(cx
, obj
->lastProperty());
2195 // Code the number of slots in the vector.
2198 // Code ids of the object in order. As opposed to DeepCloneObjectLiteral we
2199 // cannot just re-use the shape of the original bytecode value and we have
2200 // to write down the shape as well as the corresponding values. Ideally we
2201 // would have a mechanism to serialize the shape too.
2202 js::AutoIdVector
ids(cx
);
2204 if (mode
== XDR_ENCODE
&& !shape
->isEmptyShape()) {
2205 nslot
= shape
->slotSpan();
2206 if (!ids
.reserve(nslot
))
2209 for (unsigned i
= 0; i
< nslot
; i
++)
2210 ids
.infallibleAppend(JSID_VOID
);
2212 for (Shape::Range
<NoGC
> it(shape
); !it
.empty(); it
.popFront()) {
2213 // If we have reached the native property of the array class, we
2214 // exit as the remaining would only be reserved slots.
2215 if (!it
.front().hasSlot()) {
2220 JS_ASSERT(it
.front().hasDefaultGetter());
2221 ids
[it
.front().slot()].set(it
.front().propid());
2225 if (!xdr
->codeUint32(&nslot
))
2228 RootedAtom
atom(cx
);
2230 uint32_t idType
= 0;
2231 for (unsigned i
= 0; i
< nslot
; i
++) {
2232 if (mode
== XDR_ENCODE
) {
2234 if (JSID_IS_INT(id
))
2235 idType
= JSID_TYPE_INT
;
2236 else if (JSID_IS_ATOM(id
))
2237 idType
= JSID_TYPE_STRING
;
2239 MOZ_CRASH("Symbol property is not yet supported by XDR.");
2241 tmpValue
= obj
->getSlot(i
);
2244 if (!xdr
->codeUint32(&idType
))
2247 if (idType
== JSID_TYPE_STRING
) {
2248 if (mode
== XDR_ENCODE
)
2249 atom
= JSID_TO_ATOM(id
);
2250 if (!XDRAtom(xdr
, &atom
))
2252 if (mode
== XDR_DECODE
)
2253 id
= AtomToId(atom
);
2255 JS_ASSERT(idType
== JSID_TYPE_INT
);
2257 if (mode
== XDR_ENCODE
)
2258 indexVal
= uint32_t(JSID_TO_INT(id
));
2259 if (!xdr
->codeUint32(&indexVal
))
2261 if (mode
== XDR_DECODE
)
2262 id
= INT_TO_JSID(int32_t(indexVal
));
2265 if (!xdr
->codeConstValue(&tmpValue
))
2268 if (mode
== XDR_DECODE
) {
2269 if (!DefineNativeProperty(cx
, obj
, id
, tmpValue
, NULL
, NULL
, JSPROP_ENUMERATE
))
2274 JS_ASSERT_IF(mode
== XDR_DECODE
, !obj
->inDictionaryMode());
2277 // Fix up types, distinguishing singleton-typed objects.
2278 uint32_t isSingletonTyped
;
2279 if (mode
== XDR_ENCODE
)
2280 isSingletonTyped
= obj
->hasSingletonType() ? 1 : 0;
2281 if (!xdr
->codeUint32(&isSingletonTyped
))
2284 if (mode
== XDR_DECODE
) {
2285 if (isSingletonTyped
) {
2286 if (!JSObject::setSingletonType(cx
, obj
))
2288 } else if (isArray
) {
2289 FixArrayType(cx
, obj
);
2291 FixObjectType(cx
, obj
);
2298 if (mode
== XDR_ENCODE
) {
2299 if (!JSObject::isExtensible(cx
, obj
, &extensible
))
2301 frozen
= extensible
? 0 : 1;
2303 if (!xdr
->codeUint32(&frozen
))
2305 if (mode
== XDR_DECODE
&& frozen
== 1) {
2306 if (!JSObject::freeze(cx
, obj
))
2312 uint32_t copyOnWrite
;
2313 if (mode
== XDR_ENCODE
)
2314 copyOnWrite
= obj
->denseElementsAreCopyOnWrite();
2315 if (!xdr
->codeUint32(©OnWrite
))
2317 if (mode
== XDR_DECODE
&& copyOnWrite
) {
2318 if (!ObjectElements::MakeElementsCopyOnWrite(cx
, obj
))
2327 js::XDRObjectLiteral(XDRState
<XDR_ENCODE
> *xdr
, MutableHandleObject obj
);
2330 js::XDRObjectLiteral(XDRState
<XDR_DECODE
> *xdr
, MutableHandleObject obj
);
2333 js::CloneObjectLiteral(JSContext
*cx
, HandleObject parent
, HandleObject srcObj
)
2335 if (srcObj
->getClass() == &JSObject::class_
) {
2336 AllocKind kind
= GetBackgroundAllocKind(GuessObjectGCKind(srcObj
->numFixedSlots()));
2337 JS_ASSERT_IF(srcObj
->isTenured(), kind
== srcObj
->tenuredGetAllocKind());
2339 JSObject
*proto
= cx
->global()->getOrCreateObjectPrototype(cx
);
2342 Rooted
<TypeObject
*> typeObj(cx
, cx
->getNewType(&JSObject::class_
, TaggedProto(proto
)));
2346 RootedShape
shape(cx
, srcObj
->lastProperty());
2347 return NewReshapedObject(cx
, typeObj
, parent
, kind
, shape
);
2350 JS_ASSERT(srcObj
->is
<ArrayObject
>());
2351 JS_ASSERT(srcObj
->denseElementsAreCopyOnWrite());
2352 JS_ASSERT(srcObj
->getElementsHeader()->ownerObject() == srcObj
);
2354 size_t length
= srcObj
->as
<ArrayObject
>().length();
2355 RootedObject
res(cx
, NewDenseAllocatedArray(cx
, length
, nullptr, MaybeSingletonObject
));
2360 RootedValue
value(cx
);
2361 for (size_t i
= 0; i
< length
; i
++) {
2362 // The only markable values in copy on write arrays are atoms, which
2363 // can be freely copied between compartments.
2364 value
= srcObj
->getDenseElement(i
);
2365 JS_ASSERT_IF(value
.isMarkable(),
2366 cx
->runtime()->isAtomsZone(value
.toGCThing()->tenuredZone()));
2368 id
= INT_TO_JSID(i
);
2369 if (!JSObject::defineGeneric(cx
, res
, id
, value
, nullptr, nullptr, JSPROP_ENUMERATE
))
2373 if (!ObjectElements::MakeElementsCopyOnWrite(cx
, res
))
2379 struct JSObject::TradeGutsReserved
{
2380 Vector
<Value
> avals
;
2381 Vector
<Value
> bvals
;
2384 RootedShape newashape
;
2385 RootedShape newbshape
;
2386 HeapSlot
*newaslots
;
2387 HeapSlot
*newbslots
;
2389 explicit TradeGutsReserved(JSContext
*cx
)
2390 : avals(cx
), bvals(cx
),
2391 newafixed(0), newbfixed(0),
2392 newashape(cx
), newbshape(cx
),
2393 newaslots(nullptr), newbslots(nullptr)
2396 ~TradeGutsReserved()
2404 JSObject::ReserveForTradeGuts(JSContext
*cx
, JSObject
*aArg
, JSObject
*bArg
,
2405 TradeGutsReserved
&reserved
)
2408 * Avoid GC in here to avoid confusing the tracing code with our
2409 * intermediate state.
2411 AutoSuppressGC
suppress(cx
);
2413 RootedObject
a(cx
, aArg
);
2414 RootedObject
b(cx
, bArg
);
2415 JS_ASSERT(a
->compartment() == b
->compartment());
2416 AutoCompartment
ac(cx
, a
);
2419 * When performing multiple swaps between objects which may have different
2420 * numbers of fixed slots, we reserve all space ahead of time so that the
2421 * swaps can be performed infallibly.
2425 * Swap prototypes and classes on the two objects, so that TradeGuts can
2426 * preserve the types of the two objects.
2428 const Class
*aClass
= a
->getClass();
2429 const Class
*bClass
= b
->getClass();
2430 Rooted
<TaggedProto
> aProto(cx
, a
->getTaggedProto());
2431 Rooted
<TaggedProto
> bProto(cx
, b
->getTaggedProto());
2433 if (!SetClassAndProto(cx
, a
, bClass
, bProto
, &success
) || !success
)
2435 if (!SetClassAndProto(cx
, b
, aClass
, aProto
, &success
) || !success
)
2438 if (a
->tenuredSizeOfThis() == b
->tenuredSizeOfThis())
2442 * If either object is native, it needs a new shape to preserve the
2443 * invariant that objects with the same shape have the same number of
2444 * inline slots. The fixed slots will be updated in place during TradeGuts.
2445 * Non-native objects need to be reshaped according to the new count.
2447 if (a
->isNative()) {
2448 if (!a
->generateOwnShape(cx
))
2451 reserved
.newbshape
= EmptyShape::getInitialShape(cx
, aClass
, aProto
, a
->getParent(), a
->getMetadata(),
2452 b
->tenuredGetAllocKind());
2453 if (!reserved
.newbshape
)
2456 if (b
->isNative()) {
2457 if (!b
->generateOwnShape(cx
))
2460 reserved
.newashape
= EmptyShape::getInitialShape(cx
, bClass
, bProto
, b
->getParent(), b
->getMetadata(),
2461 a
->tenuredGetAllocKind());
2462 if (!reserved
.newashape
)
2466 /* The avals/bvals vectors hold all original values from the objects. */
2468 if (!reserved
.avals
.reserve(a
->slotSpan()))
2470 if (!reserved
.bvals
.reserve(b
->slotSpan()))
2474 * The newafixed/newbfixed hold the number of fixed slots in the objects
2475 * after the swap. Adjust these counts according to whether the objects
2476 * use their last fixed slot for storing private data.
2479 reserved
.newafixed
= a
->numFixedSlots();
2480 reserved
.newbfixed
= b
->numFixedSlots();
2482 if (aClass
->hasPrivate()) {
2483 reserved
.newafixed
++;
2484 reserved
.newbfixed
--;
2486 if (bClass
->hasPrivate()) {
2487 reserved
.newbfixed
++;
2488 reserved
.newafixed
--;
2491 JS_ASSERT(reserved
.newafixed
>= 0);
2492 JS_ASSERT(reserved
.newbfixed
>= 0);
2495 * The newaslots/newbslots arrays hold any dynamic slots for the objects
2496 * if they do not have enough fixed slots to accomodate the slots in the
2500 unsigned adynamic
= dynamicSlotsCount(reserved
.newafixed
, b
->slotSpan(), b
->getClass());
2501 unsigned bdynamic
= dynamicSlotsCount(reserved
.newbfixed
, a
->slotSpan(), a
->getClass());
2504 reserved
.newaslots
= a
->pod_malloc
<HeapSlot
>(adynamic
);
2505 if (!reserved
.newaslots
)
2507 Debug_SetSlotRangeToCrashOnTouch(reserved
.newaslots
, adynamic
);
2510 reserved
.newbslots
= b
->pod_malloc
<HeapSlot
>(bdynamic
);
2511 if (!reserved
.newbslots
)
2513 Debug_SetSlotRangeToCrashOnTouch(reserved
.newbslots
, bdynamic
);
2520 JSObject::TradeGuts(JSContext
*cx
, JSObject
*a
, JSObject
*b
, TradeGutsReserved
&reserved
)
2522 JS_ASSERT(a
->compartment() == b
->compartment());
2523 JS_ASSERT(a
->is
<JSFunction
>() == b
->is
<JSFunction
>());
2526 * Neither object may be in the nursery, but ensure we update any embedded
2527 * nursery pointers in either object.
2529 #ifdef JSGC_GENERATIONAL
2530 JS_ASSERT(!IsInsideNursery(a
) && !IsInsideNursery(b
));
2531 cx
->runtime()->gc
.storeBuffer
.putWholeCellFromMainThread(a
);
2532 cx
->runtime()->gc
.storeBuffer
.putWholeCellFromMainThread(b
);
2534 JS::AutoCheckCannotGC nogc
;
2537 * Swap the object's types, to restore their initial type information.
2538 * The prototypes and classes of the objects were swapped in ReserveForTradeGuts.
2540 TypeObject
*tmp
= a
->type_
;
2541 a
->type_
= b
->type_
;
2544 /* Don't try to swap a JSFunction for a plain function JSObject. */
2545 JS_ASSERT_IF(a
->is
<JSFunction
>(), a
->tenuredSizeOfThis() == b
->tenuredSizeOfThis());
2548 * Regexp guts are more complicated -- we would need to migrate the
2549 * refcounted JIT code blob for them across compartments instead of just
2552 JS_ASSERT(!a
->is
<RegExpObject
>() && !b
->is
<RegExpObject
>());
2554 /* Arrays can use their fixed storage for elements. */
2555 JS_ASSERT(!a
->is
<ArrayObject
>() && !b
->is
<ArrayObject
>());
2558 * Callers should not try to swap ArrayBuffer objects,
2559 * these use a different slot representation from other objects.
2561 JS_ASSERT(!a
->is
<ArrayBufferObject
>() && !b
->is
<ArrayBufferObject
>());
2563 /* Trade the guts of the objects. */
2564 const size_t size
= a
->tenuredSizeOfThis();
2565 if (size
== b
->tenuredSizeOfThis()) {
2567 * If the objects are the same size, then we make no assumptions about
2568 * whether they have dynamically allocated slots and instead just copy
2569 * them over wholesale.
2571 char tmp
[mozilla::tl::Max
<sizeof(JSFunction
), sizeof(JSObject_Slots16
)>::value
];
2572 JS_ASSERT(size
<= sizeof(tmp
));
2574 js_memcpy(tmp
, a
, size
);
2575 js_memcpy(a
, b
, size
);
2576 js_memcpy(b
, tmp
, size
);
2579 * If the objects are of differing sizes, use the space we reserved
2580 * earlier to save the slots from each object and then copy them into
2581 * the new layout for the other object.
2584 uint32_t acap
= a
->slotSpan();
2585 uint32_t bcap
= b
->slotSpan();
2587 for (size_t i
= 0; i
< acap
; i
++)
2588 reserved
.avals
.infallibleAppend(a
->getSlot(i
));
2590 for (size_t i
= 0; i
< bcap
; i
++)
2591 reserved
.bvals
.infallibleAppend(b
->getSlot(i
));
2593 /* Done with the dynamic slots. */
2594 if (a
->hasDynamicSlots())
2596 if (b
->hasDynamicSlots())
2599 void *apriv
= a
->hasPrivate() ? a
->getPrivate() : nullptr;
2600 void *bpriv
= b
->hasPrivate() ? b
->getPrivate() : nullptr;
2602 char tmp
[sizeof(JSObject
)];
2603 js_memcpy(&tmp
, a
, sizeof tmp
);
2604 js_memcpy(a
, b
, sizeof tmp
);
2605 js_memcpy(b
, &tmp
, sizeof tmp
);
2608 a
->shape_
->setNumFixedSlots(reserved
.newafixed
);
2610 a
->shape_
= reserved
.newashape
;
2612 a
->slots
= reserved
.newaslots
;
2613 a
->initSlotRange(0, reserved
.bvals
.begin(), bcap
);
2614 if (a
->hasPrivate())
2615 a
->initPrivate(bpriv
);
2618 b
->shape_
->setNumFixedSlots(reserved
.newbfixed
);
2620 b
->shape_
= reserved
.newbshape
;
2622 b
->slots
= reserved
.newbslots
;
2623 b
->initSlotRange(0, reserved
.avals
.begin(), acap
);
2624 if (b
->hasPrivate())
2625 b
->initPrivate(apriv
);
2627 /* Make sure the destructor for reserved doesn't free the slots. */
2628 reserved
.newaslots
= nullptr;
2629 reserved
.newbslots
= nullptr;
2632 if (a
->inDictionaryMode())
2633 a
->lastProperty()->listp
= &a
->shape_
;
2634 if (b
->inDictionaryMode())
2635 b
->lastProperty()->listp
= &b
->shape_
;
2637 #ifdef JSGC_INCREMENTAL
2639 * We need a write barrier here. If |a| was marked and |b| was not, then
2640 * after the swap, |b|'s guts would never be marked. The write barrier
2643 * Normally write barriers happen before the write. However, that's not
2644 * necessary here because nothing is being destroyed. We're just swapping.
2645 * We don't do the barrier before TradeGuts because ReserveForTradeGuts
2646 * makes changes to the objects that might confuse the tracing code.
2648 JS::Zone
*zone
= a
->zone();
2649 if (zone
->needsIncrementalBarrier()) {
2650 MarkChildren(zone
->barrierTracer(), a
);
2651 MarkChildren(zone
->barrierTracer(), b
);
2656 /* Use this method with extreme caution. It trades the guts of two objects. */
2658 JSObject::swap(JSContext
*cx
, HandleObject a
, HandleObject b
)
2660 // Ensure swap doesn't cause a finalizer to not be run.
2661 JS_ASSERT(IsBackgroundFinalized(a
->tenuredGetAllocKind()) ==
2662 IsBackgroundFinalized(b
->tenuredGetAllocKind()));
2663 JS_ASSERT(a
->compartment() == b
->compartment());
2665 unsigned r
= NotifyGCPreSwap(a
, b
);
2667 TradeGutsReserved
reserved(cx
);
2668 if (!ReserveForTradeGuts(cx
, a
, b
, reserved
)) {
2669 NotifyGCPostSwap(b
, a
, r
);
2672 TradeGuts(cx
, a
, b
, reserved
);
2674 NotifyGCPostSwap(a
, b
, r
);
2679 DefineStandardSlot(JSContext
*cx
, HandleObject obj
, JSProtoKey key
, JSAtom
*atom
,
2680 HandleValue v
, uint32_t attrs
, bool &named
)
2682 RootedId
id(cx
, AtomToId(atom
));
2684 if (key
!= JSProto_Null
) {
2686 * Initializing an actual standard class on a global object. If the
2687 * property is not yet present, force it into a new one bound to a
2688 * reserved slot. Otherwise, go through the normal property path.
2690 JS_ASSERT(obj
->is
<GlobalObject
>());
2691 JS_ASSERT(obj
->isNative());
2693 if (!obj
->nativeLookup(cx
, id
)) {
2694 obj
->as
<GlobalObject
>().setConstructorPropertySlot(key
, v
);
2696 uint32_t slot
= GlobalObject::constructorPropertySlot(key
);
2697 if (!JSObject::addProperty(cx
, obj
, id
, JS_PropertyStub
, JS_StrictPropertyStub
, slot
, attrs
, 0))
2705 named
= JSObject::defineGeneric(cx
, obj
, id
,
2706 v
, JS_PropertyStub
, JS_StrictPropertyStub
, attrs
);
2711 SetClassObject(JSObject
*obj
, JSProtoKey key
, JSObject
*cobj
, JSObject
*proto
)
2713 JS_ASSERT(!obj
->getParent());
2714 if (!obj
->is
<GlobalObject
>())
2717 obj
->as
<GlobalObject
>().setConstructor(key
, ObjectOrNullValue(cobj
));
2718 obj
->as
<GlobalObject
>().setPrototype(key
, ObjectOrNullValue(proto
));
2722 ClearClassObject(JSObject
*obj
, JSProtoKey key
)
2724 JS_ASSERT(!obj
->getParent());
2725 if (!obj
->is
<GlobalObject
>())
2728 obj
->as
<GlobalObject
>().setConstructor(key
, UndefinedValue());
2729 obj
->as
<GlobalObject
>().setPrototype(key
, UndefinedValue());
2733 DefineConstructorAndPrototype(JSContext
*cx
, HandleObject obj
, JSProtoKey key
, HandleAtom atom
,
2734 JSObject
*protoProto
, const Class
*clasp
,
2735 Native constructor
, unsigned nargs
,
2736 const JSPropertySpec
*ps
, const JSFunctionSpec
*fs
,
2737 const JSPropertySpec
*static_ps
, const JSFunctionSpec
*static_fs
,
2738 JSObject
**ctorp
, AllocKind ctorKind
)
2741 * Create a prototype object for this class.
2743 * FIXME: lazy standard (built-in) class initialization and even older
2744 * eager boostrapping code rely on all of these properties:
2746 * 1. NewObject attempting to compute a default prototype object when
2747 * passed null for proto; and
2749 * 2. NewObject tolerating no default prototype (null proto slot value)
2750 * due to this js_InitClass call coming from js_InitFunctionClass on an
2751 * otherwise-uninitialized global.
2753 * 3. NewObject allocating a JSFunction-sized GC-thing when clasp is
2754 * &JSFunction::class_, not a JSObject-sized (smaller) GC-thing.
2756 * The JS_NewObjectForGivenProto and JS_NewObject APIs also allow clasp to
2757 * be &JSFunction::class_ (we could break compatibility easily). But
2758 * fixing (3) is not enough without addressing the bootstrapping dependency
2763 * Create the prototype object. (GlobalObject::createBlankPrototype isn't
2764 * used because it parents the prototype object to the global and because
2765 * it uses WithProto::Given. FIXME: Undo dependencies on this parentage
2766 * [which already needs to happen for bug 638316], figure out nicer
2767 * semantics for null-protoProto, and use createBlankPrototype.)
2769 RootedObject
proto(cx
, NewObjectWithClassProto(cx
, clasp
, protoProto
, obj
, SingletonObject
));
2773 /* After this point, control must exit via label bad or out. */
2774 RootedObject
ctor(cx
);
2776 bool cached
= false;
2779 * Lacking a constructor, name the prototype (e.g., Math) unless this
2780 * class (a) is anonymous, i.e. for internal use only; (b) the class
2781 * of obj (the global object) is has a reserved slot indexed by key;
2782 * and (c) key is not the null key.
2784 if (!(clasp
->flags
& JSCLASS_IS_ANONYMOUS
) || !obj
->is
<GlobalObject
>() ||
2785 key
== JSProto_Null
)
2787 uint32_t attrs
= (clasp
->flags
& JSCLASS_IS_ANONYMOUS
)
2788 ? JSPROP_READONLY
| JSPROP_PERMANENT
2790 RootedValue
value(cx
, ObjectValue(*proto
));
2791 if (!DefineStandardSlot(cx
, obj
, key
, atom
, value
, attrs
, named
))
2798 * Create the constructor, not using GlobalObject::createConstructor
2799 * because the constructor currently must have |obj| as its parent.
2800 * (FIXME: remove this dependency on the exact identity of the parent,
2801 * perhaps as part of bug 638316.)
2803 RootedFunction
fun(cx
, NewFunction(cx
, js::NullPtr(), constructor
, nargs
,
2804 JSFunction::NATIVE_CTOR
, obj
, atom
, ctorKind
));
2809 * Set the class object early for standard class constructors. Type
2810 * inference may need to access these, and js::GetBuiltinPrototype will
2811 * fail if it tries to do a reentrant reconstruction of the class.
2813 if (key
!= JSProto_Null
) {
2814 SetClassObject(obj
, key
, fun
, proto
);
2818 RootedValue
value(cx
, ObjectValue(*fun
));
2819 if (!DefineStandardSlot(cx
, obj
, key
, atom
, value
, 0, named
))
2823 * Optionally construct the prototype object, before the class has
2824 * been fully initialized. Allow the ctor to replace proto with a
2825 * different object, as is done for operator new.
2828 if (!LinkConstructorAndPrototype(cx
, ctor
, proto
))
2831 /* Bootstrap Function.prototype (see also JS_InitStandardClasses). */
2832 Rooted
<TaggedProto
> tagged(cx
, TaggedProto(proto
));
2833 if (ctor
->getClass() == clasp
&& !ctor
->splicePrototype(cx
, clasp
, tagged
))
2837 if (!DefinePropertiesAndFunctions(cx
, proto
, ps
, fs
) ||
2838 (ctor
!= proto
&& !DefinePropertiesAndFunctions(cx
, ctor
, static_ps
, static_fs
)))
2843 /* If this is a standard class, cache its prototype. */
2844 if (!cached
&& key
!= JSProto_Null
)
2845 SetClassObject(obj
, key
, ctor
, proto
);
2854 RootedId
id(cx
, AtomToId(atom
));
2855 JSObject::deleteGeneric(cx
, obj
, id
, &succeeded
);
2858 ClearClassObject(obj
, key
);
2863 js_InitClass(JSContext
*cx
, HandleObject obj
, JSObject
*protoProto_
,
2864 const Class
*clasp
, Native constructor
, unsigned nargs
,
2865 const JSPropertySpec
*ps
, const JSFunctionSpec
*fs
,
2866 const JSPropertySpec
*static_ps
, const JSFunctionSpec
*static_fs
,
2867 JSObject
**ctorp
, AllocKind ctorKind
)
2869 RootedObject
protoProto(cx
, protoProto_
);
2871 /* Assert mandatory function pointer members. */
2872 JS_ASSERT(clasp
->addProperty
);
2873 JS_ASSERT(clasp
->delProperty
);
2874 JS_ASSERT(clasp
->getProperty
);
2875 JS_ASSERT(clasp
->setProperty
);
2876 JS_ASSERT(clasp
->enumerate
);
2877 JS_ASSERT(clasp
->resolve
);
2878 JS_ASSERT(clasp
->convert
);
2880 RootedAtom
atom(cx
, Atomize(cx
, clasp
->name
, strlen(clasp
->name
)));
2885 * All instances of the class will inherit properties from the prototype
2886 * object we are about to create (in DefineConstructorAndPrototype), which
2887 * in turn will inherit from protoProto.
2889 * When initializing a standard class (other than Object), if protoProto is
2890 * null, default to Object.prototype. The engine's internal uses of
2891 * js_InitClass depend on this nicety.
2893 JSProtoKey key
= JSCLASS_CACHED_PROTO_KEY(clasp
);
2894 if (key
!= JSProto_Null
&&
2896 !GetBuiltinPrototype(cx
, JSProto_Object
, &protoProto
))
2901 return DefineConstructorAndPrototype(cx
, obj
, key
, atom
, protoProto
, clasp
, constructor
, nargs
,
2902 ps
, fs
, static_ps
, static_fs
, ctorp
, ctorKind
);
2905 /* static */ inline bool
2906 JSObject::updateSlotsForSpan(ThreadSafeContext
*cx
,
2907 HandleObject obj
, size_t oldSpan
, size_t newSpan
)
2909 JS_ASSERT(cx
->isThreadLocal(obj
));
2910 JS_ASSERT(oldSpan
!= newSpan
);
2912 size_t oldCount
= dynamicSlotsCount(obj
->numFixedSlots(), oldSpan
, obj
->getClass());
2913 size_t newCount
= dynamicSlotsCount(obj
->numFixedSlots(), newSpan
, obj
->getClass());
2915 if (oldSpan
< newSpan
) {
2916 if (oldCount
< newCount
&& !JSObject::growSlots(cx
, obj
, oldCount
, newCount
))
2919 if (newSpan
== oldSpan
+ 1)
2920 obj
->initSlotUnchecked(oldSpan
, UndefinedValue());
2922 obj
->initializeSlotRange(oldSpan
, newSpan
- oldSpan
);
2924 /* Trigger write barriers on the old slots before reallocating. */
2925 obj
->prepareSlotRangeForOverwrite(newSpan
, oldSpan
);
2926 obj
->invalidateSlotRange(newSpan
, oldSpan
- newSpan
);
2928 if (oldCount
> newCount
)
2929 JSObject::shrinkSlots(cx
, obj
, oldCount
, newCount
);
2936 JSObject::setLastProperty(ThreadSafeContext
*cx
, HandleObject obj
, HandleShape shape
)
2938 JS_ASSERT(cx
->isThreadLocal(obj
));
2939 JS_ASSERT(!obj
->inDictionaryMode());
2940 JS_ASSERT(!shape
->inDictionary());
2941 JS_ASSERT(shape
->compartment() == obj
->compartment());
2942 JS_ASSERT(shape
->numFixedSlots() == obj
->numFixedSlots());
2944 size_t oldSpan
= obj
->lastProperty()->slotSpan();
2945 size_t newSpan
= shape
->slotSpan();
2947 if (oldSpan
== newSpan
) {
2948 obj
->shape_
= shape
;
2952 if (!updateSlotsForSpan(cx
, obj
, oldSpan
, newSpan
))
2955 obj
->shape_
= shape
;
2960 JSObject::setSlotSpan(ThreadSafeContext
*cx
, HandleObject obj
, uint32_t span
)
2962 JS_ASSERT(cx
->isThreadLocal(obj
));
2963 JS_ASSERT(obj
->inDictionaryMode());
2965 size_t oldSpan
= obj
->lastProperty()->base()->slotSpan();
2966 if (oldSpan
== span
)
2969 if (!JSObject::updateSlotsForSpan(cx
, obj
, oldSpan
, span
))
2972 obj
->lastProperty()->base()->setSlotSpan(span
);
2976 // This will not run the garbage collector. If a nursery cannot accomodate the slot array
2977 // an attempt will be made to place the array in the tenured area.
2979 AllocateSlots(ThreadSafeContext
*cx
, JSObject
*obj
, uint32_t nslots
)
2981 #ifdef JSGC_GENERATIONAL
2982 if (cx
->isJSContext())
2983 return cx
->asJSContext()->runtime()->gc
.nursery
.allocateSlots(obj
, nslots
);
2985 #ifdef JSGC_FJGENERATIONAL
2986 if (cx
->isForkJoinContext())
2987 return cx
->asForkJoinContext()->nursery().allocateSlots(obj
, nslots
);
2989 return obj
->pod_malloc
<HeapSlot
>(nslots
);
2992 // This will not run the garbage collector. If a nursery cannot accomodate the slot array
2993 // an attempt will be made to place the array in the tenured area.
2995 // If this returns null then the old slots will be left alone.
2997 ReallocateSlots(ThreadSafeContext
*cx
, JSObject
*obj
, HeapSlot
*oldSlots
,
2998 uint32_t oldCount
, uint32_t newCount
)
3000 #ifdef JSGC_GENERATIONAL
3001 if (cx
->isJSContext()) {
3002 return cx
->asJSContext()->runtime()->gc
.nursery
.reallocateSlots(obj
, oldSlots
,
3003 oldCount
, newCount
);
3006 #ifdef JSGC_FJGENERATIONAL
3007 if (cx
->isForkJoinContext()) {
3008 return cx
->asForkJoinContext()->nursery().reallocateSlots(obj
, oldSlots
,
3009 oldCount
, newCount
);
3012 return obj
->pod_realloc
<HeapSlot
>(oldSlots
, oldCount
, newCount
);
3016 JSObject::growSlots(ThreadSafeContext
*cx
, HandleObject obj
, uint32_t oldCount
, uint32_t newCount
)
3018 JS_ASSERT(cx
->isThreadLocal(obj
));
3019 JS_ASSERT(newCount
> oldCount
);
3020 JS_ASSERT_IF(!obj
->is
<ArrayObject
>(), newCount
>= SLOT_CAPACITY_MIN
);
3023 * Slot capacities are determined by the span of allocated objects. Due to
3024 * the limited number of bits to store shape slots, object growth is
3025 * throttled well before the slot capacity can overflow.
3027 JS_ASSERT(newCount
< NELEMENTS_LIMIT
);
3030 * If we are allocating slots for an object whose type is always created
3031 * by calling 'new' on a particular script, bump the GC kind for that
3032 * type to give these objects a larger number of fixed slots when future
3033 * objects are constructed.
3035 if (!obj
->hasLazyType() && !oldCount
&& obj
->type()->newScript()) {
3036 JSObject
*oldTemplate
= obj
->type()->newScript()->templateObject
;
3037 gc::AllocKind kind
= gc::GetGCObjectFixedSlotsKind(oldTemplate
->numFixedSlots());
3038 uint32_t newScriptSlots
= gc::GetGCKindSlots(kind
);
3039 if (newScriptSlots
== obj
->numFixedSlots() &&
3040 gc::TryIncrementAllocKind(&kind
) &&
3043 JSContext
*ncx
= cx
->asJSContext();
3044 AutoEnterAnalysis
enter(ncx
);
3046 Rooted
<TypeObject
*> typeObj(cx
, obj
->type());
3047 RootedShape
shape(cx
, oldTemplate
->lastProperty());
3048 JSObject
*reshapedObj
= NewReshapedObject(ncx
, typeObj
, obj
->getParent(), kind
, shape
,
3049 MaybeSingletonObject
);
3053 typeObj
->newScript()->templateObject
= reshapedObj
;
3054 typeObj
->markStateChange(ncx
);
3059 obj
->slots
= AllocateSlots(cx
, obj
, newCount
);
3062 Debug_SetSlotRangeToCrashOnTouch(obj
->slots
, newCount
);
3066 HeapSlot
*newslots
= ReallocateSlots(cx
, obj
, obj
->slots
, oldCount
, newCount
);
3068 return false; /* Leave slots at its old size. */
3070 obj
->slots
= newslots
;
3072 Debug_SetSlotRangeToCrashOnTouch(obj
->slots
+ oldCount
, newCount
- oldCount
);
3078 FreeSlots(ThreadSafeContext
*cx
, HeapSlot
*slots
)
3080 #ifdef JSGC_GENERATIONAL
3081 // Note: threads without a JSContext do not have access to GGC nursery allocated things.
3082 if (cx
->isJSContext())
3083 return cx
->asJSContext()->runtime()->gc
.nursery
.freeSlots(slots
);
3085 #ifdef JSGC_FJGENERATIONAL
3086 if (cx
->isForkJoinContext())
3087 return cx
->asForkJoinContext()->nursery().freeSlots(slots
);
3093 JSObject::shrinkSlots(ThreadSafeContext
*cx
, HandleObject obj
, uint32_t oldCount
, uint32_t newCount
)
3095 JS_ASSERT(cx
->isThreadLocal(obj
));
3096 JS_ASSERT(newCount
< oldCount
);
3098 if (newCount
== 0) {
3099 FreeSlots(cx
, obj
->slots
);
3100 obj
->slots
= nullptr;
3104 JS_ASSERT_IF(!obj
->is
<ArrayObject
>(), newCount
>= SLOT_CAPACITY_MIN
);
3106 HeapSlot
*newslots
= ReallocateSlots(cx
, obj
, obj
->slots
, oldCount
, newCount
);
3108 return; /* Leave slots at its old size. */
3110 obj
->slots
= newslots
;
3114 JSObject::sparsifyDenseElement(ExclusiveContext
*cx
, HandleObject obj
, uint32_t index
)
3116 if (!obj
->maybeCopyElementsForWrite(cx
))
3119 RootedValue
value(cx
, obj
->getDenseElement(index
));
3120 JS_ASSERT(!value
.isMagic(JS_ELEMENTS_HOLE
));
3122 JSObject::removeDenseElementForSparseIndex(cx
, obj
, index
);
3124 uint32_t slot
= obj
->slotSpan();
3125 if (!obj
->addDataProperty(cx
, INT_TO_JSID(index
), slot
, JSPROP_ENUMERATE
)) {
3126 obj
->setDenseElement(index
, value
);
3130 JS_ASSERT(slot
== obj
->slotSpan() - 1);
3131 obj
->initSlot(slot
, value
);
3137 JSObject::sparsifyDenseElements(js::ExclusiveContext
*cx
, HandleObject obj
)
3139 if (!obj
->maybeCopyElementsForWrite(cx
))
3142 uint32_t initialized
= obj
->getDenseInitializedLength();
3144 /* Create new properties with the value of non-hole dense elements. */
3145 for (uint32_t i
= 0; i
< initialized
; i
++) {
3146 if (obj
->getDenseElement(i
).isMagic(JS_ELEMENTS_HOLE
))
3149 if (!sparsifyDenseElement(cx
, obj
, i
))
3154 obj
->setDenseInitializedLength(0);
3157 * Reduce storage for dense elements which are now holes. Explicitly mark
3158 * the elements capacity as zero, so that any attempts to add dense
3159 * elements will be caught in ensureDenseElements.
3161 if (obj
->getDenseCapacity()) {
3162 obj
->shrinkElements(cx
, 0);
3163 obj
->getElementsHeader()->capacity
= 0;
3170 JSObject::willBeSparseElements(uint32_t requiredCapacity
, uint32_t newElementsHint
)
3172 JS_ASSERT(isNative());
3173 JS_ASSERT(requiredCapacity
> MIN_SPARSE_INDEX
);
3175 uint32_t cap
= getDenseCapacity();
3176 JS_ASSERT(requiredCapacity
>= cap
);
3178 if (requiredCapacity
>= NELEMENTS_LIMIT
)
3181 uint32_t minimalDenseCount
= requiredCapacity
/ SPARSE_DENSITY_RATIO
;
3182 if (newElementsHint
>= minimalDenseCount
)
3184 minimalDenseCount
-= newElementsHint
;
3186 if (minimalDenseCount
> cap
)
3189 uint32_t len
= getDenseInitializedLength();
3190 const Value
*elems
= getDenseElements();
3191 for (uint32_t i
= 0; i
< len
; i
++) {
3192 if (!elems
[i
].isMagic(JS_ELEMENTS_HOLE
) && !--minimalDenseCount
)
3198 /* static */ JSObject::EnsureDenseResult
3199 JSObject::maybeDensifySparseElements(js::ExclusiveContext
*cx
, HandleObject obj
)
3202 * Wait until after the object goes into dictionary mode, which must happen
3203 * when sparsely packing any array with more than MIN_SPARSE_INDEX elements
3204 * (see PropertyTree::MAX_HEIGHT).
3206 if (!obj
->inDictionaryMode())
3210 * Only measure the number of indexed properties every log(n) times when
3211 * populating the object.
3213 uint32_t slotSpan
= obj
->slotSpan();
3214 if (slotSpan
!= RoundUpPow2(slotSpan
))
3217 /* Watch for conditions under which an object's elements cannot be dense. */
3218 if (!obj
->nonProxyIsExtensible() || obj
->watched())
3222 * The indexes in the object need to be sufficiently dense before they can
3223 * be converted to dense mode.
3225 uint32_t numDenseElements
= 0;
3226 uint32_t newInitializedLength
= 0;
3228 RootedShape
shape(cx
, obj
->lastProperty());
3229 while (!shape
->isEmptyShape()) {
3231 if (js_IdIsIndex(shape
->propid(), &index
)) {
3232 if (shape
->attributes() == JSPROP_ENUMERATE
&&
3233 shape
->hasDefaultGetter() &&
3234 shape
->hasDefaultSetter())
3237 newInitializedLength
= Max(newInitializedLength
, index
+ 1);
3240 * For simplicity, only densify the object if all indexed
3241 * properties can be converted to dense elements.
3246 shape
= shape
->previous();
3249 if (numDenseElements
* SPARSE_DENSITY_RATIO
< newInitializedLength
)
3252 if (newInitializedLength
>= NELEMENTS_LIMIT
)
3256 * This object meets all necessary restrictions, convert all indexed
3257 * properties into dense elements.
3260 if (!obj
->maybeCopyElementsForWrite(cx
))
3263 if (newInitializedLength
> obj
->getDenseCapacity()) {
3264 if (!obj
->growElements(cx
, newInitializedLength
))
3268 obj
->ensureDenseInitializedLength(cx
, newInitializedLength
, 0);
3270 RootedValue
value(cx
);
3272 shape
= obj
->lastProperty();
3273 while (!shape
->isEmptyShape()) {
3274 jsid id
= shape
->propid();
3276 if (js_IdIsIndex(id
, &index
)) {
3277 value
= obj
->getSlot(shape
->slot());
3280 * When removing a property from a dictionary, the specified
3281 * property will be removed from the dictionary list and the
3282 * last property will then be changed due to reshaping the object.
3283 * Compute the next shape in the traverse, watching for such
3284 * removals from the list.
3286 if (shape
!= obj
->lastProperty()) {
3287 shape
= shape
->previous();
3288 if (!obj
->removeProperty(cx
, id
))
3291 if (!obj
->removeProperty(cx
, id
))
3293 shape
= obj
->lastProperty();
3296 obj
->setDenseElement(index
, value
);
3298 shape
= shape
->previous();
3303 * All indexed properties on the object are now dense, clear the indexed
3304 * flag so that we will not start using sparse indexes again if we need
3305 * to grow the object.
3307 if (!obj
->clearFlag(cx
, BaseShape::INDEXED
))
3313 // This will not run the garbage collector. If a nursery cannot accomodate the element array
3314 // an attempt will be made to place the array in the tenured area.
3315 static ObjectElements
*
3316 AllocateElements(ThreadSafeContext
*cx
, JSObject
*obj
, uint32_t nelems
)
3318 #ifdef JSGC_GENERATIONAL
3319 if (cx
->isJSContext())
3320 return cx
->asJSContext()->runtime()->gc
.nursery
.allocateElements(obj
, nelems
);
3322 #ifdef JSGC_FJGENERATIONAL
3323 if (cx
->isForkJoinContext())
3324 return cx
->asForkJoinContext()->nursery().allocateElements(obj
, nelems
);
3327 return reinterpret_cast<js::ObjectElements
*>(obj
->pod_malloc
<HeapSlot
>(nelems
));
3330 // This will not run the garbage collector. If a nursery cannot accomodate the element array
3331 // an attempt will be made to place the array in the tenured area.
3332 static ObjectElements
*
3333 ReallocateElements(ThreadSafeContext
*cx
, JSObject
*obj
, ObjectElements
*oldHeader
,
3334 uint32_t oldCount
, uint32_t newCount
)
3336 #ifdef JSGC_GENERATIONAL
3337 if (cx
->isJSContext()) {
3338 return cx
->asJSContext()->runtime()->gc
.nursery
.reallocateElements(obj
, oldHeader
,
3339 oldCount
, newCount
);
3342 #ifdef JSGC_FJGENERATIONAL
3343 if (cx
->isForkJoinContext()) {
3344 return cx
->asForkJoinContext()->nursery().reallocateElements(obj
, oldHeader
,
3345 oldCount
, newCount
);
3349 return reinterpret_cast<js::ObjectElements
*>(
3350 obj
->pod_realloc
<HeapSlot
>(reinterpret_cast<HeapSlot
*>(oldHeader
),
3351 oldCount
, newCount
));
3354 // Round up |reqAllocated| to a good size. Up to 1 Mebi (i.e. 1,048,576) the
3355 // slot count is usually a power-of-two:
3357 // 8, 16, 32, 64, ..., 256 Ki, 512 Ki, 1 Mi
3359 // Beyond that, we use this formula:
3361 // count(n+1) = Math.ceil(count(n) * 1.125)
3363 // where |count(n)| is the size of the nth bucket measured in MiSlots.
3365 // These counts lets us add N elements to an array in amortized O(N) time.
3366 // Having the second class means that for bigger arrays the constant factor is
3367 // higher, but we waste less space.
3369 // There is one exception to the above rule: for the power-of-two cases, if the
3370 // chosen capacity would be 2/3 or more of the array's length, the chosen
3371 // capacity is adjusted (up or down) to be equal to the array's length
3372 // (assuming length is at least as large as the required capacity). This avoids
3373 // the allocation of excess elements which are unlikely to be needed, either in
3374 // this resizing or a subsequent one. The 2/3 factor is chosen so that
3375 // exceptional resizings will at most triple the capacity, as opposed to the
3378 /* static */ uint32_t
3379 JSObject::goodAllocated(uint32_t reqAllocated
, uint32_t length
= 0)
3381 static const uint32_t Mebi
= 1024 * 1024;
3383 // This table was generated with this JavaScript code and a small amount
3384 // subsequent reformatting:
3386 // for (let n = 1, i = 0; i < 57; i++) {
3387 // print((n * 1024 * 1024) + ', ');
3388 // n = Math.ceil(n * 1.125);
3392 // The final element is a sentinel value.
3393 static const uint32_t BigBuckets
[] = {
3394 1048576, 2097152, 3145728, 4194304, 5242880, 6291456, 7340032, 8388608,
3395 9437184, 11534336, 13631488, 15728640, 17825792, 20971520, 24117248,
3396 27262976, 31457280, 35651584, 40894464, 46137344, 52428800, 59768832,
3397 68157440, 77594624, 88080384, 99614720, 112197632, 126877696,
3398 143654912, 162529280, 183500800, 206569472, 232783872, 262144000,
3399 295698432, 333447168, 375390208, 422576128, 476053504, 535822336,
3400 602931200, 678428672, 763363328, 858783744, 966787072, 1088421888,
3401 1224736768, 1377828864, 1550843904, 1744830464, 1962934272, 2208301056,
3402 2485125120, 2796552192, 3146776576, 3541041152, 3984588800, 0
3405 // This code relies very much on |goodAllocated| being a uint32_t.
3406 uint32_t goodAllocated
= reqAllocated
;
3407 if (goodAllocated
< Mebi
) {
3408 goodAllocated
= RoundUpPow2(goodAllocated
);
3410 // Look for the abovementioned exception.
3411 uint32_t goodCapacity
= goodAllocated
- ObjectElements::VALUES_PER_HEADER
;
3412 uint32_t reqCapacity
= reqAllocated
- ObjectElements::VALUES_PER_HEADER
;
3413 if (length
>= reqCapacity
&& goodCapacity
> (length
/ 3) * 2)
3414 goodAllocated
= length
+ ObjectElements::VALUES_PER_HEADER
;
3416 if (goodAllocated
< JSObject::SLOT_CAPACITY_MIN
)
3417 goodAllocated
= JSObject::SLOT_CAPACITY_MIN
;
3422 uint32_t b
= BigBuckets
[i
++];
3423 if (b
>= goodAllocated
) {
3424 // Found the first bucket greater than or equal to
3428 } else if (b
== 0) {
3429 // Hit the end; return the maximum possible goodAllocated.
3430 goodAllocated
= 0xffffffff;
3436 return goodAllocated
;
3440 JSObject::growElements(ThreadSafeContext
*cx
, uint32_t reqCapacity
)
3442 JS_ASSERT(nonProxyIsExtensible());
3443 JS_ASSERT(canHaveNonEmptyElements());
3444 if (denseElementsAreCopyOnWrite())
3447 uint32_t oldCapacity
= getDenseCapacity();
3448 JS_ASSERT(oldCapacity
< reqCapacity
);
3450 using mozilla::CheckedInt
;
3452 CheckedInt
<uint32_t> checkedOldAllocated
=
3453 CheckedInt
<uint32_t>(oldCapacity
) + ObjectElements::VALUES_PER_HEADER
;
3454 CheckedInt
<uint32_t> checkedReqAllocated
=
3455 CheckedInt
<uint32_t>(reqCapacity
) + ObjectElements::VALUES_PER_HEADER
;
3456 if (!checkedOldAllocated
.isValid() || !checkedReqAllocated
.isValid())
3459 uint32_t reqAllocated
= checkedReqAllocated
.value();
3460 uint32_t oldAllocated
= checkedOldAllocated
.value();
3462 uint32_t newAllocated
;
3463 if (is
<ArrayObject
>() && !as
<ArrayObject
>().lengthIsWritable()) {
3464 JS_ASSERT(reqCapacity
<= as
<ArrayObject
>().length());
3465 // Preserve the |capacity <= length| invariant for arrays with
3466 // non-writable length. See also js::ArraySetLength which initially
3467 // enforces this requirement.
3468 newAllocated
= reqAllocated
;
3470 newAllocated
= goodAllocated(reqAllocated
, getElementsHeader()->length
);
3473 uint32_t newCapacity
= newAllocated
- ObjectElements::VALUES_PER_HEADER
;
3474 JS_ASSERT(newCapacity
> oldCapacity
&& newCapacity
>= reqCapacity
);
3476 // Don't let nelements get close to wrapping around uint32_t.
3477 if (newCapacity
>= NELEMENTS_LIMIT
)
3480 uint32_t initlen
= getDenseInitializedLength();
3482 ObjectElements
*newheader
;
3483 if (hasDynamicElements()) {
3484 newheader
= ReallocateElements(cx
, this, getElementsHeader(), oldAllocated
, newAllocated
);
3486 return false; // Leave elements at its old size.
3488 newheader
= AllocateElements(cx
, this, newAllocated
);
3490 return false; // Leave elements at its old size.
3491 js_memcpy(newheader
, getElementsHeader(),
3492 (ObjectElements::VALUES_PER_HEADER
+ initlen
) * sizeof(Value
));
3495 newheader
->capacity
= newCapacity
;
3496 elements
= newheader
->elements();
3498 Debug_SetSlotRangeToCrashOnTouch(elements
+ initlen
, newCapacity
- initlen
);
3504 JSObject::shrinkElements(ThreadSafeContext
*cx
, uint32_t reqCapacity
)
3506 JS_ASSERT(cx
->isThreadLocal(this));
3507 JS_ASSERT(canHaveNonEmptyElements());
3508 if (denseElementsAreCopyOnWrite())
3511 if (!hasDynamicElements())
3514 uint32_t oldCapacity
= getDenseCapacity();
3515 JS_ASSERT(reqCapacity
< oldCapacity
);
3517 uint32_t oldAllocated
= oldCapacity
+ ObjectElements::VALUES_PER_HEADER
;
3518 uint32_t reqAllocated
= reqCapacity
+ ObjectElements::VALUES_PER_HEADER
;
3519 uint32_t newAllocated
= goodAllocated(reqAllocated
);
3520 if (newAllocated
== oldAllocated
)
3521 return; // Leave elements at its old size.
3523 MOZ_ASSERT(newAllocated
> ObjectElements::VALUES_PER_HEADER
);
3524 uint32_t newCapacity
= newAllocated
- ObjectElements::VALUES_PER_HEADER
;
3526 ObjectElements
*newheader
= ReallocateElements(cx
, this, getElementsHeader(),
3527 oldAllocated
, newAllocated
);
3529 cx
->recoverFromOutOfMemory();
3530 return; // Leave elements at its old size.
3533 newheader
->capacity
= newCapacity
;
3534 elements
= newheader
->elements();
3538 JSObject::CopyElementsForWrite(ThreadSafeContext
*cx
, JSObject
*obj
)
3540 JS_ASSERT(obj
->denseElementsAreCopyOnWrite());
3542 // The original owner of a COW elements array should never be modified.
3543 JS_ASSERT(obj
->getElementsHeader()->ownerObject() != obj
);
3545 uint32_t initlen
= obj
->getDenseInitializedLength();
3546 uint32_t allocated
= initlen
+ ObjectElements::VALUES_PER_HEADER
;
3547 uint32_t newAllocated
= goodAllocated(allocated
);
3549 uint32_t newCapacity
= newAllocated
- ObjectElements::VALUES_PER_HEADER
;
3551 if (newCapacity
>= NELEMENTS_LIMIT
)
3554 JSObject::writeBarrierPre(obj
->getElementsHeader()->ownerObject());
3556 ObjectElements
*newheader
= AllocateElements(cx
, obj
, newAllocated
);
3559 js_memcpy(newheader
, obj
->getElementsHeader(),
3560 (ObjectElements::VALUES_PER_HEADER
+ initlen
) * sizeof(Value
));
3562 newheader
->capacity
= newCapacity
;
3563 newheader
->clearCopyOnWrite();
3564 obj
->elements
= newheader
->elements();
3566 Debug_SetSlotRangeToCrashOnTouch(obj
->elements
+ initlen
, newCapacity
- initlen
);
3572 js::SetClassAndProto(JSContext
*cx
, HandleObject obj
,
3573 const Class
*clasp
, Handle
<js::TaggedProto
> proto
,
3577 * Regenerate shapes for all of the scopes along the old prototype chain,
3578 * in case any entries were filled by looking up through obj. Stop when a
3579 * non-native object is found, prototype lookups will not be cached across
3582 * How this shape change is done is very delicate; the change can be made
3583 * either by marking the object's prototype as uncacheable (such that the
3584 * property cache and JIT'ed ICs cannot assume the shape determines the
3585 * prototype) or by just generating a new shape for the object. Choosing
3586 * the former is bad if the object is on the prototype chain of other
3587 * objects, as the uncacheable prototype can inhibit iterator caches on
3588 * those objects and slow down prototype accesses. Choosing the latter is
3589 * bad if there are many similar objects to this one which will have their
3590 * prototype mutated, as the generateOwnShape forces the object into
3591 * dictionary mode and similar property lineages will be repeatedly cloned.
3593 * :XXX: bug 707717 make this code less brittle.
3596 RootedObject
oldproto(cx
, obj
);
3597 while (oldproto
&& oldproto
->isNative()) {
3598 if (oldproto
->hasSingletonType()) {
3599 if (!oldproto
->generateOwnShape(cx
))
3602 if (!oldproto
->setUncacheableProto(cx
))
3605 oldproto
= oldproto
->getProto();
3608 if (obj
->hasSingletonType()) {
3610 * Just splice the prototype, but mark the properties as unknown for
3611 * consistent behavior.
3613 if (!obj
->splicePrototype(cx
, clasp
, proto
))
3615 MarkTypeObjectUnknownProperties(cx
, obj
->type());
3620 if (proto
.isObject()) {
3621 RootedObject
protoObj(cx
, proto
.toObject());
3622 if (!JSObject::setNewTypeUnknown(cx
, clasp
, protoObj
))
3626 TypeObject
*type
= cx
->getNewType(clasp
, proto
);
3631 * Setting __proto__ on an object that has escaped and may be referenced by
3632 * other heap objects can only be done if the properties of both objects
3633 * are unknown. Type sets containing this object will contain the original
3634 * type but not the new type of the object, so we need to go and scan the
3635 * entire compartment for type sets which have these objects and mark them
3636 * as containing generic objects.
3638 MarkTypeObjectUnknownProperties(cx
, obj
->type(), true);
3639 MarkTypeObjectUnknownProperties(cx
, type
, true);
3648 MaybeResolveConstructor(ExclusiveContext
*cxArg
, Handle
<GlobalObject
*> global
, JSProtoKey key
)
3650 if (global
->isStandardClassResolved(key
))
3652 if (!cxArg
->shouldBeJSContext())
3655 JSContext
*cx
= cxArg
->asJSContext();
3656 return GlobalObject::resolveConstructor(cx
, global
, key
);
3660 js::GetBuiltinConstructor(ExclusiveContext
*cx
, JSProtoKey key
, MutableHandleObject objp
)
3662 MOZ_ASSERT(key
!= JSProto_Null
);
3663 Rooted
<GlobalObject
*> global(cx
, cx
->global());
3664 if (!MaybeResolveConstructor(cx
, global
, key
))
3667 objp
.set(&global
->getConstructor(key
).toObject());
3672 js::GetBuiltinPrototype(ExclusiveContext
*cx
, JSProtoKey key
, MutableHandleObject protop
)
3674 MOZ_ASSERT(key
!= JSProto_Null
);
3675 Rooted
<GlobalObject
*> global(cx
, cx
->global());
3676 if (!MaybeResolveConstructor(cx
, global
, key
))
3679 protop
.set(&global
->getPrototype(key
).toObject());
3684 IsStandardPrototype(JSObject
*obj
, JSProtoKey key
)
3686 GlobalObject
&global
= obj
->global();
3687 Value v
= global
.getPrototype(key
);
3688 return v
.isObject() && obj
== &v
.toObject();
3692 JS::IdentifyStandardInstance(JSObject
*obj
)
3694 // Note: The prototype shares its JSClass with instances.
3695 JS_ASSERT(!obj
->is
<CrossCompartmentWrapperObject
>());
3696 JSProtoKey key
= StandardProtoKeyOrNull(obj
);
3697 if (key
!= JSProto_Null
&& !IsStandardPrototype(obj
, key
))
3699 return JSProto_Null
;
3703 JS::IdentifyStandardPrototype(JSObject
*obj
)
3705 // Note: The prototype shares its JSClass with instances.
3706 JS_ASSERT(!obj
->is
<CrossCompartmentWrapperObject
>());
3707 JSProtoKey key
= StandardProtoKeyOrNull(obj
);
3708 if (key
!= JSProto_Null
&& IsStandardPrototype(obj
, key
))
3710 return JSProto_Null
;
3714 JS::IdentifyStandardInstanceOrPrototype(JSObject
*obj
)
3716 return StandardProtoKeyOrNull(obj
);
3720 JS::IdentifyStandardConstructor(JSObject
*obj
)
3722 // Note that NATIVE_CTOR does not imply that we are a standard constructor,
3723 // but the converse is true (at least until we start having self-hosted
3724 // constructors for standard classes). This lets us avoid a costly loop for
3725 // many functions (which, depending on the call site, may be the common case).
3726 if (!obj
->is
<JSFunction
>() || !(obj
->as
<JSFunction
>().flags() & JSFunction::NATIVE_CTOR
))
3727 return JSProto_Null
;
3729 GlobalObject
&global
= obj
->global();
3730 for (size_t k
= 0; k
< JSProto_LIMIT
; ++k
) {
3731 JSProtoKey key
= static_cast<JSProtoKey
>(k
);
3732 if (global
.getConstructor(key
) == ObjectValue(*obj
))
3736 return JSProto_Null
;
3740 js::FindClassObject(ExclusiveContext
*cx
, MutableHandleObject protop
, const Class
*clasp
)
3742 JSProtoKey protoKey
= ClassProtoKeyOrAnonymousOrNull(clasp
);
3743 if (protoKey
!= JSProto_Null
) {
3744 JS_ASSERT(JSProto_Null
< protoKey
);
3745 JS_ASSERT(protoKey
< JSProto_LIMIT
);
3746 return GetBuiltinConstructor(cx
, protoKey
, protop
);
3749 JSAtom
*atom
= Atomize(cx
, clasp
->name
, strlen(clasp
->name
));
3752 RootedId
id(cx
, AtomToId(atom
));
3754 RootedObject
pobj(cx
);
3755 RootedShape
shape(cx
);
3756 if (!LookupNativeProperty(cx
, cx
->global(), id
, &pobj
, &shape
))
3759 if (shape
&& pobj
->isNative()) {
3760 if (shape
->hasSlot())
3761 v
= pobj
->nativeGetSlot(shape
->slot());
3764 protop
.set(&v
.toObject());
3769 JSObject::isConstructor() const
3771 if (is
<JSFunction
>()) {
3772 const JSFunction
&fun
= as
<JSFunction
>();
3773 return fun
.isNativeConstructor() || fun
.isInterpretedConstructor();
3775 return getClass()->construct
!= nullptr;
3779 JSObject::allocSlot(ThreadSafeContext
*cx
, HandleObject obj
, uint32_t *slotp
)
3781 JS_ASSERT(cx
->isThreadLocal(obj
));
3783 uint32_t slot
= obj
->slotSpan();
3784 JS_ASSERT(slot
>= JSSLOT_FREE(obj
->getClass()));
3787 * If this object is in dictionary mode, try to pull a free slot from the
3788 * shape table's slot-number freelist.
3790 if (obj
->inDictionaryMode()) {
3791 ShapeTable
&table
= obj
->lastProperty()->table();
3792 uint32_t last
= table
.freelist
;
3793 if (last
!= SHAPE_INVALID_SLOT
) {
3795 JS_ASSERT(last
< slot
);
3796 uint32_t next
= obj
->getSlot(last
).toPrivateUint32();
3797 JS_ASSERT_IF(next
!= SHAPE_INVALID_SLOT
, next
< slot
);
3802 const Value
&vref
= obj
->getSlot(last
);
3803 table
.freelist
= vref
.toPrivateUint32();
3804 obj
->setSlot(last
, UndefinedValue());
3809 if (slot
>= SHAPE_MAXIMUM_SLOT
) {
3810 js_ReportOutOfMemory(cx
);
3816 if (obj
->inDictionaryMode() && !setSlotSpan(cx
, obj
, slot
+ 1))
3823 JSObject::freeSlot(uint32_t slot
)
3825 JS_ASSERT(slot
< slotSpan());
3827 if (inDictionaryMode()) {
3828 uint32_t &last
= lastProperty()->table().freelist
;
3830 /* Can't afford to check the whole freelist, but let's check the head. */
3831 JS_ASSERT_IF(last
!= SHAPE_INVALID_SLOT
, last
< slotSpan() && last
!= slot
);
3834 * Place all freed slots other than reserved slots (bug 595230) on the
3835 * dictionary's free list.
3837 if (JSSLOT_FREE(getClass()) <= slot
) {
3838 JS_ASSERT_IF(last
!= SHAPE_INVALID_SLOT
, last
< slotSpan());
3839 setSlot(slot
, PrivateUint32Value(last
));
3844 setSlot(slot
, UndefinedValue());
3848 PurgeProtoChain(ExclusiveContext
*cx
, JSObject
*objArg
, HandleId id
)
3850 /* Root locally so we can re-assign. */
3851 RootedObject
obj(cx
, objArg
);
3853 RootedShape
shape(cx
);
3855 /* Lookups will not be cached through non-native protos. */
3856 if (!obj
->isNative())
3859 shape
= obj
->nativeLookup(cx
, id
);
3861 if (!obj
->shadowingShapeChange(cx
, *shape
))
3864 obj
->shadowingShapeChange(cx
, *shape
);
3867 obj
= obj
->getProto();
3874 PurgeScopeChainHelper(ExclusiveContext
*cx
, HandleObject objArg
, HandleId id
)
3876 /* Re-root locally so we can re-assign. */
3877 RootedObject
obj(cx
, objArg
);
3879 JS_ASSERT(obj
->isNative());
3880 JS_ASSERT(obj
->isDelegate());
3882 /* Lookups on integer ids cannot be cached through prototypes. */
3883 if (JSID_IS_INT(id
))
3886 PurgeProtoChain(cx
, obj
->getProto(), id
);
3889 * We must purge the scope chain only for Call objects as they are the only
3890 * kind of cacheable non-global object that can gain properties after outer
3891 * properties with the same names have been cached or traced. Call objects
3892 * may gain such properties via eval introducing new vars; see bug 490364.
3894 if (obj
->is
<CallObject
>()) {
3895 while ((obj
= obj
->enclosingScope()) != nullptr) {
3896 if (!PurgeProtoChain(cx
, obj
, id
))
3905 * PurgeScopeChain does nothing if obj is not itself a prototype or parent
3906 * scope, else it reshapes the scope and prototype chains it links. It calls
3907 * PurgeScopeChainHelper, which asserts that obj is flagged as a delegate
3908 * (i.e., obj has ever been on a prototype or parent chain).
3911 PurgeScopeChain(ExclusiveContext
*cx
, JS::HandleObject obj
, JS::HandleId id
)
3913 if (obj
->isDelegate())
3914 return PurgeScopeChainHelper(cx
, obj
, id
);
3919 baseops::DefineGeneric(ExclusiveContext
*cx
, HandleObject obj
, HandleId id
, HandleValue value
,
3920 PropertyOp getter
, StrictPropertyOp setter
, unsigned attrs
)
3922 return DefineNativeProperty(cx
, obj
, id
, value
, getter
, setter
, attrs
);
3926 JSObject::defineGeneric(ExclusiveContext
*cx
, HandleObject obj
,
3927 HandleId id
, HandleValue value
,
3928 JSPropertyOp getter
, JSStrictPropertyOp setter
, unsigned attrs
)
3930 JS_ASSERT(!(attrs
& JSPROP_NATIVE_ACCESSORS
));
3931 js::DefineGenericOp op
= obj
->getOps()->defineGeneric
;
3933 if (!cx
->shouldBeJSContext())
3935 return op(cx
->asJSContext(), obj
, id
, value
, getter
, setter
, attrs
);
3937 return baseops::DefineGeneric(cx
, obj
, id
, value
, getter
, setter
, attrs
);
3941 JSObject::defineProperty(ExclusiveContext
*cx
, HandleObject obj
,
3942 PropertyName
*name
, HandleValue value
,
3943 JSPropertyOp getter
, JSStrictPropertyOp setter
, unsigned attrs
)
3945 RootedId
id(cx
, NameToId(name
));
3946 return defineGeneric(cx
, obj
, id
, value
, getter
, setter
, attrs
);
3950 baseops::DefineElement(ExclusiveContext
*cx
, HandleObject obj
, uint32_t index
, HandleValue value
,
3951 PropertyOp getter
, StrictPropertyOp setter
, unsigned attrs
)
3954 if (index
<= JSID_INT_MAX
) {
3955 id
= INT_TO_JSID(index
);
3956 return DefineNativeProperty(cx
, obj
, id
, value
, getter
, setter
, attrs
);
3959 AutoRooterGetterSetter
gsRoot(cx
, attrs
, &getter
, &setter
);
3961 if (!IndexToId(cx
, index
, &id
))
3964 return DefineNativeProperty(cx
, obj
, id
, value
, getter
, setter
, attrs
);
3968 JSObject::defineElement(ExclusiveContext
*cx
, HandleObject obj
,
3969 uint32_t index
, HandleValue value
,
3970 JSPropertyOp getter
, JSStrictPropertyOp setter
, unsigned attrs
)
3972 js::DefineElementOp op
= obj
->getOps()->defineElement
;
3974 if (!cx
->shouldBeJSContext())
3976 return op(cx
->asJSContext(), obj
, index
, value
, getter
, setter
, attrs
);
3978 return baseops::DefineElement(cx
, obj
, index
, value
, getter
, setter
, attrs
);
3982 JSObject::addDataProperty(ExclusiveContext
*cx
, jsid idArg
, uint32_t slot
, unsigned attrs
)
3984 JS_ASSERT(!(attrs
& (JSPROP_GETTER
| JSPROP_SETTER
)));
3985 RootedObject
self(cx
, this);
3986 RootedId
id(cx
, idArg
);
3987 return addProperty(cx
, self
, id
, nullptr, nullptr, slot
, attrs
, 0);
3991 JSObject::addDataProperty(ExclusiveContext
*cx
, HandlePropertyName name
,
3992 uint32_t slot
, unsigned attrs
)
3994 JS_ASSERT(!(attrs
& (JSPROP_GETTER
| JSPROP_SETTER
)));
3995 RootedObject
self(cx
, this);
3996 RootedId
id(cx
, NameToId(name
));
3997 return addProperty(cx
, self
, id
, nullptr, nullptr, slot
, attrs
, 0);
4001 * Backward compatibility requires allowing addProperty hooks to mutate the
4002 * nominal initial value of a slotful property, while GC safety wants that
4003 * value to be stored before the call-out through the hook. Optimize to do
4004 * both while saving cycles for classes that stub their addProperty hook.
4006 template <ExecutionMode mode
>
4008 CallAddPropertyHook(typename ExecutionModeTraits
<mode
>::ExclusiveContextType cxArg
,
4009 const Class
*clasp
, HandleObject obj
, HandleShape shape
,
4010 HandleValue nominal
)
4012 if (clasp
->addProperty
!= JS_PropertyStub
) {
4013 if (mode
== ParallelExecution
)
4016 ExclusiveContext
*cx
= cxArg
->asExclusiveContext();
4017 if (!cx
->shouldBeJSContext())
4020 /* Make a local copy of value so addProperty can mutate its inout parameter. */
4021 RootedValue
value(cx
, nominal
);
4023 Rooted
<jsid
> id(cx
, shape
->propid());
4024 if (!CallJSPropertyOp(cx
->asJSContext(), clasp
->addProperty
, obj
, id
, &value
)) {
4025 obj
->removeProperty(cx
, shape
->propid());
4028 if (value
.get() != nominal
) {
4029 if (shape
->hasSlot())
4030 obj
->nativeSetSlotWithType(cx
, shape
, value
);
4036 template <ExecutionMode mode
>
4038 CallAddPropertyHookDense(typename ExecutionModeTraits
<mode
>::ExclusiveContextType cxArg
,
4039 const Class
*clasp
, HandleObject obj
, uint32_t index
,
4040 HandleValue nominal
)
4042 /* Inline addProperty for array objects. */
4043 if (obj
->is
<ArrayObject
>()) {
4044 ArrayObject
*arr
= &obj
->as
<ArrayObject
>();
4045 uint32_t length
= arr
->length();
4046 if (index
>= length
) {
4047 if (mode
== ParallelExecution
) {
4048 /* We cannot deal with overflows in parallel. */
4049 if (length
> INT32_MAX
)
4051 arr
->setLengthInt32(index
+ 1);
4053 arr
->setLength(cxArg
->asExclusiveContext(), index
+ 1);
4059 if (clasp
->addProperty
!= JS_PropertyStub
) {
4060 if (mode
== ParallelExecution
)
4063 ExclusiveContext
*cx
= cxArg
->asExclusiveContext();
4064 if (!cx
->shouldBeJSContext())
4067 if (!obj
->maybeCopyElementsForWrite(cx
))
4070 /* Make a local copy of value so addProperty can mutate its inout parameter. */
4071 RootedValue
value(cx
, nominal
);
4073 Rooted
<jsid
> id(cx
, INT_TO_JSID(index
));
4074 if (!CallJSPropertyOp(cx
->asJSContext(), clasp
->addProperty
, obj
, id
, &value
)) {
4075 obj
->setDenseElementHole(cx
, index
);
4078 if (value
.get() != nominal
)
4079 obj
->setDenseElementWithType(cx
, index
, value
);
4085 template <ExecutionMode mode
>
4087 UpdateShapeTypeAndValue(typename ExecutionModeTraits
<mode
>::ExclusiveContextType cx
,
4088 JSObject
*obj
, Shape
*shape
, const Value
&value
)
4090 jsid id
= shape
->propid();
4091 if (shape
->hasSlot()) {
4092 if (mode
== ParallelExecution
) {
4093 if (!obj
->nativeSetSlotIfHasType(shape
, value
, /* overwriting = */ false))
4096 obj
->nativeSetSlotWithType(cx
->asExclusiveContext(), shape
, value
, /* overwriting = */ false);
4099 if (!shape
->hasSlot() || !shape
->hasDefaultGetter() || !shape
->hasDefaultSetter()) {
4100 if (mode
== ParallelExecution
) {
4101 if (!IsTypePropertyIdMarkedNonData(obj
, id
))
4104 MarkTypePropertyNonData(cx
->asExclusiveContext(), obj
, id
);
4107 if (!shape
->writable()) {
4108 if (mode
== ParallelExecution
) {
4109 if (!IsTypePropertyIdMarkedNonWritable(obj
, id
))
4112 MarkTypePropertyNonWritable(cx
->asExclusiveContext(), obj
, id
);
4118 template <ExecutionMode mode
>
4120 DefinePropertyOrElement(typename ExecutionModeTraits
<mode
>::ExclusiveContextType cx
,
4121 HandleObject obj
, HandleId id
,
4122 PropertyOp getter
, StrictPropertyOp setter
,
4123 unsigned attrs
, HandleValue value
,
4124 bool callSetterAfterwards
, bool setterIsStrict
)
4126 /* Use dense storage for new indexed properties where possible. */
4127 if (JSID_IS_INT(id
) &&
4128 getter
== JS_PropertyStub
&&
4129 setter
== JS_StrictPropertyStub
&&
4130 attrs
== JSPROP_ENUMERATE
&&
4131 (!obj
->isIndexed() || !obj
->nativeContainsPure(id
)) &&
4132 !obj
->is
<TypedArrayObject
>())
4134 uint32_t index
= JSID_TO_INT(id
);
4136 if (!WouldDefinePastNonwritableLength(cx
, obj
, index
, setterIsStrict
, &definesPast
))
4141 JSObject::EnsureDenseResult result
;
4142 if (mode
== ParallelExecution
) {
4143 if (obj
->writeToIndexWouldMarkNotPacked(index
))
4145 result
= obj
->ensureDenseElementsPreservePackedFlag(cx
, index
, 1);
4147 result
= obj
->ensureDenseElements(cx
->asExclusiveContext(), index
, 1);
4150 if (result
== JSObject::ED_FAILED
)
4152 if (result
== JSObject::ED_OK
) {
4153 if (mode
== ParallelExecution
) {
4154 if (!obj
->setDenseElementIfHasType(index
, value
))
4157 obj
->setDenseElementWithType(cx
->asExclusiveContext(), index
, value
);
4159 return CallAddPropertyHookDense
<mode
>(cx
, obj
->getClass(), obj
, index
, value
);
4163 if (obj
->is
<ArrayObject
>()) {
4164 Rooted
<ArrayObject
*> arr(cx
, &obj
->as
<ArrayObject
>());
4165 if (id
== NameToId(cx
->names().length
)) {
4166 if (mode
== SequentialExecution
&& !cx
->shouldBeJSContext())
4168 return ArraySetLength
<mode
>(ExecutionModeTraits
<mode
>::toContextType(cx
), arr
, id
,
4169 attrs
, value
, setterIsStrict
);
4173 if (js_IdIsIndex(id
, &index
)) {
4175 if (!WouldDefinePastNonwritableLength(cx
, arr
, index
, setterIsStrict
, &definesPast
))
4182 // Don't define new indexed properties on typed arrays.
4183 if (obj
->is
<TypedArrayObject
>()) {
4185 if (IsTypedArrayIndex(id
, &index
))
4189 AutoRooterGetterSetter
gsRoot(cx
, attrs
, &getter
, &setter
);
4191 RootedShape
shape(cx
, JSObject::putProperty
<mode
>(cx
, obj
, id
, getter
, setter
,
4192 SHAPE_INVALID_SLOT
, attrs
, 0));
4196 if (!UpdateShapeTypeAndValue
<mode
>(cx
, obj
, shape
, value
))
4200 * Clear any existing dense index after adding a sparse indexed property,
4201 * and investigate converting the object to dense indexes.
4203 if (JSID_IS_INT(id
)) {
4204 if (mode
== ParallelExecution
)
4207 if (!obj
->maybeCopyElementsForWrite(cx
))
4210 ExclusiveContext
*ncx
= cx
->asExclusiveContext();
4211 uint32_t index
= JSID_TO_INT(id
);
4212 JSObject::removeDenseElementForSparseIndex(ncx
, obj
, index
);
4213 JSObject::EnsureDenseResult result
= JSObject::maybeDensifySparseElements(ncx
, obj
);
4214 if (result
== JSObject::ED_FAILED
)
4216 if (result
== JSObject::ED_OK
) {
4217 JS_ASSERT(setter
== JS_StrictPropertyStub
);
4218 return CallAddPropertyHookDense
<mode
>(cx
, obj
->getClass(), obj
, index
, value
);
4222 if (!CallAddPropertyHook
<mode
>(cx
, obj
->getClass(), obj
, shape
, value
))
4225 if (callSetterAfterwards
&& setter
!= JS_StrictPropertyStub
) {
4226 if (!cx
->shouldBeJSContext())
4228 RootedValue
nvalue(cx
, value
);
4229 return NativeSet
<mode
>(ExecutionModeTraits
<mode
>::toContextType(cx
),
4230 obj
, obj
, shape
, setterIsStrict
, &nvalue
);
4236 NativeLookupOwnProperty(ExclusiveContext
*cx
, HandleObject obj
, HandleId id
,
4237 MutableHandle
<Shape
*> shapep
);
4240 js::DefineNativeProperty(ExclusiveContext
*cx
, HandleObject obj
, HandleId id
, HandleValue value
,
4241 PropertyOp getter
, StrictPropertyOp setter
, unsigned attrs
)
4243 JS_ASSERT(!(attrs
& JSPROP_NATIVE_ACCESSORS
));
4245 AutoRooterGetterSetter
gsRoot(cx
, attrs
, &getter
, &setter
);
4247 RootedShape
shape(cx
);
4248 RootedValue
updateValue(cx
, value
);
4249 bool shouldDefine
= true;
4252 * If defining a getter or setter, we must check for its counterpart and
4253 * update the attributes and property ops. A getter or setter is really
4254 * only half of a property.
4256 if (attrs
& (JSPROP_GETTER
| JSPROP_SETTER
)) {
4257 if (!NativeLookupOwnProperty(cx
, obj
, id
, &shape
))
4261 * If we are defining a getter whose setter was already defined, or
4262 * vice versa, finish the job via obj->changeProperty.
4264 if (IsImplicitDenseOrTypedArrayElement(shape
)) {
4265 if (obj
->is
<TypedArrayObject
>()) {
4266 /* Ignore getter/setter properties added to typed arrays. */
4269 if (!JSObject::sparsifyDenseElement(cx
, obj
, JSID_TO_INT(id
)))
4271 shape
= obj
->nativeLookup(cx
, id
);
4273 if (shape
->isAccessorDescriptor()) {
4274 attrs
= ApplyOrDefaultAttributes(attrs
, shape
);
4275 shape
= JSObject::changeProperty
<SequentialExecution
>(cx
, obj
, shape
, attrs
,
4276 JSPROP_GETTER
| JSPROP_SETTER
,
4277 (attrs
& JSPROP_GETTER
)
4280 (attrs
& JSPROP_SETTER
)
4285 shouldDefine
= false;
4288 } else if (!(attrs
& JSPROP_IGNORE_VALUE
)) {
4290 * We might still want to ignore redefining some of our attributes, if the
4291 * request came through a proxy after Object.defineProperty(), but only if we're redefining
4293 * FIXME: All this logic should be removed when Proxies use PropDesc, but we need to
4294 * remove JSPropertyOp getters and setters first.
4295 * FIXME: This is still wrong for various array types, and will set the wrong attributes
4296 * by accident, but we can't use NativeLookupOwnProperty in this case, because of resolve
4299 shape
= obj
->nativeLookup(cx
, id
);
4300 if (shape
&& shape
->isDataDescriptor())
4301 attrs
= ApplyOrDefaultAttributes(attrs
, shape
);
4304 * We have been asked merely to update some attributes by a caller of
4305 * Object.defineProperty, laundered through the proxy system, and returning here. We can
4306 * get away with just using JSObject::changeProperty here.
4308 if (!NativeLookupOwnProperty(cx
, obj
, id
, &shape
))
4312 // Don't forget about arrays.
4313 if (IsImplicitDenseOrTypedArrayElement(shape
)) {
4314 if (obj
->is
<TypedArrayObject
>()) {
4316 * Silently ignore attempts to change individial index attributes.
4317 * FIXME: Uses the same broken behavior as for accessors. This should
4322 if (!JSObject::sparsifyDenseElement(cx
, obj
, JSID_TO_INT(id
)))
4324 shape
= obj
->nativeLookup(cx
, id
);
4327 attrs
= ApplyOrDefaultAttributes(attrs
, shape
);
4329 if (shape
->isAccessorDescriptor() && !(attrs
& JSPROP_IGNORE_READONLY
)) {
4330 // ES6 draft 2014-10-14 9.1.6.3 step 7.c: Since [[Writable]]
4331 // is present, change the existing accessor property to a data
4333 updateValue
= UndefinedValue();
4335 // We are at most changing some attributes, and cannot convert
4336 // from data descriptor to accessor, or vice versa. Take
4337 // everything from the shape that we aren't changing.
4338 uint32_t propMask
= JSPROP_ENUMERATE
| JSPROP_READONLY
| JSPROP_PERMANENT
;
4339 attrs
= (shape
->attributes() & ~propMask
) | (attrs
& propMask
);
4340 getter
= shape
->getter();
4341 setter
= shape
->setter();
4342 if (shape
->hasSlot())
4343 updateValue
= obj
->getSlot(shape
->slot());
4349 * Purge the property cache of any properties named by id that are about
4350 * to be shadowed in obj's scope chain.
4352 if (!PurgeScopeChain(cx
, obj
, id
))
4355 /* Use the object's class getter and setter by default. */
4356 const Class
*clasp
= obj
->getClass();
4357 if (!getter
&& !(attrs
& JSPROP_GETTER
))
4358 getter
= clasp
->getProperty
;
4359 if (!setter
&& !(attrs
& JSPROP_SETTER
))
4360 setter
= clasp
->setProperty
;
4363 // Handle the default cases here. Anyone that wanted to set non-default attributes has
4364 // cleared the IGNORE flags by now. Since we can never get here with JSPROP_IGNORE_VALUE
4365 // relevant, just clear it.
4366 attrs
= ApplyOrDefaultAttributes(attrs
) & ~JSPROP_IGNORE_VALUE
;
4367 return DefinePropertyOrElement
<SequentialExecution
>(cx
, obj
, id
, getter
, setter
,
4368 attrs
, updateValue
, false, false);
4373 JS_ALWAYS_TRUE(UpdateShapeTypeAndValue
<SequentialExecution
>(cx
, obj
, shape
, updateValue
));
4375 return CallAddPropertyHook
<SequentialExecution
>(cx
, clasp
, obj
, shape
, updateValue
);
4379 * Call obj's resolve hook.
4381 * cx, id, and flags are the parameters initially passed to the ongoing lookup;
4382 * objp and propp are its out parameters. obj is an object along the prototype
4383 * chain from where the lookup started.
4385 * There are four possible outcomes:
4387 * - On failure, report an error or exception and return false.
4389 * - If we are already resolving a property of *curobjp, set *recursedp = true,
4392 * - If the resolve hook finds or defines the sought property, set *objp and
4393 * *propp appropriately, set *recursedp = false, and return true.
4395 * - Otherwise no property was resolved. Set *propp = nullptr and
4396 * *recursedp = false and return true.
4398 static MOZ_ALWAYS_INLINE
bool
4399 CallResolveOp(JSContext
*cx
, HandleObject obj
, HandleId id
, MutableHandleObject objp
,
4400 MutableHandleShape propp
, bool *recursedp
)
4402 const Class
*clasp
= obj
->getClass();
4403 JSResolveOp resolve
= clasp
->resolve
;
4406 * Avoid recursion on (obj, id) already being resolved on cx.
4408 * Once we have successfully added an entry for (obj, key) to
4409 * cx->resolvingTable, control must go through cleanup: before
4410 * returning. But note that JS_DHASH_ADD may find an existing
4411 * entry, in which case we bail to suppress runaway recursion.
4413 AutoResolving
resolving(cx
, obj
, id
);
4414 if (resolving
.alreadyStarted()) {
4415 /* Already resolving id in obj -- suppress recursion. */
4423 if (clasp
->flags
& JSCLASS_NEW_RESOLVE
) {
4424 JSNewResolveOp newresolve
= reinterpret_cast<JSNewResolveOp
>(resolve
);
4425 RootedObject
obj2(cx
, nullptr);
4426 if (!newresolve(cx
, obj
, id
, &obj2
))
4430 * We trust the new style resolve hook to set obj2 to nullptr when
4431 * the id cannot be resolved. But, when obj2 is not null, we do
4432 * not assume that id must exist and do full nativeLookup for
4438 if (!obj2
->isNative()) {
4439 /* Whoops, newresolve handed back a foreign obj2. */
4440 JS_ASSERT(obj2
!= obj
);
4441 return JSObject::lookupGeneric(cx
, obj2
, id
, objp
, propp
);
4446 if (!resolve(cx
, obj
, id
))
4452 if (JSID_IS_INT(id
) && objp
->containsDenseElement(JSID_TO_INT(id
))) {
4453 MarkDenseOrTypedArrayElementFound
<CanGC
>(propp
);
4458 if (!objp
->nativeEmpty() && (shape
= objp
->nativeLookup(cx
, id
)))
4466 template <AllowGC allowGC
>
4467 static MOZ_ALWAYS_INLINE
bool
4468 LookupOwnPropertyInline(ExclusiveContext
*cx
,
4469 typename MaybeRooted
<JSObject
*, allowGC
>::HandleType obj
,
4470 typename MaybeRooted
<jsid
, allowGC
>::HandleType id
,
4471 typename MaybeRooted
<JSObject
*, allowGC
>::MutableHandleType objp
,
4472 typename MaybeRooted
<Shape
*, allowGC
>::MutableHandleType propp
,
4475 // Check for a native dense element.
4476 if (JSID_IS_INT(id
) && obj
->containsDenseElement(JSID_TO_INT(id
))) {
4478 MarkDenseOrTypedArrayElementFound
<allowGC
>(propp
);
4483 // Check for a typed array element. Integer lookups always finish here
4484 // so that integer properties on the prototype are ignored even for out
4485 // of bounds accesses.
4486 if (obj
->template is
<TypedArrayObject
>()) {
4488 if (IsTypedArrayIndex(id
, &index
)) {
4489 if (index
< obj
->template as
<TypedArrayObject
>().length()) {
4491 MarkDenseOrTypedArrayElementFound
<allowGC
>(propp
);
4501 // Check for a native property.
4502 if (Shape
*shape
= obj
->nativeLookup(cx
, id
)) {
4509 // id was not found in obj. Try obj's resolve hook, if any.
4510 if (obj
->getClass()->resolve
!= JS_ResolveStub
) {
4511 if (!cx
->shouldBeJSContext() || !allowGC
)
4515 if (!CallResolveOp(cx
->asJSContext(),
4516 MaybeRooted
<JSObject
*, allowGC
>::toHandle(obj
),
4517 MaybeRooted
<jsid
, allowGC
>::toHandle(id
),
4518 MaybeRooted
<JSObject
*, allowGC
>::toMutableHandle(objp
),
4519 MaybeRooted
<Shape
*, allowGC
>::toMutableHandle(propp
),
4543 NativeLookupOwnProperty(ExclusiveContext
*cx
, HandleObject obj
, HandleId id
,
4544 MutableHandle
<Shape
*> shapep
)
4546 RootedObject
pobj(cx
);
4549 if (!LookupOwnPropertyInline
<CanGC
>(cx
, obj
, id
, &pobj
, shapep
, &done
))
4551 if (!done
|| pobj
!= obj
)
4552 shapep
.set(nullptr);
4556 template <AllowGC allowGC
>
4557 static MOZ_ALWAYS_INLINE
bool
4558 LookupPropertyInline(ExclusiveContext
*cx
,
4559 typename MaybeRooted
<JSObject
*, allowGC
>::HandleType obj
,
4560 typename MaybeRooted
<jsid
, allowGC
>::HandleType id
,
4561 typename MaybeRooted
<JSObject
*, allowGC
>::MutableHandleType objp
,
4562 typename MaybeRooted
<Shape
*, allowGC
>::MutableHandleType propp
)
4564 /* NB: The logic of this procedure is implicitly reflected in
4565 * BaselineIC.cpp's |EffectlesslyLookupProperty| logic.
4566 * If this changes, please remember to update the logic there as well.
4569 /* Search scopes starting with obj and following the prototype link. */
4570 typename MaybeRooted
<JSObject
*, allowGC
>::RootType
current(cx
, obj
);
4574 if (!LookupOwnPropertyInline
<allowGC
>(cx
, current
, id
, objp
, propp
, &done
))
4579 typename MaybeRooted
<JSObject
*, allowGC
>::RootType
proto(cx
, current
->getProto());
4583 if (!proto
->isNative()) {
4584 if (!cx
->shouldBeJSContext() || !allowGC
)
4586 return JSObject::lookupGeneric(cx
->asJSContext(),
4587 MaybeRooted
<JSObject
*, allowGC
>::toHandle(proto
),
4588 MaybeRooted
<jsid
, allowGC
>::toHandle(id
),
4589 MaybeRooted
<JSObject
*, allowGC
>::toMutableHandle(objp
),
4590 MaybeRooted
<Shape
*, allowGC
>::toMutableHandle(propp
));
4601 template <AllowGC allowGC
>
4603 baseops::LookupProperty(ExclusiveContext
*cx
,
4604 typename MaybeRooted
<JSObject
*, allowGC
>::HandleType obj
,
4605 typename MaybeRooted
<jsid
, allowGC
>::HandleType id
,
4606 typename MaybeRooted
<JSObject
*, allowGC
>::MutableHandleType objp
,
4607 typename MaybeRooted
<Shape
*, allowGC
>::MutableHandleType propp
)
4609 return LookupPropertyInline
<allowGC
>(cx
, obj
, id
, objp
, propp
);
4613 baseops::LookupProperty
<CanGC
>(ExclusiveContext
*cx
, HandleObject obj
, HandleId id
,
4614 MutableHandleObject objp
, MutableHandleShape propp
);
4617 baseops::LookupProperty
<NoGC
>(ExclusiveContext
*cx
, JSObject
*obj
, jsid id
,
4618 FakeMutableHandle
<JSObject
*> objp
,
4619 FakeMutableHandle
<Shape
*> propp
);
4622 JSObject::lookupGeneric(JSContext
*cx
, HandleObject obj
, js::HandleId id
,
4623 MutableHandleObject objp
, MutableHandleShape propp
)
4625 /* NB: The logic of lookupGeneric is implicitly reflected in
4626 * BaselineIC.cpp's |EffectlesslyLookupProperty| logic.
4627 * If this changes, please remember to update the logic there as well.
4629 LookupGenericOp op
= obj
->getOps()->lookupGeneric
;
4631 return op(cx
, obj
, id
, objp
, propp
);
4632 return baseops::LookupProperty
<js::CanGC
>(cx
, obj
, id
, objp
, propp
);
4636 baseops::LookupElement(JSContext
*cx
, HandleObject obj
, uint32_t index
,
4637 MutableHandleObject objp
, MutableHandleShape propp
)
4640 if (!IndexToId(cx
, index
, &id
))
4643 return LookupPropertyInline
<CanGC
>(cx
, obj
, id
, objp
, propp
);
4647 js::LookupNativeProperty(ExclusiveContext
*cx
, HandleObject obj
, HandleId id
,
4648 MutableHandleObject objp
, MutableHandleShape propp
)
4650 return LookupPropertyInline
<CanGC
>(cx
, obj
, id
, objp
, propp
);
4654 js::LookupName(JSContext
*cx
, HandlePropertyName name
, HandleObject scopeChain
,
4655 MutableHandleObject objp
, MutableHandleObject pobjp
, MutableHandleShape propp
)
4657 RootedId
id(cx
, NameToId(name
));
4659 for (RootedObject
scope(cx
, scopeChain
); scope
; scope
= scope
->enclosingScope()) {
4660 if (!JSObject::lookupGeneric(cx
, scope
, id
, pobjp
, propp
))
4675 js::LookupNameNoGC(JSContext
*cx
, PropertyName
*name
, JSObject
*scopeChain
,
4676 JSObject
**objp
, JSObject
**pobjp
, Shape
**propp
)
4678 AutoAssertNoException
nogc(cx
);
4680 JS_ASSERT(!*objp
&& !*pobjp
&& !*propp
);
4682 for (JSObject
*scope
= scopeChain
; scope
; scope
= scope
->enclosingScope()) {
4683 if (scope
->getOps()->lookupGeneric
)
4685 if (!LookupPropertyInline
<NoGC
>(cx
, scope
, NameToId(name
), pobjp
, propp
))
4697 js::LookupNameWithGlobalDefault(JSContext
*cx
, HandlePropertyName name
, HandleObject scopeChain
,
4698 MutableHandleObject objp
)
4700 RootedId
id(cx
, NameToId(name
));
4702 RootedObject
pobj(cx
);
4703 RootedShape
prop(cx
);
4705 RootedObject
scope(cx
, scopeChain
);
4706 for (; !scope
->is
<GlobalObject
>(); scope
= scope
->enclosingScope()) {
4707 if (!JSObject::lookupGeneric(cx
, scope
, id
, &pobj
, &prop
))
4718 js::LookupNameUnqualified(JSContext
*cx
, HandlePropertyName name
, HandleObject scopeChain
,
4719 MutableHandleObject objp
)
4721 RootedId
id(cx
, NameToId(name
));
4723 RootedObject
pobj(cx
);
4724 RootedShape
prop(cx
);
4726 RootedObject
scope(cx
, scopeChain
);
4727 for (; !scope
->isUnqualifiedVarObj(); scope
= scope
->enclosingScope()) {
4728 if (!JSObject::lookupGeneric(cx
, scope
, id
, &pobj
, &prop
))
4738 template <AllowGC allowGC
>
4740 js::HasOwnProperty(JSContext
*cx
, LookupGenericOp lookup
,
4741 typename MaybeRooted
<JSObject
*, allowGC
>::HandleType obj
,
4742 typename MaybeRooted
<jsid
, allowGC
>::HandleType id
,
4743 typename MaybeRooted
<JSObject
*, allowGC
>::MutableHandleType objp
,
4744 typename MaybeRooted
<Shape
*, allowGC
>::MutableHandleType propp
)
4750 MaybeRooted
<JSObject
*, allowGC
>::toHandle(obj
),
4751 MaybeRooted
<jsid
, allowGC
>::toHandle(id
),
4752 MaybeRooted
<JSObject
*, allowGC
>::toMutableHandle(objp
),
4753 MaybeRooted
<Shape
*, allowGC
>::toMutableHandle(propp
)))
4759 if (!LookupOwnPropertyInline
<allowGC
>(cx
, obj
, id
, objp
, propp
, &done
))
4774 JSObject
*outer
= nullptr;
4775 if (js::ObjectOp op
= objp
->getClass()->ext
.outerObject
) {
4778 RootedObject
inner(cx
, objp
);
4779 outer
= op(cx
, inner
);
4790 js::HasOwnProperty
<CanGC
>(JSContext
*cx
, LookupGenericOp lookup
,
4791 HandleObject obj
, HandleId id
,
4792 MutableHandleObject objp
, MutableHandleShape propp
);
4795 js::HasOwnProperty
<NoGC
>(JSContext
*cx
, LookupGenericOp lookup
,
4796 JSObject
*obj
, jsid id
,
4797 FakeMutableHandle
<JSObject
*> objp
, FakeMutableHandle
<Shape
*> propp
);
4800 js::HasOwnProperty(JSContext
*cx
, HandleObject obj
, HandleId id
, bool *resultp
)
4802 RootedObject
pobj(cx
);
4803 RootedShape
shape(cx
);
4804 if (!HasOwnProperty
<CanGC
>(cx
, obj
->getOps()->lookupGeneric
, obj
, id
, &pobj
, &shape
))
4806 *resultp
= (shape
!= nullptr);
4810 template <AllowGC allowGC
>
4811 static MOZ_ALWAYS_INLINE
bool
4812 NativeGetInline(JSContext
*cx
,
4813 typename MaybeRooted
<JSObject
*, allowGC
>::HandleType obj
,
4814 typename MaybeRooted
<JSObject
*, allowGC
>::HandleType receiver
,
4815 typename MaybeRooted
<JSObject
*, allowGC
>::HandleType pobj
,
4816 typename MaybeRooted
<Shape
*, allowGC
>::HandleType shape
,
4817 typename MaybeRooted
<Value
, allowGC
>::MutableHandleType vp
)
4819 JS_ASSERT(pobj
->isNative());
4821 if (shape
->hasSlot()) {
4822 vp
.set(pobj
->nativeGetSlot(shape
->slot()));
4823 JS_ASSERT(!vp
.isMagic());
4824 JS_ASSERT_IF(!pobj
->hasSingletonType() &&
4825 !pobj
->template is
<ScopeObject
>() &&
4826 shape
->hasDefaultGetter(),
4827 js::types::TypeHasProperty(cx
, pobj
->type(), shape
->propid(), vp
));
4831 if (shape
->hasDefaultGetter())
4836 JSScript
*script
= cx
->currentScript(&pc
);
4837 if (script
&& script
->hasBaselineScript()) {
4838 switch (JSOp(*pc
)) {
4842 script
->baselineScript()->noteAccessedGetter(script
->pcToOffset(pc
));
4854 MaybeRooted
<JSObject
*, allowGC
>::toHandle(receiver
),
4855 MaybeRooted
<JSObject
*, allowGC
>::toHandle(obj
),
4856 MaybeRooted
<JSObject
*, allowGC
>::toHandle(pobj
),
4857 MaybeRooted
<Value
, allowGC
>::toMutableHandle(vp
)))
4862 /* Update slotful shapes according to the value produced by the getter. */
4863 if (shape
->hasSlot() && pobj
->nativeContains(cx
, shape
))
4864 pobj
->nativeSetSlot(shape
->slot(), vp
);
4870 js::NativeGet(JSContext
*cx
, Handle
<JSObject
*> obj
, Handle
<JSObject
*> pobj
, Handle
<Shape
*> shape
,
4871 MutableHandle
<Value
> vp
)
4873 return NativeGetInline
<CanGC
>(cx
, obj
, obj
, pobj
, shape
, vp
);
4876 template <ExecutionMode mode
>
4878 js::NativeSet(typename ExecutionModeTraits
<mode
>::ContextType cxArg
,
4879 Handle
<JSObject
*> obj
, Handle
<JSObject
*> receiver
,
4880 HandleShape shape
, bool strict
, MutableHandleValue vp
)
4882 JS_ASSERT(cxArg
->isThreadLocal(obj
));
4883 JS_ASSERT(obj
->isNative());
4885 if (shape
->hasSlot()) {
4886 /* If shape has a stub setter, just store vp. */
4887 if (shape
->hasDefaultSetter()) {
4888 if (mode
== ParallelExecution
) {
4889 if (!obj
->nativeSetSlotIfHasType(shape
, vp
))
4892 obj
->nativeSetSlotWithType(cxArg
->asExclusiveContext(), shape
, vp
);
4899 if (mode
== ParallelExecution
)
4901 JSContext
*cx
= cxArg
->asJSContext();
4903 if (!shape
->hasSlot()) {
4905 * Allow API consumers to create shared properties with stub setters.
4906 * Such properties effectively function as data descriptors which are
4907 * not writable, so attempting to set such a property should do nothing
4908 * or throw if we're in strict mode.
4910 if (!shape
->hasGetterValue() && shape
->hasDefaultSetter())
4911 return js_ReportGetterOnlyAssignment(cx
, strict
);
4914 RootedValue
ovp(cx
, vp
);
4916 uint32_t sample
= cx
->runtime()->propertyRemovals
;
4917 if (!shape
->set(cx
, obj
, receiver
, strict
, vp
))
4921 * Update any slot for the shape with the value produced by the setter,
4922 * unless the setter deleted the shape.
4924 if (shape
->hasSlot() &&
4925 (MOZ_LIKELY(cx
->runtime()->propertyRemovals
== sample
) ||
4926 obj
->nativeContains(cx
, shape
)))
4928 obj
->setSlot(shape
->slot(), vp
);
4935 js::NativeSet
<SequentialExecution
>(JSContext
*cx
,
4936 Handle
<JSObject
*> obj
, Handle
<JSObject
*> receiver
,
4937 HandleShape shape
, bool strict
, MutableHandleValue vp
);
4939 js::NativeSet
<ParallelExecution
>(ForkJoinContext
*cx
,
4940 Handle
<JSObject
*> obj
, Handle
<JSObject
*> receiver
,
4941 HandleShape shape
, bool strict
, MutableHandleValue vp
);
4943 template <AllowGC allowGC
>
4944 static MOZ_ALWAYS_INLINE
bool
4945 GetPropertyHelperInline(JSContext
*cx
,
4946 typename MaybeRooted
<JSObject
*, allowGC
>::HandleType obj
,
4947 typename MaybeRooted
<JSObject
*, allowGC
>::HandleType receiver
,
4948 typename MaybeRooted
<jsid
, allowGC
>::HandleType id
,
4949 typename MaybeRooted
<Value
, allowGC
>::MutableHandleType vp
)
4951 /* This call site is hot -- use the always-inlined variant of LookupNativeProperty(). */
4952 typename MaybeRooted
<JSObject
*, allowGC
>::RootType
obj2(cx
);
4953 typename MaybeRooted
<Shape
*, allowGC
>::RootType
shape(cx
);
4954 if (!LookupPropertyInline
<allowGC
>(cx
, obj
, id
, &obj2
, &shape
))
4963 if (!CallJSPropertyOp(cx
, obj
->getClass()->getProperty
,
4964 MaybeRooted
<JSObject
*, allowGC
>::toHandle(obj
),
4965 MaybeRooted
<jsid
, allowGC
>::toHandle(id
),
4966 MaybeRooted
<Value
, allowGC
>::toMutableHandle(vp
)))
4972 * Give a strict warning if foo.bar is evaluated by a script for an
4973 * object foo with no property named 'bar'.
4975 if (vp
.isUndefined()) {
4976 jsbytecode
*pc
= nullptr;
4977 RootedScript
script(cx
, cx
->currentScript(&pc
));
4980 JSOp op
= (JSOp
) *pc
;
4982 if (op
== JSOP_GETXPROP
) {
4983 /* Undefined property during a name lookup, report an error. */
4984 JSAutoByteString printable
;
4985 if (js_ValueToPrintable(cx
, IdToValue(id
), &printable
))
4986 js_ReportIsNotDefined(cx
, printable
.ptr());
4990 /* Don't warn if extra warnings not enabled or for random getprop operations. */
4991 if (!cx
->compartment()->options().extraWarnings(cx
) || (op
!= JSOP_GETPROP
&& op
!= JSOP_GETELEM
))
4994 /* Don't warn repeatedly for the same script. */
4995 if (!script
|| script
->warnedAboutUndefinedProp())
4999 * Don't warn in self-hosted code (where the further presence of
5000 * JS::RuntimeOptions::werror() would result in impossible-to-avoid
5001 * errors to entirely-innocent client code).
5003 if (script
->selfHosted())
5006 /* We may just be checking if that object has an iterator. */
5007 if (JSID_IS_ATOM(id
, cx
->names().iteratorIntrinsic
))
5010 /* Do not warn about tests like (obj[prop] == undefined). */
5011 pc
+= js_CodeSpec
[op
].length
;
5012 if (Detecting(cx
, script
, pc
))
5015 unsigned flags
= JSREPORT_WARNING
| JSREPORT_STRICT
;
5016 script
->setWarnedAboutUndefinedProp();
5018 /* Ok, bad undefined property reference: whine about it. */
5019 RootedValue
val(cx
, IdToValue(id
));
5020 if (!js_ReportValueErrorFlags(cx
, flags
, JSMSG_UNDEFINED_PROP
,
5021 JSDVG_IGNORE_STACK
, val
, js::NullPtr(),
5030 if (!obj2
->isNative()) {
5033 HandleObject obj2Handle
= MaybeRooted
<JSObject
*, allowGC
>::toHandle(obj2
);
5034 HandleObject receiverHandle
= MaybeRooted
<JSObject
*, allowGC
>::toHandle(receiver
);
5035 HandleId idHandle
= MaybeRooted
<jsid
, allowGC
>::toHandle(id
);
5036 MutableHandleValue vpHandle
= MaybeRooted
<Value
, allowGC
>::toMutableHandle(vp
);
5037 return obj2
->template is
<ProxyObject
>()
5038 ? Proxy::get(cx
, obj2Handle
, receiverHandle
, idHandle
, vpHandle
)
5039 : JSObject::getGeneric(cx
, obj2Handle
, obj2Handle
, idHandle
, vpHandle
);
5042 if (IsImplicitDenseOrTypedArrayElement(shape
)) {
5043 vp
.set(obj2
->getDenseOrTypedArrayElement(JSID_TO_INT(id
)));
5047 /* This call site is hot -- use the always-inlined variant of NativeGet(). */
5048 if (!NativeGetInline
<allowGC
>(cx
, obj
, receiver
, obj2
, shape
, vp
))
5055 baseops::GetProperty(JSContext
*cx
, HandleObject obj
, HandleObject receiver
, HandleId id
, MutableHandleValue vp
)
5057 /* This call site is hot -- use the always-inlined variant of GetPropertyHelper(). */
5058 return GetPropertyHelperInline
<CanGC
>(cx
, obj
, receiver
, id
, vp
);
5062 baseops::GetPropertyNoGC(JSContext
*cx
, JSObject
*obj
, JSObject
*receiver
, jsid id
, Value
*vp
)
5064 AutoAssertNoException
nogc(cx
);
5065 return GetPropertyHelperInline
<NoGC
>(cx
, obj
, receiver
, id
, vp
);
5068 static MOZ_ALWAYS_INLINE
bool
5069 LookupPropertyPureInline(JSObject
*obj
, jsid id
, JSObject
**objp
, Shape
**propp
)
5071 if (!obj
->isNative())
5074 JSObject
*current
= obj
;
5076 /* Search for a native dense element, typed array element, or property. */
5078 if (JSID_IS_INT(id
) && current
->containsDenseElement(JSID_TO_INT(id
))) {
5080 MarkDenseOrTypedArrayElementFound
<NoGC
>(propp
);
5084 if (current
->is
<TypedArrayObject
>()) {
5086 if (IsTypedArrayIndex(id
, &index
)) {
5087 if (index
< obj
->as
<TypedArrayObject
>().length()) {
5089 MarkDenseOrTypedArrayElementFound
<NoGC
>(propp
);
5098 if (Shape
*shape
= current
->nativeLookupPure(id
)) {
5104 /* Fail if there's a resolve hook. */
5105 if (current
->getClass()->resolve
!= JS_ResolveStub
)
5108 JSObject
*proto
= current
->getProto();
5112 if (!proto
->isNative())
5123 static MOZ_ALWAYS_INLINE
bool
5124 NativeGetPureInline(JSObject
*pobj
, Shape
*shape
, Value
*vp
)
5126 JS_ASSERT(pobj
->isNative());
5128 if (shape
->hasSlot()) {
5129 *vp
= pobj
->nativeGetSlot(shape
->slot());
5130 JS_ASSERT(!vp
->isMagic());
5135 /* Fail if we have a custom getter. */
5136 return shape
->hasDefaultGetter();
5140 js::LookupPropertyPure(JSObject
*obj
, jsid id
, JSObject
**objp
, Shape
**propp
)
5142 return LookupPropertyPureInline(obj
, id
, objp
, propp
);
5146 * A pure version of GetPropertyHelper that can be called from parallel code
5147 * without locking. This code path cannot GC. This variant returns false
5148 * whenever a side-effect might have occured in the effectful version. This
5149 * includes, but is not limited to:
5151 * - Any object in the lookup chain has a non-stub resolve hook.
5152 * - Any object in the lookup chain is non-native.
5153 * - The property has a getter.
5156 js::GetPropertyPure(ThreadSafeContext
*cx
, JSObject
*obj
, jsid id
, Value
*vp
)
5158 /* Deal with native objects. */
5161 if (!LookupPropertyPureInline(obj
, id
, &obj2
, &shape
))
5165 /* Fail if we have a non-stub class op hooks. */
5166 if (obj
->getClass()->getProperty
&& obj
->getClass()->getProperty
!= JS_PropertyStub
)
5169 if (obj
->getOps()->getElement
)
5172 /* Vanilla native object, return undefined. */
5177 if (IsImplicitDenseOrTypedArrayElement(shape
)) {
5178 *vp
= obj2
->getDenseOrTypedArrayElement(JSID_TO_INT(id
));
5182 /* Special case 'length' on Array and TypedArray. */
5183 if (JSID_IS_ATOM(id
, cx
->names().length
)) {
5184 if (obj
->is
<ArrayObject
>()) {
5185 vp
->setNumber(obj
->as
<ArrayObject
>().length());
5189 if (obj
->is
<TypedArrayObject
>()) {
5190 vp
->setNumber(obj
->as
<TypedArrayObject
>().length());
5195 return NativeGetPureInline(obj2
, shape
, vp
);
5200 GetElementPure(ThreadSafeContext
*cx
, JSObject
*obj
, uint32_t index
, Value
*vp
)
5202 if (index
<= JSID_INT_MAX
)
5203 return GetPropertyPure(cx
, obj
, INT_TO_JSID(index
), vp
);
5208 * A pure version of GetObjectElementOperation that can be called from
5209 * parallel code without locking. This variant returns false whenever a
5210 * side-effect might have occurred.
5213 js::GetObjectElementOperationPure(ThreadSafeContext
*cx
, JSObject
*obj
, const Value
&prop
,
5217 if (IsDefinitelyIndex(prop
, &index
))
5218 return GetElementPure(cx
, obj
, index
, vp
);
5220 /* Atomizing the property value is effectful and not threadsafe. */
5221 if (!prop
.isString() || !prop
.toString()->isAtom())
5224 JSAtom
*name
= &prop
.toString()->asAtom();
5225 if (name
->isIndex(&index
))
5226 return GetElementPure(cx
, obj
, index
, vp
);
5228 return GetPropertyPure(cx
, obj
, NameToId(name
->asPropertyName()), vp
);
5232 baseops::GetElement(JSContext
*cx
, HandleObject obj
, HandleObject receiver
, uint32_t index
,
5233 MutableHandleValue vp
)
5236 if (!IndexToId(cx
, index
, &id
))
5239 /* This call site is hot -- use the always-inlined variant of js_GetPropertyHelper(). */
5240 return GetPropertyHelperInline
<CanGC
>(cx
, obj
, receiver
, id
, vp
);
5244 MaybeReportUndeclaredVarAssignment(JSContext
*cx
, JSString
*propname
)
5247 JSScript
*script
= cx
->currentScript(nullptr, JSContext::ALLOW_CROSS_COMPARTMENT
);
5251 // If the code is not strict and extra warnings aren't enabled, then no
5253 if (!script
->strict() && !cx
->compartment()->options().extraWarnings(cx
))
5257 JSAutoByteString
bytes(cx
, propname
);
5259 JS_ReportErrorFlagsAndNumber(cx
,
5260 (JSREPORT_WARNING
| JSREPORT_STRICT
5261 | JSREPORT_STRICT_MODE_ERROR
),
5262 js_GetErrorMessage
, nullptr,
5263 JSMSG_UNDECLARED_VAR
, bytes
.ptr());
5267 JSObject::reportReadOnly(ThreadSafeContext
*cxArg
, jsid id
, unsigned report
)
5269 if (cxArg
->isForkJoinContext())
5270 return cxArg
->asForkJoinContext()->reportError(report
);
5272 if (!cxArg
->isJSContext())
5275 JSContext
*cx
= cxArg
->asJSContext();
5276 RootedValue
val(cx
, IdToValue(id
));
5277 return js_ReportValueErrorFlags(cx
, report
, JSMSG_READ_ONLY
,
5278 JSDVG_IGNORE_STACK
, val
, js::NullPtr(),
5283 JSObject::reportNotConfigurable(ThreadSafeContext
*cxArg
, jsid id
, unsigned report
)
5285 if (cxArg
->isForkJoinContext())
5286 return cxArg
->asForkJoinContext()->reportError(report
);
5288 if (!cxArg
->isJSContext())
5291 JSContext
*cx
= cxArg
->asJSContext();
5292 RootedValue
val(cx
, IdToValue(id
));
5293 return js_ReportValueErrorFlags(cx
, report
, JSMSG_CANT_DELETE
,
5294 JSDVG_IGNORE_STACK
, val
, js::NullPtr(),
5299 JSObject::reportNotExtensible(ThreadSafeContext
*cxArg
, unsigned report
)
5301 if (cxArg
->isForkJoinContext())
5302 return cxArg
->asForkJoinContext()->reportError(report
);
5304 if (!cxArg
->isJSContext())
5307 JSContext
*cx
= cxArg
->asJSContext();
5308 RootedValue
val(cx
, ObjectValue(*this));
5309 return js_ReportValueErrorFlags(cx
, report
, JSMSG_OBJECT_NOT_EXTENSIBLE
,
5310 JSDVG_IGNORE_STACK
, val
, js::NullPtr(),
5315 JSObject::callMethod(JSContext
*cx
, HandleId id
, unsigned argc
, Value
*argv
, MutableHandleValue vp
)
5317 RootedValue
fval(cx
);
5318 RootedObject
obj(cx
, this);
5319 if (!JSObject::getGeneric(cx
, obj
, obj
, id
, &fval
))
5321 return Invoke(cx
, ObjectValue(*obj
), fval
, argc
, argv
, vp
);
5324 template <ExecutionMode mode
>
5326 baseops::SetPropertyHelper(typename ExecutionModeTraits
<mode
>::ContextType cxArg
,
5327 HandleObject obj
, HandleObject receiver
, HandleId id
,
5328 QualifiedBool qualified
, MutableHandleValue vp
, bool strict
)
5330 JS_ASSERT(cxArg
->isThreadLocal(obj
));
5332 if (MOZ_UNLIKELY(obj
->watched())) {
5333 if (mode
== ParallelExecution
)
5336 /* Fire watchpoints, if any. */
5337 JSContext
*cx
= cxArg
->asJSContext();
5338 WatchpointMap
*wpmap
= cx
->compartment()->watchpointMap
;
5339 if (wpmap
&& !wpmap
->triggerWatchpoint(cx
, obj
, id
, vp
))
5343 RootedObject
pobj(cxArg
);
5344 RootedShape
shape(cxArg
);
5345 if (mode
== ParallelExecution
) {
5346 if (!LookupPropertyPure(obj
, id
, pobj
.address(), shape
.address()))
5349 JSContext
*cx
= cxArg
->asJSContext();
5350 if (!LookupNativeProperty(cx
, obj
, id
, &pobj
, &shape
))
5354 if (!pobj
->isNative()) {
5355 if (pobj
->is
<ProxyObject
>()) {
5356 if (mode
== ParallelExecution
)
5359 JSContext
*cx
= cxArg
->asJSContext();
5360 Rooted
<PropertyDescriptor
> pd(cx
);
5361 if (!Proxy::getPropertyDescriptor(cx
, pobj
, id
, &pd
))
5364 if ((pd
.attributes() & (JSPROP_SHARED
| JSPROP_SHADOWABLE
)) == JSPROP_SHARED
) {
5365 return !pd
.setter() ||
5366 CallSetter(cx
, receiver
, id
, pd
.setter(), pd
.attributes(), strict
, vp
);
5369 if (pd
.isReadonly()) {
5371 return JSObject::reportReadOnly(cx
, id
, JSREPORT_ERROR
);
5372 if (cx
->compartment()->options().extraWarnings(cx
))
5373 return JSObject::reportReadOnly(cx
, id
, JSREPORT_STRICT
| JSREPORT_WARNING
);
5381 /* We should never add properties to lexical blocks. */
5382 JS_ASSERT(!obj
->is
<BlockObject
>());
5384 if (obj
->isUnqualifiedVarObj() && !qualified
) {
5385 if (mode
== ParallelExecution
)
5388 if (!MaybeReportUndeclaredVarAssignment(cxArg
->asJSContext(), JSID_TO_STRING(id
)))
5394 * Now either shape is null, meaning id was not found in obj or one of its
5395 * prototypes; or shape is non-null, meaning id was found directly in pobj.
5397 unsigned attrs
= JSPROP_ENUMERATE
;
5398 const Class
*clasp
= obj
->getClass();
5399 PropertyOp getter
= clasp
->getProperty
;
5400 StrictPropertyOp setter
= clasp
->setProperty
;
5402 if (IsImplicitDenseOrTypedArrayElement(shape
)) {
5403 /* ES5 8.12.4 [[Put]] step 2, for a dense data property on pobj. */
5407 /* ES5 8.12.4 [[Put]] step 2. */
5408 if (shape
->isAccessorDescriptor()) {
5409 if (shape
->hasDefaultSetter()) {
5410 /* Bail out of parallel execution if we are strict to throw. */
5411 if (mode
== ParallelExecution
)
5414 return js_ReportGetterOnlyAssignment(cxArg
->asJSContext(), strict
);
5417 JS_ASSERT(shape
->isDataDescriptor());
5419 if (!shape
->writable()) {
5421 * Error in strict mode code, warn with extra warnings
5422 * options, otherwise do nothing.
5424 * Bail out of parallel execution if we are strict to throw.
5426 if (mode
== ParallelExecution
)
5429 JSContext
*cx
= cxArg
->asJSContext();
5431 return JSObject::reportReadOnly(cx
, id
, JSREPORT_ERROR
);
5432 if (cx
->compartment()->options().extraWarnings(cx
))
5433 return JSObject::reportReadOnly(cx
, id
, JSREPORT_STRICT
| JSREPORT_WARNING
);
5438 attrs
= shape
->attributes();
5441 * We found id in a prototype object: prepare to share or shadow.
5443 if (!shape
->shadowable()) {
5444 if (shape
->hasDefaultSetter() && !shape
->hasGetterValue())
5447 if (mode
== ParallelExecution
)
5450 return shape
->set(cxArg
->asJSContext(), obj
, receiver
, strict
, vp
);
5454 * Preserve attrs except JSPROP_SHARED, getter, and setter when
5455 * shadowing any property that has no slot (is shared). We must
5456 * clear the shared attribute for the shadowing shape so that the
5457 * property in obj that it defines has a slot to retain the value
5458 * being set, in case the setter simply cannot operate on instances
5459 * of obj's class by storing the value in some class-specific
5462 if (!shape
->hasSlot()) {
5463 attrs
&= ~JSPROP_SHARED
;
5464 getter
= shape
->getter();
5465 setter
= shape
->setter();
5467 /* Restore attrs to the ECMA default for new properties. */
5468 attrs
= JSPROP_ENUMERATE
;
5472 * Forget we found the proto-property now that we've copied any
5473 * needed member values.
5479 if (IsImplicitDenseOrTypedArrayElement(shape
)) {
5480 uint32_t index
= JSID_TO_INT(id
);
5482 if (obj
->is
<TypedArrayObject
>()) {
5484 if (mode
== ParallelExecution
) {
5485 // Bail if converting the value might invoke user-defined
5489 if (!NonObjectToNumber(cxArg
, vp
, &d
))
5492 if (!ToNumber(cxArg
->asJSContext(), vp
, &d
))
5496 // Silently do nothing for out-of-bounds sets, for consistency with
5497 // current behavior. (ES6 currently says to throw for this in
5498 // strict mode code, so we may eventually need to change.)
5499 TypedArrayObject
&tarray
= obj
->as
<TypedArrayObject
>();
5500 if (index
< tarray
.length())
5501 TypedArrayObject::setElement(tarray
, index
, d
);
5506 if (!WouldDefinePastNonwritableLength(cxArg
, obj
, index
, strict
, &definesPast
))
5509 /* Bail out of parallel execution if we are strict to throw. */
5510 if (mode
== ParallelExecution
)
5515 if (!obj
->maybeCopyElementsForWrite(cxArg
))
5518 if (mode
== ParallelExecution
)
5519 return obj
->setDenseElementIfHasType(index
, vp
);
5521 obj
->setDenseElementWithType(cxArg
->asJSContext(), index
, vp
);
5525 if (obj
->is
<ArrayObject
>() && id
== NameToId(cxArg
->names().length
)) {
5526 Rooted
<ArrayObject
*> arr(cxArg
, &obj
->as
<ArrayObject
>());
5527 return ArraySetLength
<mode
>(cxArg
, arr
, id
, attrs
, vp
, strict
);
5532 if (mode
== ParallelExecution
) {
5533 if (obj
->is
<ProxyObject
>())
5535 extensible
= obj
->nonProxyIsExtensible();
5537 if (!JSObject::isExtensible(cxArg
->asJSContext(), obj
, &extensible
))
5542 /* Error in strict mode code, warn with extra warnings option, otherwise do nothing. */
5544 return obj
->reportNotExtensible(cxArg
);
5545 if (mode
== SequentialExecution
&&
5546 cxArg
->asJSContext()->compartment()->options().extraWarnings(cxArg
->asJSContext()))
5548 return obj
->reportNotExtensible(cxArg
, JSREPORT_STRICT
| JSREPORT_WARNING
);
5553 if (mode
== ParallelExecution
) {
5554 if (obj
->isDelegate())
5557 if (getter
!= JS_PropertyStub
|| !HasTypePropertyId(obj
, id
, vp
))
5560 JSContext
*cx
= cxArg
->asJSContext();
5562 /* Purge the property cache of now-shadowed id in obj's scope chain. */
5563 if (!PurgeScopeChain(cx
, obj
, id
))
5567 return DefinePropertyOrElement
<mode
>(cxArg
, obj
, id
, getter
, setter
,
5568 attrs
, vp
, true, strict
);
5571 return NativeSet
<mode
>(cxArg
, obj
, receiver
, shape
, strict
, vp
);
5575 baseops::SetPropertyHelper
<SequentialExecution
>(JSContext
*cx
, HandleObject obj
,
5576 HandleObject receiver
, HandleId id
,
5577 QualifiedBool qualified
,
5578 MutableHandleValue vp
, bool strict
);
5580 baseops::SetPropertyHelper
<ParallelExecution
>(ForkJoinContext
*cx
, HandleObject obj
,
5581 HandleObject receiver
, HandleId id
,
5582 QualifiedBool qualified
,
5583 MutableHandleValue vp
, bool strict
);
5586 baseops::SetElementHelper(JSContext
*cx
, HandleObject obj
, HandleObject receiver
, uint32_t index
,
5587 MutableHandleValue vp
, bool strict
)
5590 if (!IndexToId(cx
, index
, &id
))
5592 return baseops::SetPropertyHelper
<SequentialExecution
>(cx
, obj
, receiver
, id
, Qualified
, vp
,
5597 baseops::GetAttributes(JSContext
*cx
, HandleObject obj
, HandleId id
, unsigned *attrsp
)
5599 RootedObject
nobj(cx
);
5600 RootedShape
shape(cx
);
5601 if (!baseops::LookupProperty
<CanGC
>(cx
, obj
, id
, &nobj
, &shape
))
5607 if (!nobj
->isNative())
5608 return JSObject::getGenericAttributes(cx
, nobj
, id
, attrsp
);
5610 *attrsp
= GetShapeAttributes(nobj
, shape
);
5615 baseops::SetAttributes(JSContext
*cx
, HandleObject obj
, HandleId id
, unsigned *attrsp
)
5617 RootedObject
nobj(cx
);
5618 RootedShape
shape(cx
);
5619 if (!baseops::LookupProperty
<CanGC
>(cx
, obj
, id
, &nobj
, &shape
))
5623 if (nobj
->isNative() && IsImplicitDenseOrTypedArrayElement(shape
)) {
5624 if (nobj
->is
<TypedArrayObject
>()) {
5625 if (*attrsp
== (JSPROP_ENUMERATE
| JSPROP_PERMANENT
))
5627 JS_ReportErrorNumber(cx
, js_GetErrorMessage
, nullptr, JSMSG_CANT_SET_ARRAY_ATTRS
);
5630 if (!JSObject::sparsifyDenseElement(cx
, nobj
, JSID_TO_INT(id
)))
5632 shape
= obj
->nativeLookup(cx
, id
);
5634 if (nobj
->isNative()) {
5635 if (!JSObject::changePropertyAttributes(cx
, nobj
, shape
, *attrsp
))
5637 if (*attrsp
& JSPROP_READONLY
)
5638 MarkTypePropertyNonWritable(cx
, obj
, id
);
5641 return JSObject::setGenericAttributes(cx
, nobj
, id
, attrsp
);
5646 baseops::DeleteGeneric(JSContext
*cx
, HandleObject obj
, HandleId id
, bool *succeeded
)
5648 RootedObject
proto(cx
);
5649 RootedShape
shape(cx
);
5650 if (!baseops::LookupProperty
<CanGC
>(cx
, obj
, id
, &proto
, &shape
))
5652 if (!shape
|| proto
!= obj
) {
5654 * If no property, or the property comes from a prototype, call the
5655 * class's delProperty hook, passing succeeded as the result parameter.
5657 return CallJSDeletePropertyOp(cx
, obj
->getClass()->delProperty
, obj
, id
, succeeded
);
5660 cx
->runtime()->gc
.poke();
5662 if (IsImplicitDenseOrTypedArrayElement(shape
)) {
5663 if (obj
->is
<TypedArrayObject
>()) {
5664 // Don't delete elements from typed arrays.
5669 if (!CallJSDeletePropertyOp(cx
, obj
->getClass()->delProperty
, obj
, id
, succeeded
))
5674 if (!obj
->maybeCopyElementsForWrite(cx
))
5677 obj
->setDenseElementHole(cx
, JSID_TO_INT(id
));
5678 return js_SuppressDeletedProperty(cx
, obj
, id
);
5681 if (!shape
->configurable()) {
5686 RootedId
propid(cx
, shape
->propid());
5687 if (!CallJSDeletePropertyOp(cx
, obj
->getClass()->delProperty
, obj
, propid
, succeeded
))
5692 return obj
->removeProperty(cx
, id
) && js_SuppressDeletedProperty(cx
, obj
, id
);
5696 js::WatchGuts(JSContext
*cx
, JS::HandleObject origObj
, JS::HandleId id
, JS::HandleObject callable
)
5698 RootedObject
obj(cx
, GetInnerObject(origObj
));
5699 if (obj
->isNative()) {
5700 // Use sparse indexes for watched objects, as dense elements can be
5701 // written to without checking the watchpoint map.
5702 if (!JSObject::sparsifyDenseElements(cx
, obj
))
5705 types::MarkTypePropertyNonData(cx
, obj
, id
);
5708 WatchpointMap
*wpmap
= cx
->compartment()->watchpointMap
;
5710 wpmap
= cx
->runtime()->new_
<WatchpointMap
>();
5711 if (!wpmap
|| !wpmap
->init()) {
5712 js_ReportOutOfMemory(cx
);
5715 cx
->compartment()->watchpointMap
= wpmap
;
5718 return wpmap
->watch(cx
, obj
, id
, js::WatchHandler
, callable
);
5722 baseops::Watch(JSContext
*cx
, JS::HandleObject obj
, JS::HandleId id
, JS::HandleObject callable
)
5724 if (!obj
->isNative() || obj
->is
<TypedArrayObject
>()) {
5725 JS_ReportErrorNumber(cx
, js_GetErrorMessage
, nullptr, JSMSG_CANT_WATCH
,
5726 obj
->getClass()->name
);
5730 return WatchGuts(cx
, obj
, id
, callable
);
5734 js::UnwatchGuts(JSContext
*cx
, JS::HandleObject origObj
, JS::HandleId id
)
5736 // Looking in the map for an unsupported object will never hit, so we don't
5737 // need to check for nativeness or watchable-ness here.
5738 RootedObject
obj(cx
, GetInnerObject(origObj
));
5739 if (WatchpointMap
*wpmap
= cx
->compartment()->watchpointMap
)
5740 wpmap
->unwatch(obj
, id
, nullptr, nullptr);
5745 baseops::Unwatch(JSContext
*cx
, JS::HandleObject obj
, JS::HandleId id
)
5747 return UnwatchGuts(cx
, obj
, id
);
5751 js::HasDataProperty(JSContext
*cx
, JSObject
*obj
, jsid id
, Value
*vp
)
5753 if (JSID_IS_INT(id
) && obj
->containsDenseElement(JSID_TO_INT(id
))) {
5754 *vp
= obj
->getDenseElement(JSID_TO_INT(id
));
5758 if (Shape
*shape
= obj
->nativeLookup(cx
, id
)) {
5759 if (shape
->hasDefaultGetter() && shape
->hasSlot()) {
5760 *vp
= obj
->nativeGetSlot(shape
->slot());
5769 * Gets |obj[id]|. If that value's not callable, returns true and stores a
5770 * non-primitive value in *vp. If it's callable, calls it with no arguments
5771 * and |obj| as |this|, returning the result in *vp.
5773 * This is a mini-abstraction for ES5 8.12.8 [[DefaultValue]], either steps 1-2
5777 MaybeCallMethod(JSContext
*cx
, HandleObject obj
, HandleId id
, MutableHandleValue vp
)
5779 if (!JSObject::getGeneric(cx
, obj
, obj
, id
, vp
))
5781 if (!IsCallable(vp
)) {
5785 return Invoke(cx
, ObjectValue(*obj
), vp
, 0, nullptr, vp
);
5789 js::DefaultValue(JSContext
*cx
, HandleObject obj
, JSType hint
, MutableHandleValue vp
)
5791 JS_ASSERT(hint
== JSTYPE_NUMBER
|| hint
== JSTYPE_STRING
|| hint
== JSTYPE_VOID
);
5793 Rooted
<jsid
> id(cx
);
5795 const Class
*clasp
= obj
->getClass();
5796 if (hint
== JSTYPE_STRING
) {
5797 id
= NameToId(cx
->names().toString
);
5799 /* Optimize (new String(...)).toString(). */
5800 if (clasp
== &StringObject::class_
) {
5801 if (ClassMethodIsNative(cx
, obj
, &StringObject::class_
, id
, js_str_toString
)) {
5802 vp
.setString(obj
->as
<StringObject
>().unbox());
5807 if (!MaybeCallMethod(cx
, obj
, id
, vp
))
5809 if (vp
.isPrimitive())
5812 id
= NameToId(cx
->names().valueOf
);
5813 if (!MaybeCallMethod(cx
, obj
, id
, vp
))
5815 if (vp
.isPrimitive())
5819 /* Optimize new String(...).valueOf(). */
5820 if (clasp
== &StringObject::class_
) {
5821 id
= NameToId(cx
->names().valueOf
);
5822 if (ClassMethodIsNative(cx
, obj
, &StringObject::class_
, id
, js_str_toString
)) {
5823 vp
.setString(obj
->as
<StringObject
>().unbox());
5828 /* Optimize new Number(...).valueOf(). */
5829 if (clasp
== &NumberObject::class_
) {
5830 id
= NameToId(cx
->names().valueOf
);
5831 if (ClassMethodIsNative(cx
, obj
, &NumberObject::class_
, id
, js_num_valueOf
)) {
5832 vp
.setNumber(obj
->as
<NumberObject
>().unbox());
5837 id
= NameToId(cx
->names().valueOf
);
5838 if (!MaybeCallMethod(cx
, obj
, id
, vp
))
5840 if (vp
.isPrimitive())
5843 id
= NameToId(cx
->names().toString
);
5844 if (!MaybeCallMethod(cx
, obj
, id
, vp
))
5846 if (vp
.isPrimitive())
5850 /* Avoid recursive death when decompiling in js_ReportValueError. */
5851 RootedString
str(cx
);
5852 if (hint
== JSTYPE_STRING
) {
5853 str
= JS_InternString(cx
, clasp
->name
);
5860 RootedValue
val(cx
, ObjectValue(*obj
));
5861 js_ReportValueError2(cx
, JSMSG_CANT_CONVERT_TO
, JSDVG_SEARCH_STACK
, val
, str
,
5864 : hint
== JSTYPE_STRING
? "string" : "number");
5869 JS_EnumerateState(JSContext
*cx
, HandleObject obj
, JSIterateOp enum_op
,
5870 MutableHandleValue statep
, JS::MutableHandleId idp
)
5872 /* If the class has a custom JSCLASS_NEW_ENUMERATE hook, call it. */
5873 const Class
*clasp
= obj
->getClass();
5874 JSEnumerateOp enumerate
= clasp
->enumerate
;
5875 if (clasp
->flags
& JSCLASS_NEW_ENUMERATE
) {
5876 JS_ASSERT(enumerate
!= JS_EnumerateStub
);
5877 return ((JSNewEnumerateOp
) enumerate
)(cx
, obj
, enum_op
, statep
, idp
);
5880 if (!enumerate(cx
, obj
))
5883 /* Tell InitNativeIterator to treat us like a native object. */
5884 JS_ASSERT(enum_op
== JSENUMERATE_INIT
|| enum_op
== JSENUMERATE_INIT_ALL
);
5885 statep
.setMagic(JS_NATIVE_ENUMERATE
);
5890 js::IsDelegate(JSContext
*cx
, HandleObject obj
, const js::Value
&v
, bool *result
)
5892 if (v
.isPrimitive()) {
5896 return IsDelegateOfObject(cx
, obj
, &v
.toObject(), result
);
5900 js::IsDelegateOfObject(JSContext
*cx
, HandleObject protoObj
, JSObject
* obj
, bool *result
)
5902 RootedObject
obj2(cx
, obj
);
5904 if (!JSObject::getProto(cx
, obj2
, &obj2
))
5910 if (obj2
== protoObj
) {
5918 js::GetBuiltinPrototypePure(GlobalObject
*global
, JSProtoKey protoKey
)
5920 JS_ASSERT(JSProto_Null
<= protoKey
);
5921 JS_ASSERT(protoKey
< JSProto_LIMIT
);
5923 if (protoKey
!= JSProto_Null
) {
5924 const Value
&v
= global
->getPrototype(protoKey
);
5926 return &v
.toObject();
5933 * The first part of this function has been hand-expanded and optimized into
5934 * NewBuiltinClassInstance in jsobjinlines.h.
5937 js::FindClassPrototype(ExclusiveContext
*cx
, MutableHandleObject protop
, const Class
*clasp
)
5939 protop
.set(nullptr);
5940 JSProtoKey protoKey
= ClassProtoKeyOrAnonymousOrNull(clasp
);
5941 if (protoKey
!= JSProto_Null
)
5942 return GetBuiltinPrototype(cx
, protoKey
, protop
);
5944 RootedObject
ctor(cx
);
5945 if (!FindClassObject(cx
, &ctor
, clasp
))
5948 if (ctor
&& ctor
->is
<JSFunction
>()) {
5950 if (cx
->isJSContext()) {
5951 if (!JSObject::getProperty(cx
->asJSContext(),
5952 ctor
, ctor
, cx
->names().prototype
, &v
))
5957 Shape
*shape
= ctor
->nativeLookup(cx
, cx
->names().prototype
);
5958 if (!shape
|| !NativeGetPureInline(ctor
, shape
, v
.address()))
5962 protop
.set(&v
.toObject());
5968 js::PrimitiveToObject(JSContext
*cx
, const Value
&v
)
5971 Rooted
<JSString
*> str(cx
, v
.toString());
5972 return StringObject::create(cx
, str
);
5975 return NumberObject::create(cx
, v
.toNumber());
5977 return BooleanObject::create(cx
, v
.toBoolean());
5978 JS_ASSERT(v
.isSymbol());
5979 RootedSymbol
symbol(cx
, v
.toSymbol());
5980 return SymbolObject::create(cx
, symbol
);
5983 /* Callers must handle the already-object case. */
5985 js::ToObjectSlow(JSContext
*cx
, HandleValue val
, bool reportScanStack
)
5987 JS_ASSERT(!val
.isMagic());
5988 JS_ASSERT(!val
.isObject());
5990 if (val
.isNullOrUndefined()) {
5991 if (reportScanStack
) {
5992 js_ReportIsNullOrUndefined(cx
, JSDVG_SEARCH_STACK
, val
, NullPtr());
5994 JS_ReportErrorNumber(cx
, js_GetErrorMessage
, nullptr, JSMSG_CANT_CONVERT_TO
,
5995 val
.isNull() ? "null" : "undefined", "object");
6000 return PrimitiveToObject(cx
, val
);
6004 js_GetObjectSlotName(JSTracer
*trc
, char *buf
, size_t bufsize
)
6006 JS_ASSERT(trc
->debugPrinter() == js_GetObjectSlotName
);
6008 JSObject
*obj
= (JSObject
*)trc
->debugPrintArg();
6009 uint32_t slot
= uint32_t(trc
->debugPrintIndex());
6012 if (obj
->isNative()) {
6013 shape
= obj
->lastProperty();
6014 while (shape
&& (!shape
->hasSlot() || shape
->slot() != slot
))
6015 shape
= shape
->previous();
6022 const char *slotname
= nullptr;
6023 const char *pattern
= nullptr;
6024 if (obj
->is
<GlobalObject
>()) {
6025 pattern
= "CLASS_OBJECT(%s)";
6028 #define TEST_SLOT_MATCHES_PROTOTYPE(name,code,init,clasp) \
6029 else if ((code) == slot) { slotname = js_##name##_str; }
6030 JS_FOR_EACH_PROTOTYPE(TEST_SLOT_MATCHES_PROTOTYPE
)
6031 #undef TEST_SLOT_MATCHES_PROTOTYPE
6034 if (obj
->is
<ScopeObject
>()) {
6035 if (slot
== ScopeObject::enclosingScopeSlot()) {
6036 slotname
= "enclosing_environment";
6037 } else if (obj
->is
<CallObject
>()) {
6038 if (slot
== CallObject::calleeSlot())
6039 slotname
= "callee_slot";
6040 } else if (obj
->is
<DeclEnvObject
>()) {
6041 if (slot
== DeclEnvObject::lambdaSlot())
6042 slotname
= "named_lambda";
6043 } else if (obj
->is
<DynamicWithObject
>()) {
6044 if (slot
== DynamicWithObject::objectSlot())
6045 slotname
= "with_object";
6046 else if (slot
== DynamicWithObject::thisSlot())
6047 slotname
= "with_this";
6053 JS_snprintf(buf
, bufsize
, pattern
, slotname
);
6055 JS_snprintf(buf
, bufsize
, "**UNKNOWN SLOT %ld**", (long)slot
);
6058 jsid propid
= shape
->propid();
6059 if (JSID_IS_INT(propid
)) {
6060 JS_snprintf(buf
, bufsize
, "%ld", (long)JSID_TO_INT(propid
));
6061 } else if (JSID_IS_ATOM(propid
)) {
6062 PutEscapedString(buf
, bufsize
, JSID_TO_ATOM(propid
), 0);
6063 } else if (JSID_IS_SYMBOL(propid
)) {
6064 JS_snprintf(buf
, bufsize
, "**SYMBOL KEY**");
6066 JS_snprintf(buf
, bufsize
, "**FINALIZED ATOM KEY**");
6072 js_ReportGetterOnlyAssignment(JSContext
*cx
, bool strict
)
6074 return JS_ReportErrorFlagsAndNumber(cx
,
6077 : JSREPORT_WARNING
| JSREPORT_STRICT
,
6078 js_GetErrorMessage
, nullptr,
6083 js_GetterOnlyPropertyStub(JSContext
*cx
, HandleObject obj
, HandleId id
, bool strict
,
6084 MutableHandleValue vp
)
6086 JS_ReportErrorNumber(cx
, js_GetErrorMessage
, nullptr, JSMSG_GETTER_ONLY
);
6093 * Routines to print out values during debugging. These are FRIEND_API to help
6094 * the debugger find them and to support temporarily hacking js_Dump* calls
6099 dumpValue(const Value
&v
)
6102 fprintf(stderr
, "null");
6103 else if (v
.isUndefined())
6104 fprintf(stderr
, "undefined");
6105 else if (v
.isInt32())
6106 fprintf(stderr
, "%d", v
.toInt32());
6107 else if (v
.isDouble())
6108 fprintf(stderr
, "%g", v
.toDouble());
6109 else if (v
.isString())
6110 v
.toString()->dump();
6111 else if (v
.isObject() && v
.toObject().is
<JSFunction
>()) {
6112 JSFunction
*fun
= &v
.toObject().as
<JSFunction
>();
6113 if (fun
->displayAtom()) {
6114 fputs("<function ", stderr
);
6115 FileEscapedString(stderr
, fun
->displayAtom(), 0);
6117 fputs("<unnamed function", stderr
);
6119 if (fun
->hasScript()) {
6120 JSScript
*script
= fun
->nonLazyScript();
6121 fprintf(stderr
, " (%s:%d)",
6122 script
->filename() ? script
->filename() : "", (int) script
->lineno());
6124 fprintf(stderr
, " at %p>", (void *) fun
);
6125 } else if (v
.isObject()) {
6126 JSObject
*obj
= &v
.toObject();
6127 const Class
*clasp
= obj
->getClass();
6128 fprintf(stderr
, "<%s%s at %p>",
6130 (clasp
== &JSObject::class_
) ? "" : " object",
6132 } else if (v
.isBoolean()) {
6134 fprintf(stderr
, "true");
6136 fprintf(stderr
, "false");
6137 } else if (v
.isMagic()) {
6138 fprintf(stderr
, "<invalid");
6140 switch (v
.whyMagic()) {
6141 case JS_ELEMENTS_HOLE
: fprintf(stderr
, " elements hole"); break;
6142 case JS_NATIVE_ENUMERATE
: fprintf(stderr
, " native enumeration"); break;
6143 case JS_NO_ITER_VALUE
: fprintf(stderr
, " no iter value"); break;
6144 case JS_GENERATOR_CLOSING
: fprintf(stderr
, " generator closing"); break;
6145 case JS_OPTIMIZED_OUT
: fprintf(stderr
, " optimized out"); break;
6146 default: fprintf(stderr
, " ?!"); break;
6149 fprintf(stderr
, ">");
6151 fprintf(stderr
, "unexpected value");
6156 js_DumpValue(const Value
&val
)
6159 fputc('\n', stderr
);
6165 fprintf(stderr
, "jsid %p = ", (void *) JSID_BITS(id
));
6166 dumpValue(IdToValue(id
));
6167 fputc('\n', stderr
);
6171 DumpProperty(JSObject
*obj
, Shape
&shape
)
6173 jsid id
= shape
.propid();
6174 uint8_t attrs
= shape
.attributes();
6176 fprintf(stderr
, " ((js::Shape *) %p) ", (void *) &shape
);
6177 if (attrs
& JSPROP_ENUMERATE
) fprintf(stderr
, "enumerate ");
6178 if (attrs
& JSPROP_READONLY
) fprintf(stderr
, "readonly ");
6179 if (attrs
& JSPROP_PERMANENT
) fprintf(stderr
, "permanent ");
6180 if (attrs
& JSPROP_SHARED
) fprintf(stderr
, "shared ");
6182 if (shape
.hasGetterValue())
6183 fprintf(stderr
, "getterValue=%p ", (void *) shape
.getterObject());
6184 else if (!shape
.hasDefaultGetter())
6185 fprintf(stderr
, "getterOp=%p ", JS_FUNC_TO_DATA_PTR(void *, shape
.getterOp()));
6187 if (shape
.hasSetterValue())
6188 fprintf(stderr
, "setterValue=%p ", (void *) shape
.setterObject());
6189 else if (!shape
.hasDefaultSetter())
6190 fprintf(stderr
, "setterOp=%p ", JS_FUNC_TO_DATA_PTR(void *, shape
.setterOp()));
6192 if (JSID_IS_ATOM(id
) || JSID_IS_INT(id
) || JSID_IS_SYMBOL(id
))
6193 dumpValue(js::IdToValue(id
));
6195 fprintf(stderr
, "unknown jsid %p", (void *) JSID_BITS(id
));
6197 uint32_t slot
= shape
.hasSlot() ? shape
.maybeSlot() : SHAPE_INVALID_SLOT
;
6198 fprintf(stderr
, ": slot %d", slot
);
6199 if (shape
.hasSlot()) {
6200 fprintf(stderr
, " = ");
6201 dumpValue(obj
->getSlot(slot
));
6202 } else if (slot
!= SHAPE_INVALID_SLOT
) {
6203 fprintf(stderr
, " (INVALID!)");
6205 fprintf(stderr
, "\n");
6209 JSObject::uninlinedIsProxy() const
6211 return is
<ProxyObject
>();
6217 JSObject
*obj
= this;
6218 fprintf(stderr
, "object %p\n", (void *) obj
);
6219 const Class
*clasp
= obj
->getClass();
6220 fprintf(stderr
, "class %p %s\n", (const void *)clasp
, clasp
->name
);
6222 fprintf(stderr
, "flags:");
6223 if (obj
->isDelegate()) fprintf(stderr
, " delegate");
6224 if (!obj
->is
<ProxyObject
>() && !obj
->nonProxyIsExtensible()) fprintf(stderr
, " not_extensible");
6225 if (obj
->isIndexed()) fprintf(stderr
, " indexed");
6226 if (obj
->isBoundFunction()) fprintf(stderr
, " bound_function");
6227 if (obj
->isQualifiedVarObj()) fprintf(stderr
, " varobj");
6228 if (obj
->isUnqualifiedVarObj()) fprintf(stderr
, " unqualified_varobj");
6229 if (obj
->watched()) fprintf(stderr
, " watched");
6230 if (obj
->isIteratedSingleton()) fprintf(stderr
, " iterated_singleton");
6231 if (obj
->isNewTypeUnknown()) fprintf(stderr
, " new_type_unknown");
6232 if (obj
->hasUncacheableProto()) fprintf(stderr
, " has_uncacheable_proto");
6233 if (obj
->hadElementsAccess()) fprintf(stderr
, " had_elements_access");
6235 if (obj
->isNative()) {
6236 if (obj
->inDictionaryMode())
6237 fprintf(stderr
, " inDictionaryMode");
6238 if (obj
->hasShapeTable())
6239 fprintf(stderr
, " hasShapeTable");
6241 fprintf(stderr
, "\n");
6243 if (obj
->isNative()) {
6244 uint32_t slots
= obj
->getDenseInitializedLength();
6246 fprintf(stderr
, "elements\n");
6247 for (uint32_t i
= 0; i
< slots
; i
++) {
6248 fprintf(stderr
, " %3d: ", i
);
6249 dumpValue(obj
->getDenseElement(i
));
6250 fprintf(stderr
, "\n");
6256 fprintf(stderr
, "proto ");
6257 TaggedProto proto
= obj
->getTaggedProto();
6259 fprintf(stderr
, "<lazy>");
6261 dumpValue(ObjectOrNullValue(proto
.toObjectOrNull()));
6262 fputc('\n', stderr
);
6264 fprintf(stderr
, "parent ");
6265 dumpValue(ObjectOrNullValue(obj
->getParent()));
6266 fputc('\n', stderr
);
6268 if (clasp
->flags
& JSCLASS_HAS_PRIVATE
)
6269 fprintf(stderr
, "private %p\n", obj
->getPrivate());
6271 if (!obj
->isNative())
6272 fprintf(stderr
, "not native\n");
6274 uint32_t reservedEnd
= JSCLASS_RESERVED_SLOTS(clasp
);
6275 uint32_t slots
= obj
->slotSpan();
6276 uint32_t stop
= obj
->isNative() ? reservedEnd
: slots
;
6278 fprintf(stderr
, obj
->isNative() ? "reserved slots:\n" : "slots:\n");
6279 for (uint32_t i
= 0; i
< stop
; i
++) {
6280 fprintf(stderr
, " %3d ", i
);
6281 if (i
< reservedEnd
)
6282 fprintf(stderr
, "(reserved) ");
6283 fprintf(stderr
, "= ");
6284 dumpValue(obj
->getSlot(i
));
6285 fputc('\n', stderr
);
6288 if (obj
->isNative()) {
6289 fprintf(stderr
, "properties:\n");
6290 Vector
<Shape
*, 8, SystemAllocPolicy
> props
;
6291 for (Shape::Range
<NoGC
> r(obj
->lastProperty()); !r
.empty(); r
.popFront())
6292 props
.append(&r
.front());
6293 for (size_t i
= props
.length(); i
-- != 0;)
6294 DumpProperty(obj
, *props
[i
]);
6296 fputc('\n', stderr
);
6300 MaybeDumpObject(const char *name
, JSObject
*obj
)
6303 fprintf(stderr
, " %s: ", name
);
6304 dumpValue(ObjectValue(*obj
));
6305 fputc('\n', stderr
);
6310 MaybeDumpValue(const char *name
, const Value
&v
)
6313 fprintf(stderr
, " %s: ", name
);
6315 fputc('\n', stderr
);
6320 js_DumpInterpreterFrame(JSContext
*cx
, InterpreterFrame
*start
)
6322 /* This should only called during live debugging. */
6323 ScriptFrameIter
i(cx
, ScriptFrameIter::GO_THROUGH_SAVED
);
6326 fprintf(stderr
, "no stack for cx = %p\n", (void*) cx
);
6330 while (!i
.done() && !i
.isJit() && i
.interpFrame() != start
)
6334 fprintf(stderr
, "fp = %p not found in cx = %p\n",
6335 (void *)start
, (void *)cx
);
6340 for (; !i
.done(); ++i
) {
6342 fprintf(stderr
, "JIT frame\n");
6344 fprintf(stderr
, "InterpreterFrame at %p\n", (void *) i
.interpFrame());
6346 if (i
.isFunctionFrame()) {
6347 fprintf(stderr
, "callee fun: ");
6348 dumpValue(i
.calleev());
6350 fprintf(stderr
, "global frame, no callee");
6352 fputc('\n', stderr
);
6354 fprintf(stderr
, "file %s line %u\n",
6355 i
.script()->filename(), (unsigned) i
.script()->lineno());
6357 if (jsbytecode
*pc
= i
.pc()) {
6358 fprintf(stderr
, " pc = %p\n", pc
);
6359 fprintf(stderr
, " current op: %s\n", js_CodeName
[*pc
]);
6360 MaybeDumpObject("staticScope", i
.script()->getStaticScope(pc
));
6362 MaybeDumpValue("this", i
.thisv());
6364 fprintf(stderr
, " rval: ");
6365 dumpValue(i
.interpFrame()->returnValue());
6366 fputc('\n', stderr
);
6369 fprintf(stderr
, " flags:");
6370 if (i
.isConstructing())
6371 fprintf(stderr
, " constructing");
6372 if (!i
.isJit() && i
.interpFrame()->isDebuggerFrame())
6373 fprintf(stderr
, " debugger");
6374 if (i
.isEvalFrame())
6375 fprintf(stderr
, " eval");
6376 if (!i
.isJit() && i
.interpFrame()->isYielding())
6377 fprintf(stderr
, " yielding");
6378 if (!i
.isJit() && i
.interpFrame()->isGeneratorFrame())
6379 fprintf(stderr
, " generator");
6380 fputc('\n', stderr
);
6382 fprintf(stderr
, " scopeChain: (JSObject *) %p\n", (void *) i
.scopeChain());
6384 fputc('\n', stderr
);
6391 js_DumpBacktrace(JSContext
*cx
)
6393 Sprinter
sprinter(cx
);
6396 for (ScriptFrameIter
i(cx
); !i
.done(); ++i
, ++depth
) {
6397 const char *filename
= JS_GetScriptFilename(i
.script());
6398 unsigned line
= JS_PCToLineNumber(cx
, i
.script(), i
.pc());
6399 JSScript
*script
= i
.script();
6400 sprinter
.printf("#%d %14p %s:%d (%p @ %d)\n",
6401 depth
, (i
.isJit() ? 0 : i
.interpFrame()), filename
, line
,
6402 script
, script
->pcToOffset(i
.pc()));
6404 fprintf(stdout
, "%s", sprinter
.string());
6408 JSObject::addSizeOfExcludingThis(mozilla::MallocSizeOf mallocSizeOf
, JS::ClassInfo
*info
)
6410 if (hasDynamicSlots())
6411 info
->objectsMallocHeapSlots
+= mallocSizeOf(slots
);
6413 if (hasDynamicElements()) {
6414 js::ObjectElements
*elements
= getElementsHeader();
6415 if (!elements
->isCopyOnWrite() || elements
->ownerObject() == this)
6416 info
->objectsMallocHeapElementsNonAsmJS
+= mallocSizeOf(elements
);
6419 // Other things may be measured in the future if DMD indicates it is worthwhile.
6420 if (is
<JSFunction
>() ||
6422 is
<ArrayObject
>() ||
6424 is
<RegExpObject
>() ||
6427 // Do nothing. But this function is hot, and we win by getting the
6428 // common cases out of the way early. Some stats on the most common
6429 // classes, as measured during a vanilla browser session:
6430 // - (53.7%, 53.7%): Function
6431 // - (18.0%, 71.7%): Object
6432 // - (16.9%, 88.6%): Array
6433 // - ( 3.9%, 92.5%): Call
6434 // - ( 2.8%, 95.3%): RegExp
6435 // - ( 1.0%, 96.4%): Proxy
6437 } else if (is
<ArgumentsObject
>()) {
6438 info
->objectsMallocHeapMisc
+= as
<ArgumentsObject
>().sizeOfMisc(mallocSizeOf
);
6439 } else if (is
<RegExpStaticsObject
>()) {
6440 info
->objectsMallocHeapMisc
+= as
<RegExpStaticsObject
>().sizeOfData(mallocSizeOf
);
6441 } else if (is
<PropertyIteratorObject
>()) {
6442 info
->objectsMallocHeapMisc
+= as
<PropertyIteratorObject
>().sizeOfMisc(mallocSizeOf
);
6443 } else if (is
<ArrayBufferObject
>() || is
<SharedArrayBufferObject
>()) {
6444 ArrayBufferObject::addSizeOfExcludingThis(this, mallocSizeOf
, info
);
6445 } else if (is
<AsmJSModuleObject
>()) {
6446 as
<AsmJSModuleObject
>().addSizeOfMisc(mallocSizeOf
, &info
->objectsNonHeapCodeAsmJS
,
6447 &info
->objectsMallocHeapMisc
);
6448 #ifdef JS_HAS_CTYPES
6450 // This must be the last case.
6451 info
->objectsMallocHeapMisc
+=
6452 js::SizeOfDataIfCDataObject(mallocSizeOf
, const_cast<JSObject
*>(this));