/src/mozilla-central/js/src/vm/ArrayObject-inl.h
Line | Count | Source (jump to first uncovered line) |
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/. */ |
6 | | |
7 | | #ifndef vm_ArrayObject_inl_h |
8 | | #define vm_ArrayObject_inl_h |
9 | | |
10 | | #include "vm/ArrayObject.h" |
11 | | |
12 | | #include "gc/GCTrace.h" |
13 | | #include "vm/StringType.h" |
14 | | |
15 | | #include "vm/JSObject-inl.h" |
16 | | #include "vm/ObjectGroup-inl.h" |
17 | | #include "vm/ObjectOperations-inl.h" // js::GetElement |
18 | | #include "vm/TypeInference-inl.h" |
19 | | |
20 | | namespace js { |
21 | | |
22 | | inline void |
23 | | ArrayObject::setLength(JSContext* cx, uint32_t length) |
24 | 96 | { |
25 | 96 | MOZ_ASSERT(lengthIsWritable()); |
26 | 96 | MOZ_ASSERT_IF(length != getElementsHeader()->length, !denseElementsAreFrozen()); |
27 | 96 | |
28 | 96 | if (length > INT32_MAX) { |
29 | 0 | /* Track objects with overflowing lengths in type information. */ |
30 | 0 | MarkObjectGroupFlags(cx, this, OBJECT_FLAG_LENGTH_OVERFLOW); |
31 | 0 | } |
32 | 96 | |
33 | 96 | getElementsHeader()->length = length; |
34 | 96 | } |
35 | | |
36 | | /* static */ inline ArrayObject* |
37 | | ArrayObject::createArrayInternal(JSContext* cx, gc::AllocKind kind, gc::InitialHeap heap, |
38 | | HandleShape shape, HandleObjectGroup group, |
39 | | AutoSetNewObjectMetadata&) |
40 | 18 | { |
41 | 18 | const js::Class* clasp = group->clasp(); |
42 | 18 | MOZ_ASSERT(shape && group); |
43 | 18 | MOZ_ASSERT(clasp == shape->getObjectClass()); |
44 | 18 | MOZ_ASSERT(clasp == &ArrayObject::class_); |
45 | 18 | MOZ_ASSERT_IF(clasp->hasFinalize(), heap == gc::TenuredHeap); |
46 | 18 | MOZ_ASSERT_IF(group->hasUnanalyzedPreliminaryObjects(), |
47 | 18 | heap == js::gc::TenuredHeap); |
48 | 18 | |
49 | 18 | // Arrays can use their fixed slots to store elements, so can't have shapes |
50 | 18 | // which allow named properties to be stored in the fixed slots. |
51 | 18 | MOZ_ASSERT(shape->numFixedSlots() == 0); |
52 | 18 | |
53 | 18 | size_t nDynamicSlots = dynamicSlotsCount(0, shape->slotSpan(), clasp); |
54 | 18 | JSObject* obj = js::Allocate<JSObject>(cx, kind, nDynamicSlots, heap, clasp); |
55 | 18 | if (!obj) { |
56 | 0 | return nullptr; |
57 | 0 | } |
58 | 18 | |
59 | 18 | ArrayObject* aobj = static_cast<ArrayObject*>(obj); |
60 | 18 | aobj->initGroup(group); |
61 | 18 | aobj->initShape(shape); |
62 | 18 | // NOTE: Dynamic slots are created internally by Allocate<JSObject>. |
63 | 18 | if (!nDynamicSlots) { |
64 | 18 | aobj->initSlots(nullptr); |
65 | 18 | } |
66 | 18 | |
67 | 18 | MOZ_ASSERT(clasp->shouldDelayMetadataBuilder()); |
68 | 18 | cx->realm()->setObjectPendingMetadata(cx, aobj); |
69 | 18 | |
70 | 18 | return aobj; |
71 | 18 | } |
72 | | |
73 | | /* static */ inline ArrayObject* |
74 | | ArrayObject::finishCreateArray(ArrayObject* obj, HandleShape shape, AutoSetNewObjectMetadata& metadata) |
75 | 18 | { |
76 | 18 | size_t span = shape->slotSpan(); |
77 | 18 | if (span) { |
78 | 0 | obj->initializeSlotRange(0, span); |
79 | 0 | } |
80 | 18 | |
81 | 18 | gc::gcTracer.traceCreateObject(obj); |
82 | 18 | |
83 | 18 | return obj; |
84 | 18 | } |
85 | | |
86 | | /* static */ inline ArrayObject* |
87 | | ArrayObject::createArray(JSContext* cx, gc::AllocKind kind, gc::InitialHeap heap, |
88 | | HandleShape shape, HandleObjectGroup group, |
89 | | uint32_t length, AutoSetNewObjectMetadata& metadata) |
90 | 18 | { |
91 | 18 | ArrayObject* obj = createArrayInternal(cx, kind, heap, shape, group, metadata); |
92 | 18 | if (!obj) { |
93 | 0 | return nullptr; |
94 | 0 | } |
95 | 18 | |
96 | 18 | uint32_t capacity = gc::GetGCKindSlots(kind) - ObjectElements::VALUES_PER_HEADER; |
97 | 18 | |
98 | 18 | obj->setFixedElements(); |
99 | 18 | new (obj->getElementsHeader()) ObjectElements(capacity, length); |
100 | 18 | |
101 | 18 | return finishCreateArray(obj, shape, metadata); |
102 | 18 | } |
103 | | |
104 | | /* static */ inline ArrayObject* |
105 | | ArrayObject::createCopyOnWriteArray(JSContext* cx, gc::InitialHeap heap, |
106 | | HandleArrayObject sharedElementsOwner) |
107 | 0 | { |
108 | 0 | MOZ_ASSERT(sharedElementsOwner->getElementsHeader()->isCopyOnWrite()); |
109 | 0 | MOZ_ASSERT(sharedElementsOwner->getElementsHeader()->ownerObject() == sharedElementsOwner); |
110 | 0 |
|
111 | 0 | // Use the smallest allocation kind for the array, as it can't have any |
112 | 0 | // fixed slots (see the assert in createArrayInternal) and will not be using |
113 | 0 | // its fixed elements. |
114 | 0 | gc::AllocKind kind = gc::AllocKind::OBJECT0_BACKGROUND; |
115 | 0 |
|
116 | 0 | AutoSetNewObjectMetadata metadata(cx); |
117 | 0 | RootedShape shape(cx, sharedElementsOwner->lastProperty()); |
118 | 0 | RootedObjectGroup group(cx, sharedElementsOwner->group()); |
119 | 0 | ArrayObject* obj = createArrayInternal(cx, kind, heap, shape, group, metadata); |
120 | 0 | if (!obj) { |
121 | 0 | return nullptr; |
122 | 0 | } |
123 | 0 | |
124 | 0 | obj->elements_ = sharedElementsOwner->getDenseElementsAllowCopyOnWrite(); |
125 | 0 |
|
126 | 0 | return finishCreateArray(obj, shape, metadata); |
127 | 0 | } |
128 | | |
129 | | } // namespace js |
130 | | |
131 | | #endif // vm_ArrayObject_inl_h |