1 : /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
2 : *
3 : * ***** BEGIN LICENSE BLOCK *****
4 : * Version: MPL 1.1/GPL 2.0/LGPL 2.1
5 : *
6 : * The contents of this file are subject to the Mozilla Public License Version
7 : * 1.1 (the "License"); you may not use this file except in compliance with
8 : * the License. You may obtain a copy of the License at
9 : * http://www.mozilla.org/MPL/
10 : *
11 : * Software distributed under the License is distributed on an "AS IS" basis,
12 : * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
13 : * for the specific language governing rights and limitations under the
14 : * License.
15 : *
16 : * The Original Code is Mozilla Communicator client code, released
17 : * March 31, 1998.
18 : *
19 : * The Initial Developer of the Original Code is
20 : * Netscape Communications Corporation.
21 : * Portions created by the Initial Developer are Copyright (C) 1998
22 : * the Initial Developer. All Rights Reserved.
23 : *
24 : * Contributor(s):
25 : *
26 : * Alternatively, the contents of this file may be used under the terms of
27 : * either of the GNU General Public License Version 2 or later (the "GPL"),
28 : * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
29 : * in which case the provisions of the GPL or the LGPL are applicable instead
30 : * of those above. If you wish to allow use of your version of this file only
31 : * under the terms of either the GPL or the LGPL, and not to allow others to
32 : * use your version of this file under the terms of the MPL, indicate your
33 : * decision by deleting the provisions above and replace them with the notice
34 : * and other provisions required by the GPL or the LGPL. If you do not delete
35 : * the provisions above, a recipient may use your version of this file under
36 : * the terms of any one of the MPL, the GPL or the LGPL.
37 : *
38 : * ***** END LICENSE BLOCK ***** */
39 :
40 : #ifndef jsscopeinlines_h___
41 : #define jsscopeinlines_h___
42 :
43 : #include <new>
44 :
45 : #include "jsarray.h"
46 : #include "jsbool.h"
47 : #include "jscntxt.h"
48 : #include "jsdbgapi.h"
49 : #include "jsfun.h"
50 : #include "jsobj.h"
51 : #include "jsscope.h"
52 : #include "jsgc.h"
53 : #include "jsgcmark.h"
54 :
55 : #include "vm/ArgumentsObject.h"
56 : #include "vm/ScopeObject.h"
57 : #include "vm/StringObject.h"
58 :
59 : #include "jscntxtinlines.h"
60 : #include "jsgcinlines.h"
61 : #include "jsobjinlines.h"
62 :
63 : #include "vm/ScopeObject-inl.h"
64 :
65 : namespace js {
66 :
67 : inline
68 : BaseShape::BaseShape(Class *clasp, JSObject *parent, uint32_t objectFlags)
69 : {
70 : JS_ASSERT(!(objectFlags & ~OBJECT_FLAG_MASK));
71 : PodZero(this);
72 : this->clasp = clasp;
73 : this->parent = parent;
74 : this->flags = objectFlags;
75 : }
76 :
77 : inline
78 : BaseShape::BaseShape(Class *clasp, JSObject *parent, uint32_t objectFlags,
79 : uint8_t attrs, js::PropertyOp rawGetter, js::StrictPropertyOp rawSetter)
80 : {
81 : JS_ASSERT(!(objectFlags & ~OBJECT_FLAG_MASK));
82 : PodZero(this);
83 : this->clasp = clasp;
84 : this->parent = parent;
85 : this->flags = objectFlags;
86 : this->rawGetter = rawGetter;
87 : this->rawSetter = rawSetter;
88 : if ((attrs & JSPROP_GETTER) && rawGetter) {
89 : this->flags |= HAS_GETTER_OBJECT;
90 : JSObject::writeBarrierPost(this->getterObj, &this->getterObj);
91 : }
92 : if ((attrs & JSPROP_SETTER) && rawSetter) {
93 : this->flags |= HAS_SETTER_OBJECT;
94 : JSObject::writeBarrierPost(this->setterObj, &this->setterObj);
95 : }
96 : }
97 :
98 : inline
99 7215781 : BaseShape::BaseShape(const StackBaseShape &base)
100 : {
101 7215781 : PodZero(this);
102 7215781 : this->clasp = base.clasp;
103 7215781 : this->parent = base.parent;
104 7215781 : this->flags = base.flags;
105 7215781 : this->rawGetter = base.rawGetter;
106 7215781 : this->rawSetter = base.rawSetter;
107 7215781 : if ((base.flags & HAS_GETTER_OBJECT) && base.rawGetter) {
108 2423342 : JSObject::writeBarrierPost(this->getterObj, &this->getterObj);
109 : }
110 7215781 : if ((base.flags & HAS_SETTER_OBJECT) && base.rawSetter) {
111 438964 : JSObject::writeBarrierPost(this->setterObj, &this->setterObj);
112 : }
113 7215781 : }
114 :
115 : inline BaseShape &
116 4795011 : BaseShape::operator=(const BaseShape &other)
117 : {
118 4795011 : clasp = other.clasp;
119 4795011 : parent = other.parent;
120 4795011 : flags = other.flags;
121 4795011 : slotSpan_ = other.slotSpan_;
122 4795011 : if (flags & HAS_GETTER_OBJECT) {
123 362331 : getterObj = other.getterObj;
124 362331 : JSObject::writeBarrierPost(getterObj, &getterObj);
125 : } else {
126 4432680 : rawGetter = other.rawGetter;
127 : }
128 4795011 : if (flags & HAS_SETTER_OBJECT) {
129 11130 : setterObj = other.setterObj;
130 11130 : JSObject::writeBarrierPost(setterObj, &setterObj);
131 : } else {
132 4783881 : rawSetter = other.rawSetter;
133 : }
134 4795011 : return *this;
135 : }
136 :
137 : inline bool
138 41063073 : BaseShape::matchesGetterSetter(PropertyOp rawGetter, StrictPropertyOp rawSetter) const
139 : {
140 41063073 : return rawGetter == this->rawGetter && rawSetter == this->rawSetter;
141 : }
142 :
143 : inline
144 5416481 : StackBaseShape::StackBaseShape(Shape *shape)
145 5416481 : : flags(shape->getObjectFlags()),
146 5416481 : clasp(shape->getObjectClass()),
147 10832962 : parent(shape->getObjectParent())
148 : {
149 5416481 : updateGetterSetter(shape->attrs, shape->getter(), shape->setter());
150 5416481 : }
151 :
152 : inline void
153 29089312 : StackBaseShape::updateGetterSetter(uint8_t attrs,
154 : PropertyOp rawGetter,
155 : StrictPropertyOp rawSetter)
156 : {
157 29089312 : flags &= ~(BaseShape::HAS_GETTER_OBJECT | BaseShape::HAS_SETTER_OBJECT);
158 29089312 : if ((attrs & JSPROP_GETTER) && rawGetter)
159 2447159 : flags |= BaseShape::HAS_GETTER_OBJECT;
160 29089312 : if ((attrs & JSPROP_SETTER) && rawSetter)
161 458841 : flags |= BaseShape::HAS_SETTER_OBJECT;
162 :
163 29089312 : this->rawGetter = rawGetter;
164 29089312 : this->rawSetter = rawSetter;
165 29089312 : }
166 :
167 : inline void
168 4795011 : BaseShape::adoptUnowned(UnownedBaseShape *other)
169 : {
170 : /*
171 : * This is a base shape owned by a dictionary object, update it to reflect the
172 : * unowned base shape of a new last property.
173 : */
174 4795011 : JS_ASSERT(isOwned());
175 9590022 : DebugOnly<uint32_t> flags = getObjectFlags();
176 4795011 : JS_ASSERT((flags & other->getObjectFlags()) == flags);
177 :
178 4795011 : uint32_t span = slotSpan();
179 4795011 : PropertyTable *table = &this->table();
180 :
181 4795011 : *this = *other;
182 4795011 : setOwned(other);
183 4795011 : setTable(table);
184 4795011 : setSlotSpan(span);
185 :
186 4795011 : assertConsistency();
187 4795011 : }
188 :
189 : inline void
190 5146686 : BaseShape::setOwned(UnownedBaseShape *unowned)
191 : {
192 5146686 : flags |= OWNED_SHAPE;
193 5146686 : this->unowned_ = unowned;
194 5146686 : }
195 :
196 : inline void
197 20492213 : BaseShape::assertConsistency()
198 : {
199 : #ifdef DEBUG
200 20492213 : if (isOwned()) {
201 6371446 : UnownedBaseShape *unowned = baseUnowned();
202 6371446 : JS_ASSERT(hasGetterObject() == unowned->hasGetterObject());
203 6371446 : JS_ASSERT(hasSetterObject() == unowned->hasSetterObject());
204 6371446 : JS_ASSERT_IF(hasGetterObject(), getterObject() == unowned->getterObject());
205 6371446 : JS_ASSERT_IF(hasSetterObject(), setterObject() == unowned->setterObject());
206 6371446 : JS_ASSERT(getObjectParent() == unowned->getObjectParent());
207 6371446 : JS_ASSERT(getObjectFlags() == unowned->getObjectFlags());
208 : }
209 : #endif
210 20492213 : }
211 :
212 : inline
213 29000040 : Shape::Shape(const StackShape &other, uint32_t nfixed)
214 : : base_(other.base),
215 : propid_(other.propid),
216 29000040 : slotInfo(other.maybeSlot() | (nfixed << FIXED_SLOTS_SHIFT)),
217 : attrs(other.attrs),
218 : flags(other.flags),
219 : shortid_(other.shortid),
220 58000080 : parent(NULL)
221 : {
222 29000040 : kids.setNull();
223 29000040 : }
224 :
225 : inline
226 4739372 : Shape::Shape(UnownedBaseShape *base, uint32_t nfixed)
227 : : base_(base),
228 : propid_(JSID_EMPTY),
229 : slotInfo(SHAPE_INVALID_SLOT | (nfixed << FIXED_SLOTS_SHIFT)),
230 : attrs(JSPROP_SHARED),
231 : flags(0),
232 : shortid_(0),
233 4739372 : parent(NULL)
234 : {
235 4739372 : JS_ASSERT(base);
236 4739372 : kids.setNull();
237 4739372 : }
238 :
239 : inline JSDHashNumber
240 12426392 : StackShape::hash() const
241 : {
242 12426392 : JSDHashNumber hash = uintptr_t(base);
243 :
244 : /* Accumulate from least to most random so the low bits are most random. */
245 12426392 : hash = JS_ROTATE_LEFT32(hash, 4) ^ (flags & Shape::PUBLIC_FLAGS);
246 12426392 : hash = JS_ROTATE_LEFT32(hash, 4) ^ attrs;
247 12426392 : hash = JS_ROTATE_LEFT32(hash, 4) ^ shortid;
248 12426392 : hash = JS_ROTATE_LEFT32(hash, 4) ^ slot_;
249 12426392 : hash = JS_ROTATE_LEFT32(hash, 4) ^ JSID_BITS(propid);
250 12426392 : return hash;
251 : }
252 :
253 : inline bool
254 973294 : Shape::matches(const js::Shape *other) const
255 : {
256 973294 : return propid_.get() == other->propid_.get() &&
257 : matchesParamsAfterId(other->base(), other->maybeSlot(), other->attrs,
258 973294 : other->flags, other->shortid_);
259 : }
260 :
261 : inline bool
262 26621915 : Shape::matches(const StackShape &other) const
263 : {
264 26621915 : return propid_.get() == other.propid &&
265 26621915 : matchesParamsAfterId(other.base, other.slot_, other.attrs, other.flags, other.shortid);
266 : }
267 :
268 : inline bool
269 29411969 : Shape::matchesParamsAfterId(BaseShape *base, uint32_t aslot,
270 : unsigned aattrs, unsigned aflags, int ashortid) const
271 : {
272 29411969 : return base->unowned() == this->base()->unowned() &&
273 28049141 : maybeSlot() == aslot &&
274 : attrs == aattrs &&
275 : ((flags ^ aflags) & PUBLIC_FLAGS) == 0 &&
276 57461110 : shortid_ == ashortid;
277 : }
278 :
279 : inline bool
280 5313225 : Shape::get(JSContext* cx, JSObject *receiver, JSObject* obj, JSObject *pobj, js::Value* vp) const
281 : {
282 5313225 : JS_ASSERT(!hasDefaultGetter());
283 :
284 5313225 : if (hasGetterValue()) {
285 3213691 : JS_ASSERT(!isMethod());
286 3213691 : js::Value fval = getterValue();
287 3213691 : return js::InvokeGetterOrSetter(cx, receiver, fval, 0, 0, vp);
288 : }
289 :
290 2099534 : if (isMethod()) {
291 0 : vp->setObject(*pobj->nativeGetMethod(this));
292 0 : return pobj->methodReadBarrier(cx, *this, vp);
293 : }
294 :
295 : /*
296 : * |with (it) color;| ends up here, as do XML filter-expressions.
297 : * Avoid exposing the With object to native getters.
298 : */
299 2099534 : if (obj->isWith())
300 0 : obj = &obj->asWith().object();
301 2099534 : return js::CallJSPropertyOp(cx, getterOp(), receiver, getUserId(), vp);
302 : }
303 :
304 : inline bool
305 354989 : Shape::set(JSContext* cx, JSObject* obj, bool strict, js::Value* vp) const
306 : {
307 354989 : JS_ASSERT_IF(hasDefaultSetter(), hasGetterValue());
308 :
309 354989 : if (attrs & JSPROP_SETTER) {
310 152153 : js::Value fval = setterValue();
311 152153 : return js::InvokeGetterOrSetter(cx, obj, fval, 1, vp, vp);
312 : }
313 :
314 202836 : if (attrs & JSPROP_GETTER)
315 12 : return js_ReportGetterOnlyAssignment(cx);
316 :
317 : /* See the comment in js::Shape::get as to why we check for With. */
318 202824 : if (obj->isWith())
319 0 : obj = &obj->asWith().object();
320 202824 : return js::CallJSPropertyOpSetter(cx, setterOp(), obj, getUserId(), strict, vp);
321 : }
322 :
323 : inline void
324 29000040 : Shape::setParent(js::Shape *p)
325 : {
326 62476812 : JS_ASSERT_IF(p && !p->hasMissingSlot() && !inDictionary(),
327 91476852 : p->maybeSlot() <= maybeSlot());
328 65522913 : JS_ASSERT_IF(p && !inDictionary(),
329 94522953 : hasSlot() == (p->maybeSlot() != maybeSlot()));
330 29000040 : parent = p;
331 29000040 : }
332 :
333 : inline void
334 1508354 : Shape::removeFromDictionary(JSObject *obj)
335 : {
336 1508354 : JS_ASSERT(inDictionary());
337 1508354 : JS_ASSERT(obj->inDictionaryMode());
338 1508354 : JS_ASSERT(listp);
339 :
340 1508354 : JS_ASSERT(obj->shape_->inDictionary());
341 1508354 : JS_ASSERT(obj->shape_->listp == &obj->shape_);
342 :
343 1508354 : if (parent)
344 1491687 : parent->listp = listp;
345 1508354 : *listp = parent;
346 1508354 : listp = NULL;
347 1508354 : }
348 :
349 : inline void
350 8700405 : Shape::insertIntoDictionary(HeapPtrShape *dictp)
351 : {
352 : /*
353 : * Don't assert inDictionaryMode() here because we may be called from
354 : * JSObject::toDictionaryMode via JSObject::newDictionaryShape.
355 : */
356 8700405 : JS_ASSERT(inDictionary());
357 8700405 : JS_ASSERT(!listp);
358 :
359 8700405 : JS_ASSERT_IF(*dictp, (*dictp)->inDictionary());
360 8700405 : JS_ASSERT_IF(*dictp, (*dictp)->listp == dictp);
361 8700405 : JS_ASSERT_IF(*dictp, compartment() == (*dictp)->compartment());
362 :
363 8700405 : setParent(*dictp);
364 8700405 : if (parent)
365 4624008 : parent->listp = &parent;
366 8700405 : listp = (HeapPtrShape *) dictp;
367 8700405 : *dictp = this;
368 8700405 : }
369 :
370 : void
371 8700405 : Shape::initDictionaryShape(const StackShape &child, uint32_t nfixed, HeapPtrShape *dictp)
372 : {
373 8700405 : new (this) Shape(child, nfixed);
374 8700405 : this->flags |= IN_DICTIONARY;
375 :
376 8700405 : this->listp = NULL;
377 8700405 : insertIntoDictionary(dictp);
378 8700405 : }
379 :
380 : inline
381 3712724 : EmptyShape::EmptyShape(UnownedBaseShape *base, uint32_t nfixed)
382 3712724 : : js::Shape(base, nfixed)
383 : {
384 : /* Only empty shapes can be NON_NATIVE. */
385 3712724 : if (!getObjectClass()->isNative())
386 84015 : flags |= NON_NATIVE;
387 3712724 : }
388 :
389 : inline void
390 101468329 : Shape::writeBarrierPre(const js::Shape *shape)
391 : {
392 : #ifdef JSGC_INCREMENTAL
393 101468329 : if (!shape)
394 42729522 : return;
395 :
396 58738807 : JSCompartment *comp = shape->compartment();
397 58738807 : if (comp->needsBarrier()) {
398 11173 : Shape *tmp = const_cast<Shape *>(shape);
399 11173 : MarkShapeUnbarriered(comp->barrierTracer(), &tmp, "write barrier");
400 11173 : JS_ASSERT(tmp == shape);
401 : }
402 : #endif
403 : }
404 :
405 : inline void
406 147134564 : Shape::writeBarrierPost(const js::Shape *shape, void *addr)
407 : {
408 147134564 : }
409 :
410 : inline void
411 105005532 : Shape::readBarrier(const Shape *shape)
412 : {
413 : #ifdef JSGC_INCREMENTAL
414 105005532 : JSCompartment *comp = shape->compartment();
415 105005532 : if (comp->needsBarrier()) {
416 20830 : Shape *tmp = const_cast<Shape *>(shape);
417 20830 : MarkShapeUnbarriered(comp->barrierTracer(), &tmp, "read barrier");
418 20830 : JS_ASSERT(tmp == shape);
419 : }
420 : #endif
421 105005532 : }
422 :
423 : inline void
424 3706908 : Shape::markChildren(JSTracer *trc)
425 : {
426 3706908 : MarkBaseShape(trc, &base_, "base");
427 3706908 : gc::MarkId(trc, &propidRef(), "propid");
428 3706908 : if (parent)
429 3207569 : MarkShape(trc, &parent, "parent");
430 3706908 : }
431 :
432 : inline void
433 15226949 : BaseShape::writeBarrierPre(BaseShape *base)
434 : {
435 : #ifdef JSGC_INCREMENTAL
436 15226949 : if (!base)
437 351675 : return;
438 :
439 14875274 : JSCompartment *comp = base->compartment();
440 14875274 : if (comp->needsBarrier()) {
441 4026 : BaseShape *tmp = base;
442 4026 : MarkBaseShapeUnbarriered(comp->barrierTracer(), &tmp, "write barrier");
443 4026 : JS_ASSERT(tmp == base);
444 : }
445 : #endif
446 : }
447 :
448 : inline void
449 49318036 : BaseShape::writeBarrierPost(BaseShape *shape, void *addr)
450 : {
451 49318036 : }
452 :
453 : inline void
454 64166991 : BaseShape::readBarrier(BaseShape *base)
455 : {
456 : #ifdef JSGC_INCREMENTAL
457 64166991 : JSCompartment *comp = base->compartment();
458 64166991 : if (comp->needsBarrier()) {
459 2506 : BaseShape *tmp = base;
460 2506 : MarkBaseShapeUnbarriered(comp->barrierTracer(), &tmp, "read barrier");
461 2506 : JS_ASSERT(tmp == base);
462 : }
463 : #endif
464 64166991 : }
465 :
466 : inline void
467 1145720 : BaseShape::markChildren(JSTracer *trc)
468 : {
469 1145720 : if (hasGetterObject())
470 268362 : MarkObjectUnbarriered(trc, &getterObj, "getter");
471 :
472 1145720 : if (hasSetterObject())
473 64564 : MarkObjectUnbarriered(trc, &setterObj, "setter");
474 :
475 1145720 : if (isOwned())
476 38145 : MarkBaseShape(trc, &unowned_, "base");
477 :
478 1145720 : if (parent)
479 1096476 : MarkObject(trc, &parent, "parent");
480 1145720 : }
481 :
482 : } /* namespace js */
483 :
484 : #endif /* jsscopeinlines_h___ */
|