1 : /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
2 : * vim: set ts=8 sw=4 et tw=78:
3 : *
4 : * This Source Code Form is subject to the terms of the Mozilla Public
5 : * License, v. 2.0. If a copy of the MPL was not distributed with this file,
6 : * You can obtain one at http://mozilla.org/MPL/2.0/. */
7 :
8 : #include "mozilla/Assertions.h"
9 : #include "mozilla/Attributes.h"
10 :
11 : #include "jsscope.h"
12 : #include "jsobjinlines.h"
13 :
14 : #include "ObjectImpl.h"
15 :
16 : #include "gc/Barrier-inl.h"
17 :
18 : #include "ObjectImpl-inl.h"
19 :
20 : using namespace js;
21 :
22 18667 : static ObjectElements emptyElementsHeader(0, 0);
23 :
24 : /* Objects with no elements share one empty set of elements. */
25 : HeapSlot *js::emptyObjectElements =
26 : reinterpret_cast<HeapSlot *>(uintptr_t(&emptyElementsHeader) + sizeof(ObjectElements));
27 :
28 : #ifdef DEBUG
29 : void
30 30224190 : js::ObjectImpl::checkShapeConsistency()
31 : {
32 : static int throttle = -1;
33 30224190 : if (throttle < 0) {
34 18667 : if (const char *var = getenv("JS_CHECK_SHAPE_THROTTLE"))
35 0 : throttle = atoi(var);
36 18667 : if (throttle < 0)
37 18667 : throttle = 0;
38 : }
39 30224190 : if (throttle == 0)
40 30224190 : return;
41 :
42 0 : MOZ_ASSERT(isNative());
43 :
44 0 : Shape *shape = lastProperty();
45 0 : Shape *prev = NULL;
46 :
47 0 : if (inDictionaryMode()) {
48 0 : MOZ_ASSERT(shape->hasTable());
49 :
50 0 : PropertyTable &table = shape->table();
51 0 : for (uint32_t fslot = table.freelist; fslot != SHAPE_INVALID_SLOT;
52 0 : fslot = getSlot(fslot).toPrivateUint32()) {
53 0 : MOZ_ASSERT(fslot < slotSpan());
54 : }
55 :
56 0 : for (int n = throttle; --n >= 0 && shape->parent; shape = shape->parent) {
57 0 : MOZ_ASSERT_IF(shape != lastProperty(), !shape->hasTable());
58 :
59 0 : Shape **spp = table.search(shape->propid(), false);
60 0 : MOZ_ASSERT(SHAPE_FETCH(spp) == shape);
61 : }
62 :
63 0 : shape = lastProperty();
64 0 : for (int n = throttle; --n >= 0 && shape; shape = shape->parent) {
65 0 : MOZ_ASSERT_IF(shape->slot() != SHAPE_INVALID_SLOT, shape->slot() < slotSpan());
66 0 : if (!prev) {
67 0 : MOZ_ASSERT(shape == lastProperty());
68 0 : MOZ_ASSERT(shape->listp == &shape_);
69 : } else {
70 0 : MOZ_ASSERT(shape->listp == &prev->parent);
71 : }
72 0 : prev = shape;
73 : }
74 : } else {
75 0 : for (int n = throttle; --n >= 0 && shape->parent; shape = shape->parent) {
76 0 : if (shape->hasTable()) {
77 0 : PropertyTable &table = shape->table();
78 0 : MOZ_ASSERT(shape->parent);
79 0 : for (Shape::Range r(shape); !r.empty(); r.popFront()) {
80 0 : Shape **spp = table.search(r.front().propid(), false);
81 0 : MOZ_ASSERT(SHAPE_FETCH(spp) == &r.front());
82 : }
83 : }
84 0 : if (prev) {
85 0 : MOZ_ASSERT(prev->maybeSlot() >= shape->maybeSlot());
86 0 : shape->kids.checkConsistency(prev);
87 : }
88 0 : prev = shape;
89 : }
90 : }
91 : }
92 : #endif
93 :
94 : void
95 2235 : js::ObjectImpl::initSlotRange(uint32_t start, const Value *vector, uint32_t length)
96 : {
97 2235 : JSCompartment *comp = compartment();
98 : HeapSlot *fixedStart, *fixedEnd, *slotsStart, *slotsEnd;
99 2235 : getSlotRange(start, length, &fixedStart, &fixedEnd, &slotsStart, &slotsEnd);
100 2235 : for (HeapSlot *sp = fixedStart; sp < fixedEnd; sp++)
101 0 : sp->init(comp, this->asObjectPtr(), start++, *vector++);
102 5898 : for (HeapSlot *sp = slotsStart; sp < slotsEnd; sp++)
103 3663 : sp->init(comp, this->asObjectPtr(), start++, *vector++);
104 2235 : }
105 :
106 : void
107 376467 : js::ObjectImpl::copySlotRange(uint32_t start, const Value *vector, uint32_t length)
108 : {
109 376467 : JSCompartment *comp = compartment();
110 : HeapSlot *fixedStart, *fixedEnd, *slotsStart, *slotsEnd;
111 376467 : getSlotRange(start, length, &fixedStart, &fixedEnd, &slotsStart, &slotsEnd);
112 894623 : for (HeapSlot *sp = fixedStart; sp < fixedEnd; sp++)
113 518156 : sp->set(comp, this->asObjectPtr(), start++, *vector++);
114 1057556 : for (HeapSlot *sp = slotsStart; sp < slotsEnd; sp++)
115 681089 : sp->set(comp, this->asObjectPtr(), start++, *vector++);
116 376467 : }
117 :
118 : #ifdef DEBUG
119 : bool
120 505690759 : js::ObjectImpl::slotInRange(uint32_t slot, SentinelAllowed sentinel) const
121 : {
122 505690759 : uint32_t capacity = numFixedSlots() + numDynamicSlots();
123 505690759 : if (sentinel == SENTINEL_ALLOWED)
124 134002811 : return slot <= capacity;
125 371687948 : return slot < capacity;
126 : }
127 : #endif /* DEBUG */
128 :
129 : #if defined(_MSC_VER) && _MSC_VER >= 1500
130 : /*
131 : * Work around a compiler bug in MSVC9 and above, where inlining this function
132 : * causes stack pointer offsets to go awry and spp to refer to something higher
133 : * up the stack.
134 : */
135 : MOZ_NEVER_INLINE
136 : #endif
137 : const Shape *
138 65493592 : js::ObjectImpl::nativeLookup(JSContext *cx, jsid id)
139 : {
140 65493592 : MOZ_ASSERT(isNative());
141 : Shape **spp;
142 65493592 : return Shape::search(cx, lastProperty(), id, &spp);
143 : }
144 :
145 : void
146 2872168 : js::ObjectImpl::markChildren(JSTracer *trc)
147 : {
148 2872168 : MarkTypeObject(trc, &type_, "type");
149 :
150 2872168 : MarkShape(trc, &shape_, "shape");
151 :
152 2872168 : Class *clasp = shape_->getObjectClass();
153 2872168 : JSObject *obj = asObjectPtr();
154 2872168 : if (clasp->trace)
155 2439286 : clasp->trace(trc, obj);
156 :
157 2872168 : if (shape_->isNative())
158 2840717 : MarkObjectSlots(trc, obj, 0, obj->slotSpan());
159 2872168 : }
160 :
161 : bool
162 0 : js::SparseElementsHeader::defineElement(JSContext *cx, ObjectImpl *obj,
163 : uint32_t index, const Value &value,
164 : PropertyOp getter, StrictPropertyOp setter, unsigned attrs)
165 : {
166 0 : MOZ_ASSERT(this == &obj->elementsHeader());
167 :
168 0 : MOZ_NOT_REACHED("NYI");
169 : return false;
170 : }
171 :
172 : bool
173 0 : js::DenseElementsHeader::defineElement(JSContext *cx, ObjectImpl *obj,
174 : uint32_t index, const Value &value,
175 : PropertyOp getter, StrictPropertyOp setter, unsigned attrs)
176 : {
177 0 : MOZ_ASSERT(this == &obj->elementsHeader());
178 :
179 : /*
180 : * If the new property doesn't have the right attributes, or an atypical
181 : * getter or setter is being used, go sparse.
182 : */
183 0 : if (attrs != JSPROP_ENUMERATE ||
184 : (attrs & (JSPROP_GETTER | JSPROP_SETTER)) || getter || setter)
185 : {
186 0 : if (!obj->makeElementsSparse(cx))
187 0 : return false;
188 0 : SparseElementsHeader &elts = obj->elementsHeader().asSparseElements();
189 0 : return elts.defineElement(cx, obj, index, value, getter, setter, attrs);
190 : }
191 :
192 : /* If space for the dense element already exists, we only need set it. */
193 0 : uint32_t initLen = initializedLength();
194 0 : if (index < initLen) {
195 0 : obj->elements[index].set(obj->asObjectPtr(), index, value);
196 0 : return true;
197 : }
198 :
199 : /* Otherwise we ensure space for it exists and that it's initialized. */
200 0 : ObjectImpl::DenseElementsResult res = obj->ensureDenseElementsInitialized(cx, index, 0);
201 :
202 : /* Propagate any error. */
203 0 : if (res == ObjectImpl::Failure)
204 0 : return false;
205 :
206 : /* Otherwise, if the index was too far out of range, go sparse. */
207 0 : if (res == ObjectImpl::ConvertToSparse) {
208 0 : if (!obj->makeElementsSparse(cx))
209 0 : return false;
210 0 : SparseElementsHeader &elts = obj->elementsHeader().asSparseElements();
211 0 : return elts.defineElement(cx, obj, index, value, getter, setter, attrs);
212 : }
213 :
214 : /* But if we were able to ensure the element's existence, we're good. */
215 0 : MOZ_ASSERT(res == ObjectImpl::Succeeded);
216 0 : obj->elements[index].set(obj->asObjectPtr(), index, value);
217 0 : return true;
218 : }
219 :
220 : static JSObject *
221 0 : ArrayBufferDelegate(JSContext *cx, ObjectImpl *obj)
222 : {
223 0 : MOZ_ASSERT(obj->hasClass(&ArrayBufferClass));
224 0 : if (obj->getPrivate())
225 0 : return static_cast<JSObject *>(obj->getPrivate());
226 0 : JSObject *delegate = NewObjectWithGivenProto(cx, &ObjectClass, obj->getProto(), NULL);
227 0 : obj->setPrivate(delegate);
228 0 : return delegate;
229 : }
230 :
231 : template <typename T>
232 : bool
233 : js::TypedElementsHeader<T>::defineElement(JSContext *cx, ObjectImpl *obj,
234 : uint32_t index, const Value &value,
235 : PropertyOp getter, StrictPropertyOp setter, unsigned attrs)
236 : {
237 : /*
238 : * XXX This isn't really a good error message, if this is even how typed
239 : * arrays should behave...
240 : */
241 : js_ReportValueErrorFlags(cx, JSREPORT_ERROR, JSMSG_OBJECT_NOT_EXTENSIBLE,
242 : JSDVG_IGNORE_STACK, ObjectValue(*(JSObject*)obj), // XXX
243 : NULL, NULL, NULL);
244 : return false;
245 : }
246 :
247 : bool
248 0 : js::ArrayBufferElementsHeader::defineElement(JSContext *cx, ObjectImpl *obj,
249 : uint32_t index, const Value &value,
250 : PropertyOp getter, StrictPropertyOp setter,
251 : unsigned attrs)
252 : {
253 0 : MOZ_ASSERT(this == &obj->elementsHeader());
254 :
255 0 : JSObject *delegate = ArrayBufferDelegate(cx, obj);
256 0 : if (!delegate)
257 0 : return false;
258 0 : return DefineElement(cx, delegate, index, value, getter, setter, attrs);
259 : }
260 :
261 : bool
262 0 : js::DefineElement(JSContext *cx, ObjectImpl *obj, uint32_t index, const Value &value,
263 : PropertyOp getter, StrictPropertyOp setter, unsigned attrs)
264 : {
265 0 : NEW_OBJECT_REPRESENTATION_ONLY();
266 :
267 : ElementsHeader &header = obj->elementsHeader();
268 :
269 : switch (header.kind()) {
270 : case DenseElements:
271 : return header.asDenseElements().defineElement(cx, obj, index, value, getter, setter,
272 : attrs);
273 : case SparseElements:
274 : return header.asSparseElements().defineElement(cx, obj, index, value, getter, setter,
275 : attrs);
276 : case Uint8Elements:
277 : return header.asUint8Elements().defineElement(cx, obj, index, value, getter, setter,
278 : attrs);
279 : case Int8Elements:
280 : return header.asInt8Elements().defineElement(cx, obj, index, value, getter, setter,
281 : attrs);
282 : case Uint16Elements:
283 : return header.asUint16Elements().defineElement(cx, obj, index, value, getter, setter,
284 : attrs);
285 : case Int16Elements:
286 : return header.asInt16Elements().defineElement(cx, obj, index, value, getter, setter,
287 : attrs);
288 : case Uint32Elements:
289 : return header.asUint32Elements().defineElement(cx, obj, index, value, getter, setter,
290 : attrs);
291 : case Int32Elements:
292 : return header.asInt32Elements().defineElement(cx, obj, index, value, getter, setter,
293 : attrs);
294 : case Uint8ClampedElements:
295 : return header.asUint8ClampedElements().defineElement(cx, obj, index, value,
296 : getter, setter, attrs);
297 : case Float32Elements:
298 : return header.asFloat32Elements().defineElement(cx, obj, index, value, getter, setter,
299 : attrs);
300 : case Float64Elements:
301 : return header.asFloat64Elements().defineElement(cx, obj, index, value, getter, setter,
302 : attrs);
303 : case ArrayBufferElements:
304 : return header.asArrayBufferElements().defineElement(cx, obj, index, value, getter, setter,
305 : attrs);
306 : }
307 :
308 : MOZ_NOT_REACHED("bad elements kind!");
309 : return false;
310 56001 : }
|