1 : /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
2 : * vim: set ts=8 sw=4 et tw=99:
3 : *
4 : * ***** BEGIN LICENSE BLOCK *****
5 : * Version: MPL 1.1/GPL 2.0/LGPL 2.1
6 : *
7 : * The contents of this file are subject to the Mozilla Public License Version
8 : * 1.1 (the "License"); you may not use this file except in compliance with
9 : * the License. You may obtain a copy of the License at
10 : * http://www.mozilla.org/MPL/
11 : *
12 : * Software distributed under the License is distributed on an "AS IS" basis,
13 : * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
14 : * for the specific language governing rights and limitations under the
15 : * License.
16 : *
17 : * The Original Code is Mozilla Communicator client code, released
18 : * March 31, 1998.
19 : *
20 : * The Initial Developer of the Original Code is
21 : * Netscape Communications Corporation.
22 : * Portions created by the Initial Developer are Copyright (C) 1998
23 : * the Initial Developer. All Rights Reserved.
24 : *
25 : * Contributor(s):
26 : *
27 : * Alternatively, the contents of this file may be used under the terms of
28 : * either of the GNU General Public License Version 2 or later (the "GPL"),
29 : * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
30 : * in which case the provisions of the GPL or the LGPL are applicable instead
31 : * of those above. If you wish to allow use of your version of this file only
32 : * under the terms of either the GPL or the LGPL, and not to allow others to
33 : * use your version of this file under the terms of the MPL, indicate your
34 : * decision by deleting the provisions above and replace them with the notice
35 : * and other provisions required by the GPL or the LGPL. If you do not delete
36 : * the provisions above, a recipient may use your version of this file under
37 : * the terms of any one of the MPL, the GPL or the LGPL.
38 : *
39 : * ***** END LICENSE BLOCK ***** */
40 :
41 : #ifndef jsobjinlines_h___
42 : #define jsobjinlines_h___
43 :
44 : #include <new>
45 :
46 : #include "jsapi.h"
47 : #include "jsarray.h"
48 : #include "jsbool.h"
49 : #include "jscntxt.h"
50 : #include "jsdate.h"
51 : #include "jsfun.h"
52 : #include "jsgcmark.h"
53 : #include "jsiter.h"
54 : #include "jslock.h"
55 : #include "jsnum.h"
56 : #include "jsobj.h"
57 : #include "jsprobes.h"
58 : #include "jspropertytree.h"
59 : #include "jsproxy.h"
60 : #include "jsscope.h"
61 : #include "jsstr.h"
62 : #include "jstypedarray.h"
63 : #include "jsxml.h"
64 : #include "jswrapper.h"
65 :
66 : #include "gc/Barrier.h"
67 : #include "js/TemplateLib.h"
68 :
69 : #include "vm/BooleanObject.h"
70 : #include "vm/GlobalObject.h"
71 : #include "vm/NumberObject.h"
72 : #include "vm/RegExpStatics.h"
73 : #include "vm/StringObject.h"
74 :
75 : #include "jsatominlines.h"
76 : #include "jsfuninlines.h"
77 : #include "jsgcinlines.h"
78 : #include "jsinferinlines.h"
79 : #include "jsscopeinlines.h"
80 : #include "jsscriptinlines.h"
81 :
82 : #include "gc/Barrier-inl.h"
83 :
84 : #include "vm/ObjectImpl-inl.h"
85 : #include "vm/RegExpStatics-inl.h"
86 : #include "vm/String-inl.h"
87 :
88 : inline bool
89 60276149 : JSObject::hasPrivate() const
90 : {
91 60276149 : return getClass()->hasPrivate();
92 : }
93 :
94 : inline void *&
95 60257022 : JSObject::privateRef(uint32_t nfixed) const
96 : {
97 : /*
98 : * The private pointer of an object can hold any word sized value.
99 : * Private pointers are stored immediately after the last fixed slot of
100 : * the object.
101 : */
102 60257022 : JS_ASSERT(nfixed == numFixedSlots());
103 60257022 : JS_ASSERT(hasPrivate());
104 60257022 : js::HeapSlot *end = &fixedSlots()[nfixed];
105 60257022 : return *reinterpret_cast<void**>(end);
106 : }
107 :
108 : inline void *
109 51172724 : JSObject::getPrivate() const { return privateRef(numFixedSlots()); }
110 :
111 : inline void *
112 64262 : JSObject::getPrivate(size_t nfixed) const { return privateRef(nfixed); }
113 :
114 : inline void
115 5762115 : JSObject::setPrivate(void *data)
116 : {
117 5762115 : void **pprivate = &privateRef(numFixedSlots());
118 :
119 5762115 : privateWriteBarrierPre(pprivate);
120 5762115 : *pprivate = data;
121 5762115 : privateWriteBarrierPost(pprivate);
122 5762115 : }
123 :
124 : inline void
125 2492 : JSObject::setPrivateUnbarriered(void *data)
126 : {
127 2492 : void **pprivate = &privateRef(numFixedSlots());
128 2492 : *pprivate = data;
129 2492 : }
130 :
131 : inline void
132 591303 : JSObject::initPrivate(void *data)
133 : {
134 591303 : privateRef(numFixedSlots()) = data;
135 591303 : }
136 :
137 : inline bool
138 38703124 : JSObject::enumerate(JSContext *cx, JSIterateOp iterop, js::Value *statep, jsid *idp)
139 : {
140 38703124 : JSNewEnumerateOp op = getOps()->enumerate;
141 38703124 : return (op ? op : JS_EnumerateState)(cx, this, iterop, statep, idp);
142 : }
143 :
144 : inline bool
145 971952 : JSObject::defaultValue(JSContext *cx, JSType hint, js::Value *vp)
146 : {
147 971952 : JSConvertOp op = getClass()->convert;
148 971952 : bool ok = (op == JS_ConvertStub ? js::DefaultValue : op)(cx, this, hint, vp);
149 971952 : JS_ASSERT_IF(ok, vp->isPrimitive());
150 971952 : return ok;
151 : }
152 :
153 : inline JSType
154 6990067 : JSObject::typeOf(JSContext *cx)
155 : {
156 6990067 : js::TypeOfOp op = getOps()->typeOf;
157 6990067 : return (op ? op : js_TypeOf)(cx, this);
158 : }
159 :
160 : inline JSObject *
161 5386356 : JSObject::thisObject(JSContext *cx)
162 : {
163 5386356 : JSObjectOp op = getOps()->thisObject;
164 5386356 : return op ? op(cx, this) : this;
165 : }
166 :
167 : inline JSBool
168 18924322 : JSObject::setGeneric(JSContext *cx, jsid id, js::Value *vp, JSBool strict)
169 : {
170 18924322 : if (getOps()->setGeneric)
171 3840334 : return nonNativeSetProperty(cx, id, vp, strict);
172 15083988 : return js_SetPropertyHelper(cx, this, id, 0, vp, strict);
173 : }
174 :
175 : inline JSBool
176 86455 : JSObject::setProperty(JSContext *cx, js::PropertyName *name, js::Value *vp, JSBool strict)
177 : {
178 86455 : return setGeneric(cx, ATOM_TO_JSID(name), vp, strict);
179 : }
180 :
181 : inline JSBool
182 13549125 : JSObject::setElement(JSContext *cx, uint32_t index, js::Value *vp, JSBool strict)
183 : {
184 13549125 : if (getOps()->setElement)
185 13549124 : return nonNativeSetElement(cx, index, vp, strict);
186 1 : return js_SetElementHelper(cx, this, index, 0, vp, strict);
187 : }
188 :
189 : inline JSBool
190 0 : JSObject::setSpecial(JSContext *cx, js::SpecialId sid, js::Value *vp, JSBool strict)
191 : {
192 0 : return setGeneric(cx, SPECIALID_TO_JSID(sid), vp, strict);
193 : }
194 :
195 : inline JSBool
196 40625 : JSObject::setGenericAttributes(JSContext *cx, jsid id, unsigned *attrsp)
197 : {
198 40625 : js::types::MarkTypePropertyConfigured(cx, this, id);
199 40625 : js::GenericAttributesOp op = getOps()->setGenericAttributes;
200 40625 : return (op ? op : js_SetAttributes)(cx, this, id, attrsp);
201 : }
202 :
203 : inline JSBool
204 0 : JSObject::setPropertyAttributes(JSContext *cx, js::PropertyName *name, unsigned *attrsp)
205 : {
206 0 : return setGenericAttributes(cx, ATOM_TO_JSID(name), attrsp);
207 : }
208 :
209 : inline JSBool
210 0 : JSObject::setElementAttributes(JSContext *cx, uint32_t index, unsigned *attrsp)
211 : {
212 0 : js::ElementAttributesOp op = getOps()->setElementAttributes;
213 0 : return (op ? op : js_SetElementAttributes)(cx, this, index, attrsp);
214 : }
215 :
216 : inline JSBool
217 0 : JSObject::setSpecialAttributes(JSContext *cx, js::SpecialId sid, unsigned *attrsp)
218 : {
219 0 : return setGenericAttributes(cx, SPECIALID_TO_JSID(sid), attrsp);
220 : }
221 :
222 : inline JSBool
223 39765952 : JSObject::getGeneric(JSContext *cx, JSObject *receiver, jsid id, js::Value *vp)
224 : {
225 39765952 : js::GenericIdOp op = getOps()->getGeneric;
226 39765952 : if (op) {
227 3323932 : if (!op(cx, this, receiver, id, vp))
228 18 : return false;
229 : } else {
230 36442020 : if (!js_GetProperty(cx, this, receiver, id, vp))
231 112 : return false;
232 : }
233 39765822 : return true;
234 : }
235 :
236 : inline JSBool
237 2954448 : JSObject::getProperty(JSContext *cx, JSObject *receiver, js::PropertyName *name, js::Value *vp)
238 : {
239 2954448 : return getGeneric(cx, receiver, ATOM_TO_JSID(name), vp);
240 : }
241 :
242 : inline JSBool
243 21051529 : JSObject::getGeneric(JSContext *cx, jsid id, js::Value *vp)
244 : {
245 21051529 : return getGeneric(cx, this, id, vp);
246 : }
247 :
248 : inline JSBool
249 4011690 : JSObject::getProperty(JSContext *cx, js::PropertyName *name, js::Value *vp)
250 : {
251 4011690 : return getGeneric(cx, ATOM_TO_JSID(name), vp);
252 : }
253 :
254 : inline bool
255 48466 : JSObject::deleteProperty(JSContext *cx, js::PropertyName *name, js::Value *rval, bool strict)
256 : {
257 48466 : jsid id = js_CheckForStringIndex(ATOM_TO_JSID(name));
258 48466 : js::types::AddTypePropertyId(cx, this, id, js::types::Type::UndefinedType());
259 48466 : js::types::MarkTypePropertyConfigured(cx, this, id);
260 48466 : js::DeletePropertyOp op = getOps()->deleteProperty;
261 48466 : return (op ? op : js_DeleteProperty)(cx, this, name, rval, strict);
262 : }
263 :
264 : inline bool
265 198983 : JSObject::deleteElement(JSContext *cx, uint32_t index, js::Value *rval, bool strict)
266 : {
267 : jsid id;
268 198983 : if (!js::IndexToId(cx, index, &id))
269 0 : return false;
270 198983 : js::types::AddTypePropertyId(cx, this, id, js::types::Type::UndefinedType());
271 198983 : js::types::MarkTypePropertyConfigured(cx, this, id);
272 198983 : js::DeleteElementOp op = getOps()->deleteElement;
273 198983 : return (op ? op : js_DeleteElement)(cx, this, index, rval, strict);
274 : }
275 :
276 : inline bool
277 0 : JSObject::deleteSpecial(JSContext *cx, js::SpecialId sid, js::Value *rval, bool strict)
278 : {
279 0 : jsid id = SPECIALID_TO_JSID(sid);
280 0 : js::types::AddTypePropertyId(cx, this, id, js::types::Type::UndefinedType());
281 0 : js::types::MarkTypePropertyConfigured(cx, this, id);
282 0 : js::DeleteSpecialOp op = getOps()->deleteSpecial;
283 0 : return (op ? op : js_DeleteSpecial)(cx, this, sid, rval, strict);
284 : }
285 :
286 : inline void
287 45369271 : JSObject::finalize(JSContext *cx, bool background)
288 : {
289 45369271 : js::Probes::finalizeObject(this);
290 :
291 45369271 : if (!background) {
292 : /*
293 : * Finalize obj first, in case it needs map and slots. Objects with
294 : * finalize hooks are not finalized in the background, as the class is
295 : * stored in the object's shape, which may have already been destroyed.
296 : */
297 38956364 : js::Class *clasp = getClass();
298 38956364 : if (clasp->finalize)
299 23372337 : clasp->finalize(cx, this);
300 : }
301 :
302 45369271 : finish(cx);
303 45369271 : }
304 :
305 : inline JSObject *
306 1101610165 : JSObject::getParent() const
307 : {
308 1101610165 : return lastProperty()->getObjectParent();
309 : }
310 :
311 : inline JSObject *
312 14528347 : JSObject::enclosingScope()
313 : {
314 14528347 : return isScope() ? &asScope().enclosingScope() : getParent();
315 : }
316 :
317 : /*
318 : * Property read barrier for deferred cloning of compiler-created function
319 : * objects optimized as typically non-escaping, ad-hoc methods in obj.
320 : */
321 : inline js::Shape *
322 0 : JSObject::methodReadBarrier(JSContext *cx, const js::Shape &shape, js::Value *vp)
323 : {
324 0 : JS_ASSERT(nativeContains(cx, shape));
325 0 : JS_ASSERT(shape.isMethod());
326 0 : JS_ASSERT(shape.hasSlot());
327 0 : JS_ASSERT(shape.hasDefaultSetter());
328 0 : JS_ASSERT(!isGlobal()); /* i.e. we are not changing the global shape */
329 :
330 0 : JSFunction *fun = vp->toObject().toFunction();
331 0 : JS_ASSERT(!fun->isClonedMethod());
332 0 : JS_ASSERT(fun->isNullClosure());
333 :
334 0 : fun = js::CloneFunctionObject(cx, fun);
335 0 : if (!fun)
336 0 : return NULL;
337 0 : fun->setMethodObj(*this);
338 :
339 : /*
340 : * Replace the method property with an ordinary data property. This is
341 : * equivalent to this->setProperty(cx, shape.id, vp) except that any
342 : * watchpoint on the property is not triggered.
343 : */
344 0 : uint32_t slot = shape.slot();
345 0 : js::Shape *newshape = methodShapeChange(cx, shape);
346 0 : if (!newshape)
347 0 : return NULL;
348 0 : JS_ASSERT(!newshape->isMethod());
349 0 : JS_ASSERT(newshape->slot() == slot);
350 0 : vp->setObject(*fun);
351 0 : nativeSetSlot(slot, *vp);
352 0 : return newshape;
353 : }
354 :
355 : inline bool
356 0 : JSObject::canHaveMethodBarrier() const
357 : {
358 0 : return isObject() || isFunction() || isPrimitive() || isDate();
359 : }
360 :
361 : inline bool
362 400636 : JSObject::isFixedSlot(size_t slot)
363 : {
364 400636 : JS_ASSERT(!isDenseArray());
365 400636 : return slot < numFixedSlots();
366 : }
367 :
368 : inline size_t
369 453369 : JSObject::dynamicSlotIndex(size_t slot)
370 : {
371 453369 : JS_ASSERT(!isDenseArray() && slot >= numFixedSlots());
372 453369 : return slot - numFixedSlots();
373 : }
374 :
375 : inline size_t
376 742315416 : JSObject::numDynamicSlots() const
377 : {
378 742315416 : return dynamicSlotsCount(numFixedSlots(), slotSpan());
379 : }
380 :
381 : inline void
382 19481 : JSObject::setLastPropertyInfallible(const js::Shape *shape)
383 : {
384 19481 : JS_ASSERT(!shape->inDictionary());
385 19481 : JS_ASSERT(shape->compartment() == compartment());
386 19481 : JS_ASSERT(!inDictionaryMode());
387 19481 : JS_ASSERT(slotSpan() == shape->slotSpan());
388 19481 : JS_ASSERT(numFixedSlots() == shape->numFixedSlots());
389 :
390 19481 : shape_ = const_cast<js::Shape *>(shape);
391 19481 : }
392 :
393 : inline void
394 4221 : JSObject::removeLastProperty(JSContext *cx)
395 : {
396 4221 : JS_ASSERT(canRemoveLastProperty());
397 4221 : JS_ALWAYS_TRUE(setLastProperty(cx, lastProperty()->previous()));
398 4221 : }
399 :
400 : inline bool
401 9636 : JSObject::canRemoveLastProperty()
402 : {
403 : /*
404 : * Check that the information about the object stored in the last
405 : * property's base shape is consistent with that stored in the previous
406 : * shape. If not consistent, then the last property cannot be removed as it
407 : * will induce a change in the object itself, and the object must be
408 : * converted to dictionary mode instead. See BaseShape comment in jsscope.h
409 : */
410 9636 : JS_ASSERT(!inDictionaryMode());
411 9636 : const js::Shape *previous = lastProperty()->previous();
412 9636 : return previous->getObjectParent() == lastProperty()->getObjectParent()
413 9636 : && previous->getObjectFlags() == lastProperty()->getObjectFlags();
414 : }
415 :
416 : inline const js::HeapSlot *
417 181405 : JSObject::getRawSlots()
418 : {
419 181405 : JS_ASSERT(isGlobal());
420 181405 : return slots;
421 : }
422 :
423 : inline const js::Value &
424 45938946 : JSObject::getReservedSlot(unsigned index) const
425 : {
426 45938946 : JS_ASSERT(index < JSSLOT_FREE(getClass()));
427 45938946 : return getSlot(index);
428 : }
429 :
430 : inline js::HeapSlot &
431 147644 : JSObject::getReservedSlotRef(unsigned index)
432 : {
433 147644 : JS_ASSERT(index < JSSLOT_FREE(getClass()));
434 147644 : return getSlotRef(index);
435 : }
436 :
437 : inline void
438 6082577 : JSObject::setReservedSlot(unsigned index, const js::Value &v)
439 : {
440 6082577 : JS_ASSERT(index < JSSLOT_FREE(getClass()));
441 6082577 : setSlot(index, v);
442 6082577 : }
443 :
444 : inline void
445 560193 : JSObject::initReservedSlot(unsigned index, const js::Value &v)
446 : {
447 560193 : JS_ASSERT(index < JSSLOT_FREE(getClass()));
448 560193 : initSlot(index, v);
449 560193 : }
450 :
451 : inline bool
452 201334 : JSObject::hasContiguousSlots(size_t start, size_t count) const
453 : {
454 : /*
455 : * Check that the range [start, start+count) is either all inline or all
456 : * out of line.
457 : */
458 201334 : JS_ASSERT(slotInRange(start + count, SENTINEL_ALLOWED));
459 201334 : return (start + count <= numFixedSlots()) || (start >= numFixedSlots());
460 : }
461 :
462 : inline void
463 2542 : JSObject::prepareSlotRangeForOverwrite(size_t start, size_t end)
464 : {
465 5084 : for (size_t i = start; i < end; i++)
466 2542 : getSlotAddressUnchecked(i)->js::HeapSlot::~HeapSlot();
467 2542 : }
468 :
469 : inline void
470 1715110 : JSObject::prepareElementRangeForOverwrite(size_t start, size_t end)
471 : {
472 1715110 : JS_ASSERT(isDenseArray());
473 1715110 : JS_ASSERT(end <= getDenseArrayInitializedLength());
474 3547395 : for (size_t i = start; i < end; i++)
475 1832285 : elements[i].js::HeapSlot::~HeapSlot();
476 1715110 : }
477 :
478 : inline uint32_t
479 78572760 : JSObject::getArrayLength() const
480 : {
481 78572760 : JS_ASSERT(isArray());
482 78572760 : return getElementsHeader()->length;
483 : }
484 :
485 : inline void
486 4452848 : JSObject::setArrayLength(JSContext *cx, uint32_t length)
487 : {
488 4452848 : JS_ASSERT(isArray());
489 :
490 4452848 : if (length > INT32_MAX) {
491 : /*
492 : * Mark the type of this object as possibly not a dense array, per the
493 : * requirements of OBJECT_FLAG_NON_DENSE_ARRAY.
494 : */
495 : js::types::MarkTypeObjectFlags(cx, this,
496 : js::types::OBJECT_FLAG_NON_PACKED_ARRAY |
497 36 : js::types::OBJECT_FLAG_NON_DENSE_ARRAY);
498 36 : jsid lengthId = ATOM_TO_JSID(cx->runtime->atomState.lengthAtom);
499 : js::types::AddTypePropertyId(cx, this, lengthId,
500 36 : js::types::Type::DoubleType());
501 : }
502 :
503 4452848 : getElementsHeader()->length = length;
504 4452848 : }
505 :
506 : inline void
507 9270636 : JSObject::setDenseArrayLength(uint32_t length)
508 : {
509 : /* Variant of setArrayLength for use on dense arrays where the length cannot overflow int32. */
510 9270636 : JS_ASSERT(isDenseArray());
511 9270636 : JS_ASSERT(length <= INT32_MAX);
512 9270636 : getElementsHeader()->length = length;
513 9270636 : }
514 :
515 : inline uint32_t
516 260154313 : JSObject::getDenseArrayInitializedLength()
517 : {
518 260154313 : JS_ASSERT(isDenseArray());
519 260154313 : return getElementsHeader()->initializedLength;
520 : }
521 :
522 : inline void
523 1715110 : JSObject::setDenseArrayInitializedLength(uint32_t length)
524 : {
525 1715110 : JS_ASSERT(isDenseArray());
526 1715110 : JS_ASSERT(length <= getDenseArrayCapacity());
527 1715110 : prepareElementRangeForOverwrite(length, getElementsHeader()->initializedLength);
528 1715110 : getElementsHeader()->initializedLength = length;
529 1715110 : }
530 :
531 : inline uint32_t
532 104770147 : JSObject::getDenseArrayCapacity()
533 : {
534 104770147 : JS_ASSERT(isDenseArray());
535 104770147 : return getElementsHeader()->capacity;
536 : }
537 :
538 : inline bool
539 4106826 : JSObject::ensureElements(JSContext *cx, uint32_t capacity)
540 : {
541 4106826 : if (capacity > getDenseArrayCapacity())
542 191960 : return growElements(cx, capacity);
543 3914866 : return true;
544 : }
545 :
546 : inline js::HeapSlotArray
547 1793039 : JSObject::getDenseArrayElements()
548 : {
549 1793039 : JS_ASSERT(isDenseArray());
550 1793039 : return js::HeapSlotArray(elements);
551 : }
552 :
553 : inline const js::Value &
554 125717524 : JSObject::getDenseArrayElement(unsigned idx)
555 : {
556 125717524 : JS_ASSERT(isDenseArray() && idx < getDenseArrayInitializedLength());
557 125717524 : return elements[idx];
558 : }
559 :
560 : inline void
561 58925406 : JSObject::setDenseArrayElement(unsigned idx, const js::Value &val)
562 : {
563 58925406 : JS_ASSERT(isDenseArray() && idx < getDenseArrayInitializedLength());
564 58925406 : elements[idx].set(this, idx, val);
565 58925406 : }
566 :
567 : inline void
568 1369107 : JSObject::initDenseArrayElement(unsigned idx, const js::Value &val)
569 : {
570 1369107 : JS_ASSERT(isDenseArray() && idx < getDenseArrayInitializedLength());
571 1369107 : elements[idx].init(this, idx, val);
572 1369107 : }
573 :
574 : inline void
575 57284954 : JSObject::setDenseArrayElementWithType(JSContext *cx, unsigned idx, const js::Value &val)
576 : {
577 57284954 : js::types::AddTypePropertyId(cx, this, JSID_VOID, val);
578 57284954 : setDenseArrayElement(idx, val);
579 57284954 : }
580 :
581 : inline void
582 1369107 : JSObject::initDenseArrayElementWithType(JSContext *cx, unsigned idx, const js::Value &val)
583 : {
584 1369107 : js::types::AddTypePropertyId(cx, this, JSID_VOID, val);
585 1369107 : initDenseArrayElement(idx, val);
586 1369107 : }
587 :
588 : inline void
589 49174 : JSObject::copyDenseArrayElements(unsigned dstStart, const js::Value *src, unsigned count)
590 : {
591 49174 : JS_ASSERT(dstStart + count <= getDenseArrayCapacity());
592 49174 : JSCompartment *comp = compartment();
593 3713465 : for (unsigned i = 0; i < count; ++i)
594 3664291 : elements[dstStart + i].set(comp, this, dstStart + i, src[i]);
595 49174 : }
596 :
597 : inline void
598 190475 : JSObject::initDenseArrayElements(unsigned dstStart, const js::Value *src, unsigned count)
599 : {
600 190475 : JS_ASSERT(dstStart + count <= getDenseArrayCapacity());
601 190475 : JSCompartment *comp = compartment();
602 2347104 : for (unsigned i = 0; i < count; ++i)
603 2156629 : elements[dstStart + i].init(comp, this, dstStart + i, src[i]);
604 190475 : }
605 :
606 : inline void
607 23096 : JSObject::moveDenseArrayElements(unsigned dstStart, unsigned srcStart, unsigned count)
608 : {
609 23096 : JS_ASSERT(dstStart + count <= getDenseArrayCapacity());
610 23096 : JS_ASSERT(srcStart + count <= getDenseArrayInitializedLength());
611 :
612 : /*
613 : * Using memmove here would skip write barriers. Also, we need to consider
614 : * an array containing [A, B, C], in the following situation:
615 : *
616 : * 1. Incremental GC marks slot 0 of array (i.e., A), then returns to JS code.
617 : * 2. JS code moves slots 1..2 into slots 0..1, so it contains [B, C, C].
618 : * 3. Incremental GC finishes by marking slots 1 and 2 (i.e., C).
619 : *
620 : * Since normal marking never happens on B, it is very important that the
621 : * write barrier is invoked here on B, despite the fact that it exists in
622 : * the array before and after the move.
623 : */
624 23096 : JSCompartment *comp = compartment();
625 23096 : if (comp->needsBarrier()) {
626 23 : if (dstStart < srcStart) {
627 23 : js::HeapSlot *dst = elements + dstStart;
628 23 : js::HeapSlot *src = elements + srcStart;
629 30 : for (unsigned i = 0; i < count; i++, dst++, src++)
630 7 : dst->set(comp, this, dst - elements, *src);
631 : } else {
632 0 : js::HeapSlot *dst = elements + dstStart + count - 1;
633 0 : js::HeapSlot *src = elements + srcStart + count - 1;
634 0 : for (unsigned i = 0; i < count; i++, dst--, src--)
635 0 : dst->set(comp, this, dst - elements, *src);
636 : }
637 : } else {
638 23073 : memmove(elements + dstStart, elements + srcStart, count * sizeof(js::HeapSlot));
639 : }
640 23096 : }
641 :
642 : inline void
643 66 : JSObject::moveDenseArrayElementsUnbarriered(unsigned dstStart, unsigned srcStart, unsigned count)
644 : {
645 66 : JS_ASSERT(!compartment()->needsBarrier());
646 :
647 66 : JS_ASSERT(dstStart + count <= getDenseArrayCapacity());
648 66 : JS_ASSERT(srcStart + count <= getDenseArrayCapacity());
649 :
650 66 : memmove(elements + dstStart, elements + srcStart, count * sizeof(js::Value));
651 66 : }
652 :
653 : inline bool
654 : JSObject::denseArrayHasInlineSlots() const
655 : {
656 : JS_ASSERT(isDenseArray());
657 : return elements == fixedElements();
658 : }
659 :
660 : namespace js {
661 :
662 : /*
663 : * Any name atom for a function which will be added as a DeclEnv object to the
664 : * scope chain above call objects for fun.
665 : */
666 : static inline JSAtom *
667 739340 : CallObjectLambdaName(JSFunction *fun)
668 : {
669 739340 : return (fun->flags & JSFUN_LAMBDA) ? fun->atom : NULL;
670 : }
671 :
672 : } /* namespace js */
673 :
674 : inline const js::Value &
675 118186 : JSObject::getDateUTCTime() const
676 : {
677 118186 : JS_ASSERT(isDate());
678 118186 : return getFixedSlot(JSSLOT_DATE_UTC_TIME);
679 : }
680 :
681 : inline void
682 58881 : JSObject::setDateUTCTime(const js::Value &time)
683 : {
684 58881 : JS_ASSERT(isDate());
685 58881 : setFixedSlot(JSSLOT_DATE_UTC_TIME, time);
686 58881 : }
687 :
688 : inline js::NativeIterator *
689 35947790 : JSObject::getNativeIterator() const
690 : {
691 35947790 : return (js::NativeIterator *) getPrivate();
692 : }
693 :
694 : inline void
695 568593 : JSObject::setNativeIterator(js::NativeIterator *ni)
696 : {
697 568593 : setPrivate(ni);
698 568593 : }
699 :
700 : inline JSLinearString *
701 4727341 : JSObject::getNamePrefix() const
702 : {
703 4727341 : JS_ASSERT(isNamespace() || isQName());
704 4727341 : const js::Value &v = getSlot(JSSLOT_NAME_PREFIX);
705 4727341 : return !v.isUndefined() ? &v.toString()->asLinear() : NULL;
706 : }
707 :
708 : inline jsval
709 4729353 : JSObject::getNamePrefixVal() const
710 : {
711 4729353 : JS_ASSERT(isNamespace() || isQName());
712 4729353 : return getSlot(JSSLOT_NAME_PREFIX);
713 : }
714 :
715 : inline void
716 4730078 : JSObject::setNamePrefix(JSLinearString *prefix)
717 : {
718 4730078 : JS_ASSERT(isNamespace() || isQName());
719 4730078 : setSlot(JSSLOT_NAME_PREFIX, prefix ? js::StringValue(prefix) : js::UndefinedValue());
720 4730078 : }
721 :
722 : inline void
723 0 : JSObject::clearNamePrefix()
724 : {
725 0 : JS_ASSERT(isNamespace() || isQName());
726 0 : setSlot(JSSLOT_NAME_PREFIX, js::UndefinedValue());
727 0 : }
728 :
729 : inline JSLinearString *
730 4735439 : JSObject::getNameURI() const
731 : {
732 4735439 : JS_ASSERT(isNamespace() || isQName());
733 4735439 : const js::Value &v = getSlot(JSSLOT_NAME_URI);
734 4735439 : return !v.isUndefined() ? &v.toString()->asLinear() : NULL;
735 : }
736 :
737 : inline jsval
738 4729353 : JSObject::getNameURIVal() const
739 : {
740 4729353 : JS_ASSERT(isNamespace() || isQName());
741 4729353 : return getSlot(JSSLOT_NAME_URI);
742 : }
743 :
744 : inline void
745 4730105 : JSObject::setNameURI(JSLinearString *uri)
746 : {
747 4730105 : JS_ASSERT(isNamespace() || isQName());
748 4730105 : setSlot(JSSLOT_NAME_URI, uri ? js::StringValue(uri) : js::UndefinedValue());
749 4730105 : }
750 :
751 : inline jsval
752 4719503 : JSObject::getNamespaceDeclared() const
753 : {
754 4719503 : JS_ASSERT(isNamespace());
755 4719503 : return getSlot(JSSLOT_NAMESPACE_DECLARED);
756 : }
757 :
758 : inline void
759 1255 : JSObject::setNamespaceDeclared(jsval decl)
760 : {
761 1255 : JS_ASSERT(isNamespace());
762 1255 : setSlot(JSSLOT_NAMESPACE_DECLARED, decl);
763 1255 : }
764 :
765 : inline JSAtom *
766 2362923 : JSObject::getQNameLocalName() const
767 : {
768 2362923 : JS_ASSERT(isQName());
769 2362923 : const js::Value &v = getSlot(JSSLOT_QNAME_LOCAL_NAME);
770 2362923 : return !v.isUndefined() ? &v.toString()->asAtom() : NULL;
771 : }
772 :
773 : inline jsval
774 2369281 : JSObject::getQNameLocalNameVal() const
775 : {
776 2369281 : JS_ASSERT(isQName());
777 2369281 : return getSlot(JSSLOT_QNAME_LOCAL_NAME);
778 : }
779 :
780 : inline void
781 2369281 : JSObject::setQNameLocalName(JSAtom *name)
782 : {
783 2369281 : JS_ASSERT(isQName());
784 2369281 : setSlot(JSSLOT_QNAME_LOCAL_NAME, name ? js::StringValue(name) : js::UndefinedValue());
785 2369281 : }
786 :
787 : inline bool
788 11044156 : JSObject::setSingletonType(JSContext *cx)
789 : {
790 11044156 : if (!cx->typeInferenceEnabled())
791 7104554 : return true;
792 :
793 3939602 : JS_ASSERT(!lastProperty()->previous());
794 3939602 : JS_ASSERT(!hasLazyType());
795 3939602 : JS_ASSERT_IF(getProto(), type() == getProto()->getNewType(cx, NULL));
796 :
797 3939602 : js::types::TypeObject *type = cx->compartment->getLazyType(cx, getProto());
798 3939602 : if (!type)
799 0 : return false;
800 :
801 3939602 : type_ = type;
802 3939602 : return true;
803 : }
804 :
805 : inline js::types::TypeObject *
806 1355515 : JSObject::getType(JSContext *cx)
807 : {
808 1355515 : if (hasLazyType())
809 51738 : makeLazyType(cx);
810 1355515 : return type_;
811 : }
812 :
813 : inline bool
814 1074153 : JSObject::clearType(JSContext *cx)
815 : {
816 1074153 : JS_ASSERT(!hasSingletonType());
817 :
818 1074153 : js::types::TypeObject *type = cx->compartment->getEmptyType(cx);
819 1074153 : if (!type)
820 0 : return false;
821 :
822 1074153 : type_ = type;
823 1074153 : return true;
824 : }
825 :
826 : inline void
827 6496673 : JSObject::setType(js::types::TypeObject *newType)
828 : {
829 : #ifdef DEBUG
830 6496673 : JS_ASSERT(newType);
831 16640210 : for (JSObject *obj = newType->proto; obj; obj = obj->getProto())
832 10143537 : JS_ASSERT(obj != this);
833 : #endif
834 6509890 : JS_ASSERT_IF(hasSpecialEquality(),
835 6509890 : newType->hasAnyFlags(js::types::OBJECT_FLAG_SPECIAL_EQUALITY));
836 6496673 : JS_ASSERT(!hasSingletonType());
837 6496673 : type_ = newType;
838 6496673 : }
839 :
840 80270 : inline bool JSObject::setIteratedSingleton(JSContext *cx)
841 : {
842 80270 : return setFlag(cx, js::BaseShape::ITERATED_SINGLETON);
843 : }
844 :
845 1453003 : inline bool JSObject::isSystem() const
846 : {
847 1453003 : return lastProperty()->hasObjectFlag(js::BaseShape::SYSTEM);
848 : }
849 :
850 1445262 : inline bool JSObject::setSystem(JSContext *cx)
851 : {
852 1445262 : return setFlag(cx, js::BaseShape::SYSTEM);
853 : }
854 :
855 1653137 : inline bool JSObject::setDelegate(JSContext *cx)
856 : {
857 1653137 : return setFlag(cx, js::BaseShape::DELEGATE, GENERATE_SHAPE);
858 : }
859 :
860 1002511 : inline bool JSObject::isVarObj() const
861 : {
862 1002511 : return lastProperty()->hasObjectFlag(js::BaseShape::VAROBJ);
863 : }
864 :
865 122685 : inline bool JSObject::setVarObj(JSContext *cx)
866 : {
867 122685 : return setFlag(cx, js::BaseShape::VAROBJ);
868 : }
869 :
870 3630 : inline bool JSObject::setWatched(JSContext *cx)
871 : {
872 3630 : return setFlag(cx, js::BaseShape::WATCHED, GENERATE_SHAPE);
873 : }
874 :
875 2914144 : inline bool JSObject::hasUncacheableProto() const
876 : {
877 2914144 : return lastProperty()->hasObjectFlag(js::BaseShape::UNCACHEABLE_PROTO);
878 : }
879 :
880 87083 : inline bool JSObject::setUncacheableProto(JSContext *cx)
881 : {
882 87083 : return setFlag(cx, js::BaseShape::UNCACHEABLE_PROTO, GENERATE_SHAPE);
883 : }
884 :
885 1888283 : inline bool JSObject::isBoundFunction() const
886 : {
887 1888283 : return lastProperty()->hasObjectFlag(js::BaseShape::BOUND_FUNCTION);
888 : }
889 :
890 35378915 : inline bool JSObject::isIndexed() const
891 : {
892 35378915 : return lastProperty()->hasObjectFlag(js::BaseShape::INDEXED);
893 : }
894 :
895 36044962 : inline bool JSObject::watched() const
896 : {
897 36044962 : return lastProperty()->hasObjectFlag(js::BaseShape::WATCHED);
898 : }
899 :
900 6609400 : inline bool JSObject::hasSpecialEquality() const
901 : {
902 6609400 : return !!getClass()->ext.equality;
903 : }
904 :
905 37723977 : inline bool JSObject::isArguments() const { return isNormalArguments() || isStrictArguments(); }
906 21209 : inline bool JSObject::isArrayBuffer() const { return hasClass(&js::ArrayBufferClass); }
907 73914488 : inline bool JSObject::isBlock() const { return hasClass(&js::BlockClass); }
908 46240 : inline bool JSObject::isBoolean() const { return hasClass(&js::BooleanClass); }
909 70212446 : inline bool JSObject::isCall() const { return hasClass(&js::CallClass); }
910 651148 : inline bool JSObject::isClonedBlock() const { return isBlock() && !!getProto(); }
911 811515 : inline bool JSObject::isDate() const { return hasClass(&js::DateClass); }
912 42133806 : inline bool JSObject::isDeclEnv() const { return hasClass(&js::DeclEnvClass); }
913 34911 : inline bool JSObject::isElementIterator() const { return hasClass(&js::ElementIteratorClass); }
914 184587 : inline bool JSObject::isError() const { return hasClass(&js::ErrorClass); }
915 362528897 : inline bool JSObject::isFunction() const { return hasClass(&js::FunctionClass); }
916 : inline bool JSObject::isFunctionProxy() const { return hasClass(&js::FunctionProxyClass); }
917 15442 : inline bool JSObject::isGenerator() const { return hasClass(&js::GeneratorClass); }
918 35872714 : inline bool JSObject::isIterator() const { return hasClass(&js::IteratorClass); }
919 33102427 : inline bool JSObject::isNamespace() const { return hasClass(&js::NamespaceClass); }
920 39814994 : inline bool JSObject::isNestedScope() const { return isBlock() || isWith(); }
921 38360783 : inline bool JSObject::isNormalArguments() const { return hasClass(&js::NormalArgumentsObjectClass); }
922 302129 : inline bool JSObject::isNumber() const { return hasClass(&js::NumberClass); }
923 3004636 : inline bool JSObject::isObject() const { return hasClass(&js::ObjectClass); }
924 0 : inline bool JSObject::isPrimitive() const { return isNumber() || isString() || isBoolean(); }
925 6382783 : inline bool JSObject::isRegExp() const { return hasClass(&js::RegExpClass); }
926 9814 : inline bool JSObject::isRegExpStatics() const { return hasClass(&js::RegExpStaticsClass); }
927 51535572 : inline bool JSObject::isScope() const { return isCall() || isDeclEnv() || isNestedScope(); }
928 8456058 : inline bool JSObject::isStaticBlock() const { return isBlock() && !getProto(); }
929 164644 : inline bool JSObject::isStopIteration() const { return hasClass(&js::StopIterationClass); }
930 35653551 : inline bool JSObject::isStrictArguments() const { return hasClass(&js::StrictArgumentsObjectClass); }
931 5485099 : inline bool JSObject::isString() const { return hasClass(&js::StringClass); }
932 5705 : inline bool JSObject::isWeakMap() const { return hasClass(&js::WeakMapClass); }
933 63436028 : inline bool JSObject::isWith() const { return hasClass(&js::WithClass); }
934 8119942 : inline bool JSObject::isXML() const { return hasClass(&js::XMLClass); }
935 :
936 294122917 : inline bool JSObject::isArray() const
937 : {
938 294122917 : return isSlowArray() || isDenseArray();
939 : }
940 :
941 1233505721 : inline bool JSObject::isDenseArray() const
942 : {
943 1233505721 : bool result = hasClass(&js::ArrayClass);
944 1233505721 : JS_ASSERT_IF(result, elements != js::emptyObjectElements);
945 1233505721 : return result;
946 : }
947 :
948 295492024 : inline bool JSObject::isSlowArray() const
949 : {
950 295492024 : bool result = hasClass(&js::SlowArrayClass);
951 295492024 : JS_ASSERT_IF(result, elements != js::emptyObjectElements);
952 295492024 : return result;
953 : }
954 :
955 : inline bool
956 72 : JSObject::isXMLId() const
957 : {
958 72 : return hasClass(&js::QNameClass)
959 36 : || hasClass(&js::AttributeNameClass)
960 108 : || hasClass(&js::AnyNameClass);
961 : }
962 :
963 : inline bool
964 23703138 : JSObject::isQName() const
965 : {
966 23703138 : return hasClass(&js::QNameClass)
967 29703 : || hasClass(&js::AttributeNameClass)
968 23732841 : || hasClass(&js::AnyNameClass);
969 : }
970 :
971 : inline void
972 5992344 : JSObject::getSlotRangeUnchecked(size_t start, size_t length,
973 : js::HeapSlot **fixedStart, js::HeapSlot **fixedEnd,
974 : js::HeapSlot **slotsStart, js::HeapSlot **slotsEnd)
975 : {
976 5992344 : JS_ASSERT(!isDenseArray());
977 :
978 5992344 : size_t fixed = numFixedSlots();
979 5992344 : if (start < fixed) {
980 5958960 : if (start + length < fixed) {
981 2150971 : *fixedStart = &fixedSlots()[start];
982 2150971 : *fixedEnd = &fixedSlots()[start + length];
983 2150971 : *slotsStart = *slotsEnd = NULL;
984 : } else {
985 3807989 : size_t localCopy = fixed - start;
986 3807989 : *fixedStart = &fixedSlots()[start];
987 3807989 : *fixedEnd = &fixedSlots()[start + localCopy];
988 3807989 : *slotsStart = &slots[0];
989 3807989 : *slotsEnd = &slots[length - localCopy];
990 : }
991 : } else {
992 33384 : *fixedStart = *fixedEnd = NULL;
993 33384 : *slotsStart = &slots[start - fixed];
994 33384 : *slotsEnd = &slots[start - fixed + length];
995 : }
996 5992344 : }
997 :
998 : inline void
999 203834 : JSObject::getSlotRange(size_t start, size_t length,
1000 : js::HeapSlot **fixedStart, js::HeapSlot **fixedEnd,
1001 : js::HeapSlot **slotsStart, js::HeapSlot **slotsEnd)
1002 : {
1003 203834 : JS_ASSERT(slotInRange(start + length, SENTINEL_ALLOWED));
1004 203834 : getSlotRangeUnchecked(start, length, fixedStart, fixedEnd, slotsStart, slotsEnd);
1005 203834 : }
1006 :
1007 : inline void
1008 5788510 : JSObject::initializeSlotRange(size_t start, size_t length)
1009 : {
1010 : /*
1011 : * No bounds check, as this is used when the object's shape does not
1012 : * reflect its allocated slots (updateSlotsForSpan).
1013 : */
1014 : js::HeapSlot *fixedStart, *fixedEnd, *slotsStart, *slotsEnd;
1015 5788510 : getSlotRangeUnchecked(start, length, &fixedStart, &fixedEnd, &slotsStart, &slotsEnd);
1016 :
1017 5788510 : JSCompartment *comp = compartment();
1018 5788510 : size_t offset = start;
1019 21479826 : for (js::HeapSlot *sp = fixedStart; sp != fixedEnd; sp++)
1020 15691316 : sp->init(comp, this, offset++, js::UndefinedValue());
1021 10923963 : for (js::HeapSlot *sp = slotsStart; sp != slotsEnd; sp++)
1022 5135453 : sp->init(comp, this, offset++, js::UndefinedValue());
1023 5788510 : }
1024 :
1025 : /* static */ inline JSObject *
1026 11355957 : JSObject::create(JSContext *cx, js::gc::AllocKind kind,
1027 : js::HandleShape shape, js::HandleTypeObject type, js::HeapSlot *slots)
1028 : {
1029 : /*
1030 : * Callers must use dynamicSlotsCount to size the initial slot array of the
1031 : * object. We can't check the allocated capacity of the dynamic slots, but
1032 : * make sure their presence is consistent with the shape.
1033 : */
1034 11355957 : JS_ASSERT(shape && type);
1035 11355957 : JS_ASSERT(!!dynamicSlotsCount(shape->numFixedSlots(), shape->slotSpan()) == !!slots);
1036 11355957 : JS_ASSERT(js::gc::GetGCKindSlots(kind, shape->getObjectClass()) == shape->numFixedSlots());
1037 :
1038 11355957 : JSObject *obj = js_NewGCObject(cx, kind);
1039 11355957 : if (!obj)
1040 0 : return NULL;
1041 :
1042 11355957 : obj->shape_.init(shape);
1043 11355957 : obj->type_.init(type);
1044 11355957 : obj->slots = slots;
1045 11355957 : obj->elements = js::emptyObjectElements;
1046 :
1047 11355957 : if (shape->getObjectClass()->hasPrivate())
1048 2664126 : obj->privateRef(shape->numFixedSlots()) = NULL;
1049 :
1050 11355957 : if (size_t span = shape->slotSpan())
1051 2866739 : obj->initializeSlotRange(0, span);
1052 :
1053 11355957 : return obj;
1054 : }
1055 :
1056 : /* static */ inline JSObject *
1057 133544 : JSObject::createDenseArray(JSContext *cx, js::gc::AllocKind kind,
1058 : js::HandleShape shape, js::HandleTypeObject type,
1059 : uint32_t length)
1060 : {
1061 133544 : JS_ASSERT(shape && type);
1062 133544 : JS_ASSERT(shape->getObjectClass() == &js::ArrayClass);
1063 :
1064 : /*
1065 : * Dense arrays are non-native, and never have properties to store.
1066 : * The number of fixed slots in the shape of such objects is zero.
1067 : */
1068 133544 : JS_ASSERT(shape->numFixedSlots() == 0);
1069 :
1070 : /*
1071 : * The array initially stores its elements inline, there must be enough
1072 : * space for an elements header.
1073 : */
1074 133544 : JS_ASSERT(js::gc::GetGCKindSlots(kind) >= js::ObjectElements::VALUES_PER_HEADER);
1075 :
1076 133544 : uint32_t capacity = js::gc::GetGCKindSlots(kind) - js::ObjectElements::VALUES_PER_HEADER;
1077 :
1078 133544 : JSObject *obj = js_NewGCObject(cx, kind);
1079 133544 : if (!obj) {
1080 0 : js_ReportOutOfMemory(cx);
1081 0 : return NULL;
1082 : }
1083 :
1084 133544 : obj->shape_.init(shape);
1085 133544 : obj->type_.init(type);
1086 133544 : obj->slots = NULL;
1087 133544 : obj->setFixedElements();
1088 133544 : new (obj->getElementsHeader()) js::ObjectElements(capacity, length);
1089 :
1090 133544 : return obj;
1091 : }
1092 :
1093 : inline void
1094 45369271 : JSObject::finish(JSContext *cx)
1095 : {
1096 45369271 : if (hasDynamicSlots())
1097 5333598 : cx->free_(slots);
1098 45369271 : if (hasDynamicElements())
1099 453804 : cx->free_(getElementsHeader());
1100 45369271 : }
1101 :
1102 : inline bool
1103 4834689 : JSObject::hasProperty(JSContext *cx, jsid id, bool *foundp, unsigned flags)
1104 : {
1105 : JSObject *pobj;
1106 : JSProperty *prop;
1107 9669378 : JSAutoResolveFlags rf(cx, flags);
1108 4834689 : if (!lookupGeneric(cx, id, &pobj, &prop))
1109 0 : return false;
1110 4834689 : *foundp = !!prop;
1111 4834689 : return true;
1112 : }
1113 :
1114 : inline bool
1115 10107390 : JSObject::isCallable()
1116 : {
1117 10107390 : return isFunction() || getClass()->call;
1118 : }
1119 :
1120 : inline JSPrincipals *
1121 106462 : JSObject::principals(JSContext *cx)
1122 : {
1123 106462 : if (JSObjectPrincipalsFinder find = cx->runtime->securityCallbacks->findObjectPrincipals)
1124 578 : return find(this);
1125 105884 : return cx->compartment ? cx->compartment->principals : NULL;
1126 : }
1127 :
1128 : inline uint32_t
1129 1050781288 : JSObject::slotSpan() const
1130 : {
1131 1050781288 : if (inDictionaryMode())
1132 363448701 : return lastProperty()->base()->slotSpan();
1133 687332588 : return lastProperty()->slotSpan();
1134 : }
1135 :
1136 : inline js::HeapSlot &
1137 9669830 : JSObject::nativeGetSlotRef(unsigned slot)
1138 : {
1139 9669830 : JS_ASSERT(isNative());
1140 9669830 : JS_ASSERT(slot < slotSpan());
1141 9669830 : return getSlotRef(slot);
1142 : }
1143 :
1144 : inline const js::Value &
1145 152155527 : JSObject::nativeGetSlot(unsigned slot) const
1146 : {
1147 152155527 : JS_ASSERT(isNative());
1148 152155527 : JS_ASSERT(slot < slotSpan());
1149 152155527 : return getSlot(slot);
1150 : }
1151 :
1152 : inline JSFunction *
1153 0 : JSObject::nativeGetMethod(const js::Shape *shape) const
1154 : {
1155 : /*
1156 : * For method shapes, this object must have an uncloned function object in
1157 : * the shape's slot.
1158 : */
1159 0 : JS_ASSERT(shape->isMethod());
1160 : #ifdef DEBUG
1161 0 : JSObject *obj = &nativeGetSlot(shape->slot()).toObject();
1162 0 : JS_ASSERT(obj->isFunction() && !obj->toFunction()->isClonedMethod());
1163 : #endif
1164 :
1165 0 : return static_cast<JSFunction *>(&nativeGetSlot(shape->slot()).toObject());
1166 : }
1167 :
1168 : inline void
1169 62403775 : JSObject::nativeSetSlot(unsigned slot, const js::Value &value)
1170 : {
1171 62403775 : JS_ASSERT(isNative());
1172 62403775 : JS_ASSERT(slot < slotSpan());
1173 62403775 : return setSlot(slot, value);
1174 : }
1175 :
1176 : inline void
1177 14929174 : JSObject::nativeSetSlotWithType(JSContext *cx, const js::Shape *shape, const js::Value &value)
1178 : {
1179 14929174 : nativeSetSlot(shape->slot(), value);
1180 14929174 : js::types::AddTypePropertyId(cx, this, shape->propid(), value);
1181 14929174 : }
1182 :
1183 : inline bool
1184 265183 : JSObject::nativeContains(JSContext *cx, jsid id)
1185 : {
1186 265183 : return nativeLookup(cx, id) != NULL;
1187 : }
1188 :
1189 : inline bool
1190 48572064 : JSObject::nativeContains(JSContext *cx, const js::Shape &shape)
1191 : {
1192 48572064 : return nativeLookup(cx, shape.propid()) == &shape;
1193 : }
1194 :
1195 : inline bool
1196 14913371 : JSObject::nativeEmpty() const
1197 : {
1198 14913371 : return lastProperty()->isEmptyShape();
1199 : }
1200 :
1201 : inline uint32_t
1202 6327744 : JSObject::propertyCount() const
1203 : {
1204 6327744 : return lastProperty()->entryCount();
1205 : }
1206 :
1207 : inline bool
1208 0 : JSObject::hasPropertyTable() const
1209 : {
1210 0 : return lastProperty()->hasTable();
1211 : }
1212 :
1213 : inline size_t
1214 0 : JSObject::computedSizeOfThisSlotsElements() const
1215 : {
1216 0 : size_t n = sizeOfThis();
1217 :
1218 0 : if (hasDynamicSlots())
1219 0 : n += numDynamicSlots() * sizeof(js::Value);
1220 :
1221 0 : if (hasDynamicElements())
1222 0 : n += (js::ObjectElements::VALUES_PER_HEADER + getElementsHeader()->capacity) *
1223 0 : sizeof(js::Value);
1224 :
1225 0 : return n;
1226 : }
1227 :
1228 : inline void
1229 25914 : JSObject::sizeOfExcludingThis(JSMallocSizeOfFun mallocSizeOf,
1230 : size_t *slotsSize, size_t *elementsSize,
1231 : size_t *miscSize) const
1232 : {
1233 25914 : *slotsSize = 0;
1234 25914 : if (hasDynamicSlots()) {
1235 3624 : *slotsSize += mallocSizeOf(slots);
1236 : }
1237 :
1238 25914 : *elementsSize = 0;
1239 25914 : if (hasDynamicElements()) {
1240 452 : *elementsSize += mallocSizeOf(getElementsHeader());
1241 : }
1242 :
1243 : /* Other things may be measured in the future if DMD indicates it is worthwhile. */
1244 25914 : *miscSize = 0;
1245 25914 : if (isFunction()) {
1246 16046 : *miscSize += toFunction()->sizeOfMisc(mallocSizeOf);
1247 9868 : } else if (isArguments()) {
1248 54 : *miscSize += asArguments().sizeOfMisc(mallocSizeOf);
1249 9814 : } else if (isRegExpStatics()) {
1250 59 : *miscSize += js::SizeOfRegExpStaticsData(this, mallocSizeOf);
1251 : }
1252 25914 : }
1253 :
1254 : inline JSBool
1255 8828898 : JSObject::lookupGeneric(JSContext *cx, jsid id, JSObject **objp, JSProperty **propp)
1256 : {
1257 8828898 : js::LookupGenericOp op = getOps()->lookupGeneric;
1258 8828898 : return (op ? op : js_LookupProperty)(cx, this, id, objp, propp);
1259 : }
1260 :
1261 : inline JSBool
1262 781551 : JSObject::lookupProperty(JSContext *cx, js::PropertyName *name, JSObject **objp, JSProperty **propp)
1263 : {
1264 781551 : return lookupGeneric(cx, ATOM_TO_JSID(name), objp, propp);
1265 : }
1266 :
1267 : inline JSBool
1268 29878559 : JSObject::defineGeneric(JSContext *cx, jsid id, const js::Value &value,
1269 : JSPropertyOp getter /* = JS_PropertyStub */,
1270 : JSStrictPropertyOp setter /* = JS_StrictPropertyStub */,
1271 : unsigned attrs /* = JSPROP_ENUMERATE */)
1272 : {
1273 29878559 : js::DefineGenericOp op = getOps()->defineGeneric;
1274 29878559 : return (op ? op : js_DefineProperty)(cx, this, id, &value, getter, setter, attrs);
1275 : }
1276 :
1277 : inline JSBool
1278 2676661 : JSObject::defineProperty(JSContext *cx, js::PropertyName *name, const js::Value &value,
1279 : JSPropertyOp getter /* = JS_PropertyStub */,
1280 : JSStrictPropertyOp setter /* = JS_StrictPropertyStub */,
1281 : unsigned attrs /* = JSPROP_ENUMERATE */)
1282 : {
1283 2676661 : return defineGeneric(cx, ATOM_TO_JSID(name), value, getter, setter, attrs);
1284 : }
1285 :
1286 : inline JSBool
1287 2068225 : JSObject::defineElement(JSContext *cx, uint32_t index, const js::Value &value,
1288 : JSPropertyOp getter /* = JS_PropertyStub */,
1289 : JSStrictPropertyOp setter /* = JS_StrictPropertyStub */,
1290 : unsigned attrs /* = JSPROP_ENUMERATE */)
1291 : {
1292 2068225 : js::DefineElementOp op = getOps()->defineElement;
1293 2068225 : return (op ? op : js_DefineElement)(cx, this, index, &value, getter, setter, attrs);
1294 : }
1295 :
1296 : inline JSBool
1297 317 : JSObject::defineSpecial(JSContext *cx, js::SpecialId sid, const js::Value &value,
1298 : JSPropertyOp getter /* = JS_PropertyStub */,
1299 : JSStrictPropertyOp setter /* = JS_StrictPropertyStub */,
1300 : unsigned attrs /* = JSPROP_ENUMERATE */)
1301 : {
1302 317 : return defineGeneric(cx, SPECIALID_TO_JSID(sid), value, getter, setter, attrs);
1303 : }
1304 :
1305 : inline JSBool
1306 0 : JSObject::lookupElement(JSContext *cx, uint32_t index, JSObject **objp, JSProperty **propp)
1307 : {
1308 0 : js::LookupElementOp op = getOps()->lookupElement;
1309 0 : return (op ? op : js_LookupElement)(cx, this, index, objp, propp);
1310 : }
1311 :
1312 : inline JSBool
1313 : JSObject::lookupSpecial(JSContext *cx, js::SpecialId sid, JSObject **objp, JSProperty **propp)
1314 : {
1315 : return lookupGeneric(cx, SPECIALID_TO_JSID(sid), objp, propp);
1316 : }
1317 :
1318 : inline JSBool
1319 19714751 : JSObject::getElement(JSContext *cx, JSObject *receiver, uint32_t index, js::Value *vp)
1320 : {
1321 19714751 : js::ElementIdOp op = getOps()->getElement;
1322 19714751 : if (op)
1323 5410478 : return op(cx, this, receiver, index, vp);
1324 :
1325 : jsid id;
1326 14304273 : if (!js::IndexToId(cx, index, &id))
1327 0 : return false;
1328 14304273 : return getGeneric(cx, receiver, id, vp);
1329 : }
1330 :
1331 : inline JSBool
1332 14535151 : JSObject::getElement(JSContext *cx, uint32_t index, js::Value *vp)
1333 : {
1334 14535151 : return getElement(cx, this, index, vp);
1335 : }
1336 :
1337 : inline JSBool
1338 539249 : JSObject::getElementIfPresent(JSContext *cx, JSObject *receiver, uint32_t index, js::Value *vp,
1339 : bool *present)
1340 : {
1341 539249 : js::ElementIfPresentOp op = getOps()->getElementIfPresent;
1342 539249 : if (op)
1343 1656 : return op(cx, this, receiver, index, vp, present);
1344 :
1345 : /* For now, do the index-to-id conversion just once, then use
1346 : * lookupGeneric/getGeneric. Once lookupElement and getElement stop both
1347 : * doing index-to-id conversions, we can use those here.
1348 : */
1349 : jsid id;
1350 537593 : if (!js::IndexToId(cx, index, &id))
1351 0 : return false;
1352 :
1353 : JSObject *obj2;
1354 : JSProperty *prop;
1355 537593 : if (!lookupGeneric(cx, id, &obj2, &prop))
1356 0 : return false;
1357 :
1358 537593 : if (!prop) {
1359 523504 : *present = false;
1360 523504 : js::Debug_SetValueRangeToCrashOnTouch(vp, 1);
1361 523504 : return true;
1362 : }
1363 :
1364 14089 : *present = true;
1365 14089 : return getGeneric(cx, receiver, id, vp);
1366 : }
1367 :
1368 : inline JSBool
1369 7855 : JSObject::getSpecial(JSContext *cx, JSObject *receiver, js::SpecialId sid, js::Value *vp)
1370 : {
1371 7855 : return getGeneric(cx, receiver, SPECIALID_TO_JSID(sid), vp);
1372 : }
1373 :
1374 : inline JSBool
1375 92247 : JSObject::getGenericAttributes(JSContext *cx, jsid id, unsigned *attrsp)
1376 : {
1377 92247 : js::GenericAttributesOp op = getOps()->getGenericAttributes;
1378 92247 : return (op ? op : js_GetAttributes)(cx, this, id, attrsp);
1379 : }
1380 :
1381 : inline JSBool
1382 1217 : JSObject::getPropertyAttributes(JSContext *cx, js::PropertyName *name, unsigned *attrsp)
1383 : {
1384 1217 : return getGenericAttributes(cx, ATOM_TO_JSID(name), attrsp);
1385 : }
1386 :
1387 : inline JSBool
1388 0 : JSObject::getElementAttributes(JSContext *cx, uint32_t index, unsigned *attrsp)
1389 : {
1390 : jsid id;
1391 0 : if (!js::IndexToId(cx, index, &id))
1392 0 : return false;
1393 0 : return getGenericAttributes(cx, id, attrsp);
1394 : }
1395 :
1396 : inline JSBool
1397 0 : JSObject::getSpecialAttributes(JSContext *cx, js::SpecialId sid, unsigned *attrsp)
1398 : {
1399 0 : return getGenericAttributes(cx, SPECIALID_TO_JSID(sid), attrsp);
1400 : }
1401 :
1402 : inline bool
1403 52480384 : JSObject::isProxy() const
1404 : {
1405 52480384 : return js::IsProxy(this);
1406 : }
1407 :
1408 : inline bool
1409 47108 : JSObject::isCrossCompartmentWrapper() const
1410 : {
1411 47108 : return js::IsCrossCompartmentWrapper(this);
1412 : }
1413 :
1414 : inline bool
1415 15624903 : JSObject::isWrapper() const
1416 : {
1417 15624903 : return js::IsWrapper(this);
1418 : }
1419 :
1420 : inline js::GlobalObject &
1421 1011854163 : JSObject::global() const
1422 : {
1423 1011854163 : JSObject *obj = const_cast<JSObject *>(this);
1424 1131835505 : while (JSObject *parent = obj->getParent())
1425 59990671 : obj = parent;
1426 1011854163 : return obj->asGlobal();
1427 : }
1428 :
1429 : static inline bool
1430 3726694 : js_IsCallable(const js::Value &v)
1431 : {
1432 3726694 : return v.isObject() && v.toObject().isCallable();
1433 : }
1434 :
1435 : namespace js {
1436 :
1437 : inline void
1438 8034663 : OBJ_TO_INNER_OBJECT(JSContext *cx, JSObject *&obj)
1439 : {
1440 8034663 : if (JSObjectOp op = obj->getClass()->ext.innerObject)
1441 0 : obj = op(cx, obj);
1442 8034663 : }
1443 :
1444 : inline void
1445 4032964 : OBJ_TO_OUTER_OBJECT(JSContext *cx, JSObject *&obj)
1446 : {
1447 4032964 : if (JSObjectOp op = obj->getClass()->ext.outerObject)
1448 0 : obj = op(cx, obj);
1449 4032964 : }
1450 :
1451 : /*
1452 : * Methods to test whether an object or a value is of type "xml" (per typeof).
1453 : */
1454 :
1455 : #define VALUE_IS_XML(v) (!JSVAL_IS_PRIMITIVE(v) && JSVAL_TO_OBJECT(v)->isXML())
1456 :
1457 : static inline bool
1458 11259285 : IsXML(const js::Value &v)
1459 : {
1460 11259285 : return v.isObject() && v.toObject().isXML();
1461 : }
1462 :
1463 : static inline bool
1464 7329 : IsStopIteration(const js::Value &v)
1465 : {
1466 7329 : return v.isObject() && v.toObject().isStopIteration();
1467 : }
1468 :
1469 : /* ES5 9.1 ToPrimitive(input). */
1470 : static JS_ALWAYS_INLINE bool
1471 29238881 : ToPrimitive(JSContext *cx, Value *vp)
1472 : {
1473 29238881 : if (vp->isPrimitive())
1474 28666950 : return true;
1475 571931 : return vp->toObject().defaultValue(cx, JSTYPE_VOID, vp);
1476 : }
1477 :
1478 : /* ES5 9.1 ToPrimitive(input, PreferredType). */
1479 : static JS_ALWAYS_INLINE bool
1480 15035290 : ToPrimitive(JSContext *cx, JSType preferredType, Value *vp)
1481 : {
1482 15035290 : JS_ASSERT(preferredType != JSTYPE_VOID); /* Use the other ToPrimitive! */
1483 15035290 : if (vp->isPrimitive())
1484 14635269 : return true;
1485 400021 : return vp->toObject().defaultValue(cx, preferredType, vp);
1486 : }
1487 :
1488 : /*
1489 : * Return true if this is a compiler-created internal function accessed by
1490 : * its own object. Such a function object must not be accessible to script
1491 : * or embedding code.
1492 : */
1493 : inline bool
1494 1041072 : IsInternalFunctionObject(JSObject *funobj)
1495 : {
1496 1041072 : JSFunction *fun = funobj->toFunction();
1497 1041072 : return (fun->flags & JSFUN_LAMBDA) && !funobj->getParent();
1498 : }
1499 :
1500 : class AutoPropDescArrayRooter : private AutoGCRooter
1501 597539 : {
1502 : public:
1503 597539 : AutoPropDescArrayRooter(JSContext *cx)
1504 597539 : : AutoGCRooter(cx, DESCRIPTORS), descriptors(cx)
1505 597539 : { }
1506 :
1507 597669 : PropDesc *append() {
1508 597669 : if (!descriptors.append(PropDesc()))
1509 0 : return NULL;
1510 597669 : return &descriptors.back();
1511 : }
1512 :
1513 668 : PropDesc& operator[](size_t i) {
1514 668 : JS_ASSERT(i < descriptors.length());
1515 668 : return descriptors[i];
1516 : }
1517 :
1518 : friend void AutoGCRooter::trace(JSTracer *trc);
1519 :
1520 : private:
1521 : PropDescArray descriptors;
1522 : };
1523 :
1524 : class AutoPropertyDescriptorRooter : private AutoGCRooter, public PropertyDescriptor
1525 14665 : {
1526 : public:
1527 14638 : AutoPropertyDescriptorRooter(JSContext *cx) : AutoGCRooter(cx, DESCRIPTOR) {
1528 14638 : obj = NULL;
1529 14638 : attrs = 0;
1530 14638 : getter = (PropertyOp) NULL;
1531 14638 : setter = (StrictPropertyOp) NULL;
1532 14638 : value.setUndefined();
1533 14638 : }
1534 :
1535 27 : AutoPropertyDescriptorRooter(JSContext *cx, PropertyDescriptor *desc)
1536 27 : : AutoGCRooter(cx, DESCRIPTOR)
1537 : {
1538 27 : obj = desc->obj;
1539 27 : attrs = desc->attrs;
1540 27 : getter = desc->getter;
1541 27 : setter = desc->setter;
1542 27 : value = desc->value;
1543 27 : }
1544 :
1545 : friend void AutoGCRooter::trace(JSTracer *trc);
1546 : };
1547 :
1548 : inline bool
1549 30170174 : NewObjectCache::lookup(Class *clasp, gc::Cell *key, gc::AllocKind kind, EntryIndex *pentry)
1550 : {
1551 30170174 : uintptr_t hash = (uintptr_t(clasp) ^ uintptr_t(key)) + kind;
1552 30170174 : *pentry = hash % js::ArrayLength(entries);
1553 :
1554 30170174 : Entry *entry = &entries[*pentry];
1555 :
1556 : /* N.B. Lookups with the same clasp/key but different kinds map to different entries. */
1557 30170174 : return (entry->clasp == clasp && entry->key == key);
1558 : }
1559 :
1560 : inline bool
1561 4063815 : NewObjectCache::lookupProto(Class *clasp, JSObject *proto, gc::AllocKind kind, EntryIndex *pentry)
1562 : {
1563 4063815 : JS_ASSERT(!proto->isGlobal());
1564 4063815 : return lookup(clasp, proto, kind, pentry);
1565 : }
1566 :
1567 : inline bool
1568 23412993 : NewObjectCache::lookupGlobal(Class *clasp, js::GlobalObject *global, gc::AllocKind kind, EntryIndex *pentry)
1569 : {
1570 23412993 : return lookup(clasp, global, kind, pentry);
1571 : }
1572 :
1573 : inline bool
1574 2693366 : NewObjectCache::lookupType(Class *clasp, js::types::TypeObject *type, gc::AllocKind kind, EntryIndex *pentry)
1575 : {
1576 2693366 : return lookup(clasp, type, kind, pentry);
1577 : }
1578 :
1579 : inline void
1580 1320582 : NewObjectCache::fill(EntryIndex entry_, Class *clasp, gc::Cell *key, gc::AllocKind kind, JSObject *obj)
1581 : {
1582 1320582 : JS_ASSERT(unsigned(entry_) < ArrayLength(entries));
1583 1320582 : Entry *entry = &entries[entry_];
1584 :
1585 1320582 : JS_ASSERT(!obj->hasDynamicSlots() && !obj->hasDynamicElements());
1586 :
1587 1320582 : entry->clasp = clasp;
1588 1320582 : entry->key = key;
1589 1320582 : entry->kind = kind;
1590 :
1591 1320582 : entry->nbytes = obj->sizeOfThis();
1592 1320582 : js_memcpy(&entry->templateObject, obj, entry->nbytes);
1593 1320582 : }
1594 :
1595 : inline void
1596 759091 : NewObjectCache::fillProto(EntryIndex entry, Class *clasp, JSObject *proto, gc::AllocKind kind, JSObject *obj)
1597 : {
1598 759091 : JS_ASSERT(!proto->isGlobal());
1599 759091 : JS_ASSERT(obj->getProto() == proto);
1600 759091 : return fill(entry, clasp, proto, kind, obj);
1601 : }
1602 :
1603 : inline void
1604 489823 : NewObjectCache::fillGlobal(EntryIndex entry, Class *clasp, js::GlobalObject *global, gc::AllocKind kind, JSObject *obj)
1605 : {
1606 : //JS_ASSERT(global == obj->getGlobal());
1607 489823 : return fill(entry, clasp, global, kind, obj);
1608 : }
1609 :
1610 : inline void
1611 71668 : NewObjectCache::fillType(EntryIndex entry, Class *clasp, js::types::TypeObject *type, gc::AllocKind kind, JSObject *obj)
1612 : {
1613 71668 : JS_ASSERT(obj->type() == type);
1614 71668 : return fill(entry, clasp, type, kind, obj);
1615 : }
1616 :
1617 : inline void
1618 28743682 : NewObjectCache::copyCachedToObject(JSObject *dst, JSObject *src)
1619 : {
1620 28743682 : js_memcpy(dst, src, dst->sizeOfThis());
1621 : #ifdef JSGC_GENERATIONAL
1622 : Shape::writeBarrierPost(dst->shape_, &dst->shape_);
1623 : types::TypeObject::writeBarrierPost(dst->type_, &dst->type_);
1624 : #endif
1625 28743682 : }
1626 :
1627 : inline JSObject *
1628 28743683 : NewObjectCache::newObjectFromHit(JSContext *cx, EntryIndex entry_)
1629 : {
1630 28743683 : JS_ASSERT(unsigned(entry_) < ArrayLength(entries));
1631 28743683 : Entry *entry = &entries[entry_];
1632 :
1633 28743683 : JSObject *obj = js_TryNewGCObject(cx, entry->kind);
1634 28743683 : if (obj) {
1635 28376017 : copyCachedToObject(obj, &entry->templateObject);
1636 28376017 : Probes::createObject(cx, obj);
1637 28376017 : return obj;
1638 : }
1639 :
1640 : /* Copy the entry to the stack first in case it is purged by a GC. */
1641 367666 : size_t nbytes = entry->nbytes;
1642 : char stackObject[sizeof(JSObject_Slots16)];
1643 367666 : JS_ASSERT(nbytes <= sizeof(stackObject));
1644 367666 : js_memcpy(&stackObject, &entry->templateObject, nbytes);
1645 :
1646 367666 : JSObject *baseobj = (JSObject *) stackObject;
1647 735332 : RootShape shapeRoot(cx, (Shape **) baseobj->addressOfShape());
1648 735332 : RootTypeObject typeRoot(cx, (types::TypeObject **) baseobj->addressOfType());
1649 :
1650 367666 : obj = js_NewGCObject(cx, entry->kind);
1651 367666 : if (obj) {
1652 367665 : copyCachedToObject(obj, baseobj);
1653 367665 : Probes::createObject(cx, obj);
1654 367665 : return obj;
1655 : }
1656 :
1657 1 : return NULL;
1658 : }
1659 :
1660 : static inline bool
1661 37757149 : CanBeFinalizedInBackground(gc::AllocKind kind, Class *clasp)
1662 : {
1663 : #ifdef JS_THREADSAFE
1664 37757149 : JS_ASSERT(kind <= gc::FINALIZE_OBJECT_LAST);
1665 : /* If the class has no finalizer or a finalizer that is safe to call on
1666 : * a different thread, we change the finalize kind. For example,
1667 : * FINALIZE_OBJECT0 calls the finalizer on the main thread,
1668 : * FINALIZE_OBJECT0_BACKGROUND calls the finalizer on the gcHelperThread.
1669 : * IsBackgroundAllocKind is called to prevent recursively incrementing
1670 : * the finalize kind; kind may already be a background finalize kind.
1671 : */
1672 37757149 : if (!gc::IsBackgroundAllocKind(kind) && !clasp->finalize)
1673 12938623 : return true;
1674 : #endif
1675 24818526 : return false;
1676 : }
1677 :
1678 : /*
1679 : * Make an object with the specified prototype. If parent is null, it will
1680 : * default to the prototype's global if the prototype is non-null.
1681 : */
1682 : JSObject *
1683 : NewObjectWithGivenProto(JSContext *cx, js::Class *clasp, JSObject *proto, JSObject *parent,
1684 : gc::AllocKind kind);
1685 :
1686 : inline JSObject *
1687 1051708 : NewObjectWithGivenProto(JSContext *cx, js::Class *clasp, JSObject *proto, JSObject *parent)
1688 : {
1689 1051708 : gc::AllocKind kind = gc::GetGCObjectKind(clasp);
1690 1051708 : return NewObjectWithGivenProto(cx, clasp, proto, parent, kind);
1691 : }
1692 :
1693 : inline JSProtoKey
1694 35705764 : GetClassProtoKey(js::Class *clasp)
1695 : {
1696 35705764 : JSProtoKey key = JSCLASS_CACHED_PROTO_KEY(clasp);
1697 35705764 : if (key != JSProto_Null)
1698 35173994 : return key;
1699 531770 : if (clasp->flags & JSCLASS_IS_ANONYMOUS)
1700 846 : return JSProto_Object;
1701 530924 : return JSProto_Null;
1702 : }
1703 :
1704 : inline bool
1705 7885235 : FindProto(JSContext *cx, js::Class *clasp, HandleObject parent, JSObject **proto)
1706 : {
1707 7885235 : JSProtoKey protoKey = GetClassProtoKey(clasp);
1708 7885235 : if (!js_GetClassPrototype(cx, parent, protoKey, proto, clasp))
1709 0 : return false;
1710 7885235 : if (!(*proto) && !js_GetClassPrototype(cx, parent, JSProto_Object, proto))
1711 0 : return false;
1712 7885235 : return true;
1713 : }
1714 :
1715 : /*
1716 : * Make an object with the prototype set according to the specified prototype or class:
1717 : *
1718 : * if proto is non-null:
1719 : * use the specified proto
1720 : * for a built-in class:
1721 : * use the memoized original value of the class constructor .prototype
1722 : * property object
1723 : * else if available
1724 : * the current value of .prototype
1725 : * else
1726 : * Object.prototype.
1727 : *
1728 : * The class prototype will be fetched from the parent's global. If global is
1729 : * null, the context's active global will be used, and the resulting object's
1730 : * parent will be that global.
1731 : */
1732 : JSObject *
1733 : NewObjectWithClassProto(JSContext *cx, js::Class *clasp, JSObject *proto, JSObject *parent,
1734 : gc::AllocKind kind);
1735 :
1736 : inline JSObject *
1737 3554241 : NewObjectWithClassProto(JSContext *cx, js::Class *clasp, JSObject *proto, JSObject *parent)
1738 : {
1739 3554241 : gc::AllocKind kind = gc::GetGCObjectKind(clasp);
1740 3554241 : return NewObjectWithClassProto(cx, clasp, proto, parent, kind);
1741 : }
1742 :
1743 : /*
1744 : * Create a native instance of the given class with parent and proto set
1745 : * according to the context's active global.
1746 : */
1747 : inline JSObject *
1748 13736648 : NewBuiltinClassInstance(JSContext *cx, Class *clasp, gc::AllocKind kind)
1749 : {
1750 13736648 : return NewObjectWithClassProto(cx, clasp, NULL, NULL, kind);
1751 : }
1752 :
1753 : inline JSObject *
1754 10837954 : NewBuiltinClassInstance(JSContext *cx, Class *clasp)
1755 : {
1756 10837954 : gc::AllocKind kind = gc::GetGCObjectKind(clasp);
1757 10837954 : return NewBuiltinClassInstance(cx, clasp, kind);
1758 : }
1759 :
1760 : inline GlobalObject *
1761 18648702 : GetCurrentGlobal(JSContext *cx)
1762 : {
1763 18648702 : JSObject *scopeChain = (cx->hasfp()) ? &cx->fp()->scopeChain() : cx->globalObject;
1764 18648702 : return scopeChain ? &scopeChain->global() : NULL;
1765 : }
1766 :
1767 : bool
1768 : FindClassPrototype(JSContext *cx, JSObject *scope, JSProtoKey protoKey, JSObject **protop,
1769 : Class *clasp);
1770 :
1771 : /*
1772 : * Create a plain object with the specified type. This bypasses getNewType to
1773 : * avoid losing creation site information for objects made by scripted 'new'.
1774 : */
1775 : JSObject *
1776 : NewObjectWithType(JSContext *cx, types::TypeObject *type, JSObject *parent, gc::AllocKind kind);
1777 :
1778 : /* Make an object with pregenerated shape from a NEWOBJECT bytecode. */
1779 : static inline JSObject *
1780 2613913 : CopyInitializerObject(JSContext *cx, JSObject *baseobj, types::TypeObject *type)
1781 : {
1782 2613913 : JS_ASSERT(baseobj->getClass() == &ObjectClass);
1783 2613913 : JS_ASSERT(!baseobj->inDictionaryMode());
1784 :
1785 2613913 : gc::AllocKind kind = gc::GetGCObjectFixedSlotsKind(baseobj->numFixedSlots());
1786 : #ifdef JS_THREADSAFE
1787 2613913 : kind = gc::GetBackgroundAllocKind(kind);
1788 : #endif
1789 2613913 : JS_ASSERT(kind == baseobj->getAllocKind());
1790 2613913 : JSObject *obj = NewBuiltinClassInstance(cx, &ObjectClass, kind);
1791 :
1792 2613913 : if (!obj)
1793 1 : return NULL;
1794 :
1795 2613912 : obj->setType(type);
1796 :
1797 2613912 : if (!obj->setLastProperty(cx, baseobj->lastProperty()))
1798 0 : return NULL;
1799 :
1800 2613912 : return obj;
1801 : }
1802 :
1803 : JSObject *
1804 : NewReshapedObject(JSContext *cx, js::types::TypeObject *type, JSObject *parent,
1805 : gc::AllocKind kind, const Shape *shape);
1806 :
1807 : /*
1808 : * As for gc::GetGCObjectKind, where numSlots is a guess at the final size of
1809 : * the object, zero if the final size is unknown. This should only be used for
1810 : * objects that do not require any fixed slots.
1811 : */
1812 : static inline gc::AllocKind
1813 279737 : GuessObjectGCKind(size_t numSlots)
1814 : {
1815 279737 : if (numSlots)
1816 7390 : return gc::GetGCObjectKind(numSlots);
1817 272347 : return gc::FINALIZE_OBJECT4;
1818 : }
1819 :
1820 : static inline gc::AllocKind
1821 2960481 : GuessArrayGCKind(size_t numSlots)
1822 : {
1823 2960481 : if (numSlots)
1824 2558224 : return gc::GetGCArrayKind(numSlots);
1825 402257 : return gc::FINALIZE_OBJECT8;
1826 : }
1827 :
1828 : /*
1829 : * Get the GC kind to use for scripted 'new' on the given class.
1830 : * FIXME bug 547327: estimate the size from the allocation site.
1831 : */
1832 : static inline gc::AllocKind
1833 2311836 : NewObjectGCKind(JSContext *cx, js::Class *clasp)
1834 : {
1835 2311836 : if (clasp == &ArrayClass || clasp == &SlowArrayClass)
1836 0 : return gc::FINALIZE_OBJECT8;
1837 2311836 : if (clasp == &FunctionClass)
1838 0 : return gc::FINALIZE_OBJECT2;
1839 2311836 : return gc::FINALIZE_OBJECT4;
1840 : }
1841 :
1842 : /*
1843 : * Fill slots with the initial slot array to use for a newborn object which
1844 : * may or may not need dynamic slots.
1845 : */
1846 : inline bool
1847 9566709 : PreallocateObjectDynamicSlots(JSContext *cx, Shape *shape, HeapSlot **slots)
1848 : {
1849 9566709 : if (size_t count = JSObject::dynamicSlotsCount(shape->numFixedSlots(), shape->slotSpan())) {
1850 57874 : *slots = (HeapSlot *) cx->malloc_(count * sizeof(HeapSlot));
1851 57874 : if (!*slots)
1852 0 : return false;
1853 57874 : Debug_SetSlotRangeToCrashOnTouch(*slots, count);
1854 57874 : return true;
1855 : }
1856 9508835 : *slots = NULL;
1857 9508835 : return true;
1858 : }
1859 :
1860 : inline bool
1861 113784 : DefineConstructorAndPrototype(JSContext *cx, GlobalObject *global,
1862 : JSProtoKey key, JSObject *ctor, JSObject *proto)
1863 : {
1864 113784 : JS_ASSERT(!global->nativeEmpty()); /* reserved slots already allocated */
1865 113784 : JS_ASSERT(ctor);
1866 113784 : JS_ASSERT(proto);
1867 :
1868 113784 : jsid id = ATOM_TO_JSID(cx->runtime->atomState.classAtoms[key]);
1869 113784 : JS_ASSERT(!global->nativeLookup(cx, id));
1870 :
1871 : /* Set these first in case AddTypePropertyId looks for this class. */
1872 113784 : global->setSlot(key, ObjectValue(*ctor));
1873 113784 : global->setSlot(key + JSProto_LIMIT, ObjectValue(*proto));
1874 113784 : global->setSlot(key + JSProto_LIMIT * 2, ObjectValue(*ctor));
1875 :
1876 113784 : types::AddTypePropertyId(cx, global, id, ObjectValue(*ctor));
1877 113784 : if (!global->addDataProperty(cx, id, key + JSProto_LIMIT * 2, 0)) {
1878 0 : global->setSlot(key, UndefinedValue());
1879 0 : global->setSlot(key + JSProto_LIMIT, UndefinedValue());
1880 0 : global->setSlot(key + JSProto_LIMIT * 2, UndefinedValue());
1881 0 : return false;
1882 : }
1883 :
1884 113784 : return true;
1885 : }
1886 :
1887 : bool
1888 579792 : PropDesc::checkGetter(JSContext *cx)
1889 : {
1890 579792 : if (hasGet && !js_IsCallable(get) && !get.isUndefined()) {
1891 : JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, JSMSG_BAD_GET_SET_FIELD,
1892 18 : js_getter_str);
1893 18 : return false;
1894 : }
1895 579774 : return true;
1896 : }
1897 :
1898 : bool
1899 20416 : PropDesc::checkSetter(JSContext *cx)
1900 : {
1901 20416 : if (hasSet && !js_IsCallable(set) && !set.isUndefined()) {
1902 : JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, JSMSG_BAD_GET_SET_FIELD,
1903 0 : js_setter_str);
1904 0 : return false;
1905 : }
1906 20416 : return true;
1907 : }
1908 :
1909 : inline bool
1910 1349144 : ObjectClassIs(JSObject &obj, ESClassValue classValue, JSContext *cx)
1911 : {
1912 1349144 : if (JS_UNLIKELY(obj.isProxy()))
1913 595 : return Proxy::objectClassIs(&obj, classValue, cx);
1914 :
1915 1348549 : switch (classValue) {
1916 142131 : case ESClass_Array: return obj.isArray();
1917 39429 : case ESClass_Number: return obj.isNumber();
1918 39417 : case ESClass_String: return obj.isString();
1919 39390 : case ESClass_Boolean: return obj.isBoolean();
1920 1088182 : case ESClass_RegExp: return obj.isRegExp();
1921 : }
1922 0 : JS_NOT_REACHED("bad classValue");
1923 : return false;
1924 : }
1925 :
1926 : inline bool
1927 1189042 : IsObjectWithClass(const Value &v, ESClassValue classValue, JSContext *cx)
1928 : {
1929 1189042 : if (!v.isObject())
1930 641318 : return false;
1931 547724 : return ObjectClassIs(v.toObject(), classValue, cx);
1932 : }
1933 :
1934 : static JS_ALWAYS_INLINE bool
1935 4763782 : ValueIsSpecial(JSObject *obj, Value *propval, SpecialId *sidp, JSContext *cx)
1936 : {
1937 4763782 : if (!propval->isObject())
1938 4737681 : return false;
1939 :
1940 : #if JS_HAS_XML_SUPPORT
1941 26101 : if (obj->isXML()) {
1942 0 : *sidp = SpecialId(propval->toObject());
1943 0 : return true;
1944 : }
1945 :
1946 26101 : JSObject &propobj = propval->toObject();
1947 : JSAtom *name;
1948 26101 : if (propobj.isQName() && GetLocalNameFromFunctionQName(&propobj, &name, cx)) {
1949 0 : propval->setString(name);
1950 0 : return false;
1951 : }
1952 : #endif
1953 :
1954 26101 : return false;
1955 : }
1956 :
1957 : JSObject *
1958 : DefineConstructorAndPrototype(JSContext *cx, HandleObject obj, JSProtoKey key, HandleAtom atom,
1959 : JSObject *protoProto, Class *clasp,
1960 : Native constructor, unsigned nargs,
1961 : JSPropertySpec *ps, JSFunctionSpec *fs,
1962 : JSPropertySpec *static_ps, JSFunctionSpec *static_fs,
1963 : JSObject **ctorp = NULL,
1964 : gc::AllocKind ctorKind = JSFunction::FinalizeKind);
1965 :
1966 : } /* namespace js */
1967 :
1968 : extern JSObject *
1969 : js_InitClass(JSContext *cx, js::HandleObject obj, JSObject *parent_proto,
1970 : js::Class *clasp, JSNative constructor, unsigned nargs,
1971 : JSPropertySpec *ps, JSFunctionSpec *fs,
1972 : JSPropertySpec *static_ps, JSFunctionSpec *static_fs,
1973 : JSObject **ctorp = NULL,
1974 : js::gc::AllocKind ctorKind = JSFunction::FinalizeKind);
1975 :
1976 : inline JSObject *
1977 49399763 : js_GetProtoIfDenseArray(JSObject *obj)
1978 : {
1979 49399763 : return obj->isDenseArray() ? obj->getProto() : obj;
1980 : }
1981 :
1982 : /*
1983 : * js_PurgeScopeChain does nothing if obj is not itself a prototype or parent
1984 : * scope, else it reshapes the scope and prototype chains it links. It calls
1985 : * js_PurgeScopeChainHelper, which asserts that obj is flagged as a delegate
1986 : * (i.e., obj has ever been on a prototype or parent chain).
1987 : */
1988 : extern bool
1989 : js_PurgeScopeChainHelper(JSContext *cx, JSObject *obj, jsid id);
1990 :
1991 : inline bool
1992 40461445 : js_PurgeScopeChain(JSContext *cx, JSObject *obj, jsid id)
1993 : {
1994 40461445 : if (obj->isDelegate())
1995 1135076 : return js_PurgeScopeChainHelper(cx, obj, id);
1996 39326369 : return true;
1997 : }
1998 :
1999 : inline void
2000 88574377 : JSObject::setSlot(unsigned slot, const js::Value &value)
2001 : {
2002 88574377 : JS_ASSERT(slotInRange(slot));
2003 88574377 : getSlotRef(slot).set(this, slot, value);
2004 88574377 : }
2005 :
2006 : inline void
2007 2146014 : JSObject::initSlot(unsigned slot, const js::Value &value)
2008 : {
2009 2146014 : JS_ASSERT(getSlot(slot).isUndefined() || getSlot(slot).isMagic(JS_ARRAY_HOLE));
2010 2146014 : JS_ASSERT(slotInRange(slot));
2011 2146014 : initSlotUnchecked(slot, value);
2012 2146014 : }
2013 :
2014 : inline void
2015 29867194 : JSObject::initSlotUnchecked(unsigned slot, const js::Value &value)
2016 : {
2017 29867194 : getSlotAddressUnchecked(slot)->init(this, slot, value);
2018 29867194 : }
2019 :
2020 : inline void
2021 13920096 : JSObject::setFixedSlot(unsigned slot, const js::Value &value)
2022 : {
2023 13920096 : JS_ASSERT(slot < numFixedSlots());
2024 13920096 : fixedSlots()[slot].set(this, slot, value);
2025 13920096 : }
2026 :
2027 : inline void
2028 2648280 : JSObject::initFixedSlot(unsigned slot, const js::Value &value)
2029 : {
2030 2648280 : JS_ASSERT(slot < numFixedSlots());
2031 2648280 : fixedSlots()[slot].init(this, slot, value);
2032 2648280 : }
2033 :
2034 : #endif /* jsobjinlines_h___ */
|