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 3962586 : BaseShape::BaseShape(const StackBaseShape &base)
100 : {
101 3962586 : PodZero(this);
102 3962586 : this->clasp = base.clasp;
103 3962586 : this->parent = base.parent;
104 3962586 : this->flags = base.flags;
105 3962586 : this->rawGetter = base.rawGetter;
106 3962586 : this->rawSetter = base.rawSetter;
107 3962586 : if ((base.flags & HAS_GETTER_OBJECT) && base.rawGetter) {
108 1044856 : JSObject::writeBarrierPost(this->getterObj, &this->getterObj);
109 : }
110 3962586 : if ((base.flags & HAS_SETTER_OBJECT) && base.rawSetter) {
111 187437 : JSObject::writeBarrierPost(this->setterObj, &this->setterObj);
112 : }
113 3962586 : }
114 :
115 : inline BaseShape &
116 2015881 : BaseShape::operator=(const BaseShape &other)
117 : {
118 2015881 : clasp = other.clasp;
119 2015881 : parent = other.parent;
120 2015881 : flags = other.flags;
121 2015881 : slotSpan_ = other.slotSpan_;
122 2015881 : if (flags & HAS_GETTER_OBJECT) {
123 294196 : getterObj = other.getterObj;
124 294196 : JSObject::writeBarrierPost(getterObj, &getterObj);
125 : } else {
126 1721685 : rawGetter = other.rawGetter;
127 : }
128 2015881 : if (flags & HAS_SETTER_OBJECT) {
129 305 : setterObj = other.setterObj;
130 305 : JSObject::writeBarrierPost(setterObj, &setterObj);
131 : } else {
132 2015576 : rawSetter = other.rawSetter;
133 : }
134 2015881 : return *this;
135 : }
136 :
137 : inline bool
138 30109396 : BaseShape::matchesGetterSetter(PropertyOp rawGetter, StrictPropertyOp rawSetter) const
139 : {
140 30109396 : return rawGetter == this->rawGetter && rawSetter == this->rawSetter;
141 : }
142 :
143 : inline
144 1882807 : StackBaseShape::StackBaseShape(Shape *shape)
145 1882807 : : flags(shape->getObjectFlags()),
146 1882807 : clasp(shape->getObjectClass()),
147 3765614 : parent(shape->getObjectParent())
148 : {
149 1882807 : updateGetterSetter(shape->attrs, shape->getter(), shape->setter());
150 1882807 : }
151 :
152 : inline void
153 18148876 : StackBaseShape::updateGetterSetter(uint8_t attrs,
154 : PropertyOp rawGetter,
155 : StrictPropertyOp rawSetter)
156 : {
157 18148876 : flags &= ~(BaseShape::HAS_GETTER_OBJECT | BaseShape::HAS_SETTER_OBJECT);
158 18148876 : if ((attrs & JSPROP_GETTER) && rawGetter)
159 1044966 : flags |= BaseShape::HAS_GETTER_OBJECT;
160 18148876 : if ((attrs & JSPROP_SETTER) && rawSetter)
161 187808 : flags |= BaseShape::HAS_SETTER_OBJECT;
162 :
163 18148876 : this->rawGetter = rawGetter;
164 18148876 : this->rawSetter = rawSetter;
165 18148876 : }
166 :
167 : inline void
168 2015881 : 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 2015881 : JS_ASSERT(isOwned());
175 4031762 : DebugOnly<uint32_t> flags = getObjectFlags();
176 2015881 : JS_ASSERT((flags & other->getObjectFlags()) == flags);
177 :
178 2015881 : uint32_t span = slotSpan();
179 2015881 : PropertyTable *table = &this->table();
180 :
181 2015881 : *this = *other;
182 2015881 : setOwned(other);
183 2015881 : setTable(table);
184 2015881 : setSlotSpan(span);
185 :
186 2015881 : assertConsistency();
187 2015881 : }
188 :
189 : inline void
190 2143271 : BaseShape::setOwned(UnownedBaseShape *unowned)
191 : {
192 2143271 : flags |= OWNED_SHAPE;
193 2143271 : this->unowned_ = unowned;
194 2143271 : }
195 :
196 : inline void
197 8043686 : BaseShape::assertConsistency()
198 : {
199 : #ifdef DEBUG
200 8043686 : if (isOwned()) {
201 2392429 : UnownedBaseShape *unowned = baseUnowned();
202 2392429 : JS_ASSERT(hasGetterObject() == unowned->hasGetterObject());
203 2392429 : JS_ASSERT(hasSetterObject() == unowned->hasSetterObject());
204 2392429 : JS_ASSERT_IF(hasGetterObject(), getterObject() == unowned->getterObject());
205 2392429 : JS_ASSERT_IF(hasSetterObject(), setterObject() == unowned->setterObject());
206 2392429 : JS_ASSERT(getObjectParent() == unowned->getObjectParent());
207 2392429 : JS_ASSERT(getObjectFlags() == unowned->getObjectFlags());
208 : }
209 : #endif
210 8043686 : }
211 :
212 : inline
213 18289201 : Shape::Shape(const StackShape &other, uint32_t nfixed)
214 : : base_(other.base),
215 : propid_(other.propid),
216 18289201 : slotInfo(other.maybeSlot() | (nfixed << FIXED_SLOTS_SHIFT)),
217 : attrs(other.attrs),
218 : flags(other.flags),
219 : shortid_(other.shortid),
220 36578402 : parent(NULL)
221 : {
222 18289201 : kids.setNull();
223 18289201 : }
224 :
225 : inline
226 2225799 : 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 2225799 : parent(NULL)
234 : {
235 2225799 : JS_ASSERT(base);
236 2225799 : kids.setNull();
237 2225799 : }
238 :
239 : inline HashNumber
240 6236301 : StackShape::hash() const
241 : {
242 6236301 : HashNumber hash = uintptr_t(base);
243 :
244 : /* Accumulate from least to most random so the low bits are most random. */
245 6236301 : hash = JS_ROTATE_LEFT32(hash, 4) ^ (flags & Shape::PUBLIC_FLAGS);
246 6236301 : hash = JS_ROTATE_LEFT32(hash, 4) ^ attrs;
247 6236301 : hash = JS_ROTATE_LEFT32(hash, 4) ^ shortid;
248 6236301 : hash = JS_ROTATE_LEFT32(hash, 4) ^ slot_;
249 6236301 : hash = JS_ROTATE_LEFT32(hash, 4) ^ JSID_BITS(propid);
250 6236301 : return hash;
251 : }
252 :
253 : inline bool
254 708487 : Shape::matches(const js::Shape *other) const
255 : {
256 708487 : return propid_.get() == other->propid_.get() &&
257 : matchesParamsAfterId(other->base(), other->maybeSlot(), other->attrs,
258 708487 : other->flags, other->shortid_);
259 : }
260 :
261 : inline bool
262 20468702 : Shape::matches(const StackShape &other) const
263 : {
264 20468702 : return propid_.get() == other.propid &&
265 20468702 : matchesParamsAfterId(other.base, other.slot_, other.attrs, other.flags, other.shortid);
266 : }
267 :
268 : inline bool
269 23061558 : Shape::matchesParamsAfterId(BaseShape *base, uint32_t aslot,
270 : unsigned aattrs, unsigned aflags, int ashortid) const
271 : {
272 23061558 : return base->unowned() == this->base()->unowned() &&
273 21997204 : maybeSlot() == aslot &&
274 : attrs == aattrs &&
275 : ((flags ^ aflags) & PUBLIC_FLAGS) == 0 &&
276 45058762 : shortid_ == ashortid;
277 : }
278 :
279 : inline bool
280 1172451 : Shape::get(JSContext* cx, JSObject *receiver, JSObject* obj, JSObject *pobj, js::Value* vp) const
281 : {
282 1172451 : JS_ASSERT(!hasDefaultGetter());
283 :
284 1172451 : if (hasGetterValue()) {
285 336897 : js::Value fval = getterValue();
286 336897 : return js::InvokeGetterOrSetter(cx, receiver, fval, 0, 0, vp);
287 : }
288 :
289 : /*
290 : * |with (it) color;| ends up here, as do XML filter-expressions.
291 : * Avoid exposing the With object to native getters.
292 : */
293 835554 : if (obj->isWith())
294 0 : obj = &obj->asWith().object();
295 835554 : return js::CallJSPropertyOp(cx, getterOp(), receiver, getUserId(), vp);
296 : }
297 :
298 : inline bool
299 31852 : Shape::set(JSContext* cx, JSObject* obj, bool strict, js::Value* vp) const
300 : {
301 31852 : JS_ASSERT_IF(hasDefaultSetter(), hasGetterValue());
302 :
303 31852 : if (attrs & JSPROP_SETTER) {
304 9469 : js::Value fval = setterValue();
305 9469 : return js::InvokeGetterOrSetter(cx, obj, fval, 1, vp, vp);
306 : }
307 :
308 22383 : if (attrs & JSPROP_GETTER)
309 0 : return js_ReportGetterOnlyAssignment(cx);
310 :
311 : /* See the comment in js::Shape::get as to why we check for With. */
312 22383 : if (obj->isWith())
313 0 : obj = &obj->asWith().object();
314 22383 : return js::CallJSPropertyOpSetter(cx, setterOp(), obj, getUserId(), strict, vp);
315 : }
316 :
317 : inline void
318 18289201 : Shape::setParent(js::Shape *p)
319 : {
320 40848475 : JS_ASSERT_IF(p && !p->hasMissingSlot() && !inDictionary(),
321 59137676 : p->maybeSlot() <= maybeSlot());
322 42527306 : JS_ASSERT_IF(p && !inDictionary(),
323 60816507 : hasSlot() == (p->maybeSlot() != maybeSlot()));
324 18289201 : parent = p;
325 18289201 : }
326 :
327 : inline void
328 368161 : Shape::removeFromDictionary(JSObject *obj)
329 : {
330 368161 : JS_ASSERT(inDictionary());
331 368161 : JS_ASSERT(obj->inDictionaryMode());
332 368161 : JS_ASSERT(listp);
333 :
334 368161 : JS_ASSERT(obj->shape_->inDictionary());
335 368161 : JS_ASSERT(obj->shape_->listp == &obj->shape_);
336 :
337 368161 : if (parent)
338 355015 : parent->listp = listp;
339 368161 : *listp = parent;
340 368161 : listp = NULL;
341 368161 : }
342 :
343 : inline void
344 4789759 : Shape::insertIntoDictionary(HeapPtrShape *dictp)
345 : {
346 : /*
347 : * Don't assert inDictionaryMode() here because we may be called from
348 : * JSObject::toDictionaryMode via JSObject::newDictionaryShape.
349 : */
350 4789759 : JS_ASSERT(inDictionary());
351 4789759 : JS_ASSERT(!listp);
352 :
353 4789759 : JS_ASSERT_IF(*dictp, (*dictp)->inDictionary());
354 4789759 : JS_ASSERT_IF(*dictp, (*dictp)->listp == dictp);
355 4789759 : JS_ASSERT_IF(*dictp, compartment() == (*dictp)->compartment());
356 :
357 4789759 : setParent(*dictp);
358 4789759 : if (parent)
359 2028980 : parent->listp = &parent;
360 4789759 : listp = (HeapPtrShape *) dictp;
361 4789759 : *dictp = this;
362 4789759 : }
363 :
364 : void
365 4789759 : Shape::initDictionaryShape(const StackShape &child, uint32_t nfixed, HeapPtrShape *dictp)
366 : {
367 4789759 : new (this) Shape(child, nfixed);
368 4789759 : this->flags |= IN_DICTIONARY;
369 :
370 4789759 : this->listp = NULL;
371 4789759 : insertIntoDictionary(dictp);
372 4789759 : }
373 :
374 : inline
375 1860050 : EmptyShape::EmptyShape(UnownedBaseShape *base, uint32_t nfixed)
376 1860050 : : js::Shape(base, nfixed)
377 : {
378 : /* Only empty shapes can be NON_NATIVE. */
379 1860050 : if (!getObjectClass()->isNative())
380 56262 : flags |= NON_NATIVE;
381 1860050 : }
382 :
383 : inline void
384 62018776 : Shape::writeBarrierPre(const js::Shape *shape)
385 : {
386 : #ifdef JSGC_INCREMENTAL
387 62018776 : if (!shape)
388 24217836 : return;
389 :
390 37800940 : JSCompartment *comp = shape->compartment();
391 37800940 : if (comp->needsBarrier()) {
392 4072 : Shape *tmp = const_cast<Shape *>(shape);
393 4072 : MarkShapeUnbarriered(comp->barrierTracer(), &tmp, "write barrier");
394 4072 : JS_ASSERT(tmp == shape);
395 : }
396 : #endif
397 : }
398 :
399 : inline void
400 88064518 : Shape::writeBarrierPost(const js::Shape *shape, void *addr)
401 : {
402 88064518 : }
403 :
404 : inline void
405 48939582 : Shape::readBarrier(const Shape *shape)
406 : {
407 : #ifdef JSGC_INCREMENTAL
408 48939582 : JSCompartment *comp = shape->compartment();
409 48939582 : if (comp->needsBarrier()) {
410 8878 : Shape *tmp = const_cast<Shape *>(shape);
411 8878 : MarkShapeUnbarriered(comp->barrierTracer(), &tmp, "read barrier");
412 8878 : JS_ASSERT(tmp == shape);
413 : }
414 : #endif
415 48939582 : }
416 :
417 : inline void
418 3670845 : Shape::markChildren(JSTracer *trc)
419 : {
420 3670845 : MarkBaseShape(trc, &base_, "base");
421 3670845 : gc::MarkId(trc, &propidRef(), "propid");
422 3670845 : if (parent)
423 3180089 : MarkShape(trc, &parent, "parent");
424 3670845 : }
425 :
426 : inline void
427 6263682 : BaseShape::writeBarrierPre(BaseShape *base)
428 : {
429 : #ifdef JSGC_INCREMENTAL
430 6263682 : if (!base)
431 127390 : return;
432 :
433 6136292 : JSCompartment *comp = base->compartment();
434 6136292 : if (comp->needsBarrier()) {
435 1011 : BaseShape *tmp = base;
436 1011 : MarkBaseShapeUnbarriered(comp->barrierTracer(), &tmp, "write barrier");
437 1011 : JS_ASSERT(tmp == base);
438 : }
439 : #endif
440 : }
441 :
442 : inline void
443 26906072 : BaseShape::writeBarrierPost(BaseShape *shape, void *addr)
444 : {
445 26906072 : }
446 :
447 : inline void
448 39697306 : BaseShape::readBarrier(BaseShape *base)
449 : {
450 : #ifdef JSGC_INCREMENTAL
451 39697306 : JSCompartment *comp = base->compartment();
452 39697306 : if (comp->needsBarrier()) {
453 1472 : BaseShape *tmp = base;
454 1472 : MarkBaseShapeUnbarriered(comp->barrierTracer(), &tmp, "read barrier");
455 1472 : JS_ASSERT(tmp == base);
456 : }
457 : #endif
458 39697306 : }
459 :
460 : inline void
461 1126427 : BaseShape::markChildren(JSTracer *trc)
462 : {
463 1126427 : if (hasGetterObject())
464 251584 : MarkObjectUnbarriered(trc, &getterObj, "getter");
465 :
466 1126427 : if (hasSetterObject())
467 62896 : MarkObjectUnbarriered(trc, &setterObj, "setter");
468 :
469 1126427 : if (isOwned())
470 34789 : MarkBaseShape(trc, &unowned_, "base");
471 :
472 1126427 : if (parent)
473 1079568 : MarkObject(trc, &parent, "parent");
474 1126427 : }
475 :
476 : } /* namespace js */
477 :
478 : #endif /* jsscopeinlines_h___ */
|