/[jscoverage]/trunk/js/jsscope.h
ViewVC logotype

Contents of /trunk/js/jsscope.h

Parent Directory Parent Directory | Revision Log Revision Log


Revision 507 - (show annotations)
Sun Jan 10 07:23:34 2010 UTC (9 years, 7 months ago) by siliconforks
File MIME type: text/plain
File size: 25725 byte(s)
Update SpiderMonkey from Firefox 3.6rc1.

1 /* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
2 * vim: set ts=8 sw=4 et tw=78:
3 *
4 * ***** 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 jsscope_h___
42 #define jsscope_h___
43 /*
44 * JS symbol tables.
45 */
46 #include "jstypes.h"
47 #include "jslock.h"
48 #include "jsobj.h"
49 #include "jsprvtd.h"
50 #include "jspubtd.h"
51
52 JS_BEGIN_EXTERN_C
53
54 /*
55 * Given P independent, non-unique properties each of size S words mapped by
56 * all scopes in a runtime, construct a property tree of N nodes each of size
57 * S+L words (L for tree linkage). A nominal L value is 2 for leftmost-child
58 * and right-sibling links. We hope that the N < P by enough that the space
59 * overhead of L, and the overhead of scope entries pointing at property tree
60 * nodes, is worth it.
61 *
62 * The tree construction goes as follows. If any empty scope in the runtime
63 * has a property X added to it, find or create a node under the tree root
64 * labeled X, and set scope->lastProp to point at that node. If any non-empty
65 * scope whose most recently added property is labeled Y has another property
66 * labeled Z added, find or create a node for Z under the node that was added
67 * for Y, and set scope->lastProp to point at that node.
68 *
69 * A property is labeled by its members' values: id, getter, setter, slot,
70 * attributes, tiny or short id, and a field telling for..in order. Note that
71 * labels are not unique in the tree, but they are unique among a node's kids
72 * (barring rare and benign multi-threaded race condition outcomes, see below)
73 * and along any ancestor line from the tree root to a given leaf node (except
74 * for the hard case of duplicate formal parameters to a function).
75 *
76 * Thus the root of the tree represents all empty scopes, and the first ply
77 * of the tree represents all scopes containing one property, etc. Each node
78 * in the tree can stand for any number of scopes having the same ordered set
79 * of properties, where that node was the last added to the scope. (We need
80 * not store the root of the tree as a node, and do not -- all we need are
81 * links to its kids.)
82 *
83 * Sidebar on for..in loop order: ECMA requires no particular order, but this
84 * implementation has promised and delivered property definition order, and
85 * compatibility is king. We could use an order number per property, which
86 * would require a sort in js_Enumerate, and an entry order generation number
87 * per scope. An order number beats a list, which should be doubly-linked for
88 * O(1) delete. An even better scheme is to use a parent link in the property
89 * tree, so that the ancestor line can be iterated from scope->lastProp when
90 * filling in a JSIdArray from back to front. This parent link also helps the
91 * GC to sweep properties iteratively.
92 *
93 * What if a property Y is deleted from a scope? If Y is the last property in
94 * the scope, we simply adjust the scope's lastProp member after we remove the
95 * scope's hash-table entry pointing at that property node. The parent link
96 * mentioned in the for..in sidebar above makes this adjustment O(1). But if
97 * Y comes between X and Z in the scope, then we might have to "fork" the tree
98 * at X, leaving X->Y->Z in case other scopes have those properties added in
99 * that order; and to finish the fork, we'd add a node labeled Z with the path
100 * X->Z, if it doesn't exist. This could lead to lots of extra nodes, and to
101 * O(n^2) growth when deleting lots of properties.
102 *
103 * Rather, for O(1) growth all around, we should share the path X->Y->Z among
104 * scopes having those three properties added in that order, and among scopes
105 * having only X->Z where Y was deleted. All such scopes have a lastProp that
106 * points to the Z child of Y. But a scope in which Y was deleted does not
107 * have a table entry for Y, and when iterating that scope by traversing the
108 * ancestor line from Z, we will have to test for a table entry for each node,
109 * skipping nodes that lack entries.
110 *
111 * What if we add Y again? X->Y->Z->Y is wrong and we'll enumerate Y twice.
112 * Therefore we must fork in such a case, if not earlier. Because delete is
113 * "bursty", we should not fork eagerly. Delaying a fork till we are at risk
114 * of adding Y after it was deleted already requires a flag in the JSScope, to
115 * wit, SCOPE_MIDDLE_DELETE.
116 *
117 * What about thread safety? If the property tree operations done by requests
118 * are find-node and insert-node, then the only hazard is duplicate insertion.
119 * This is harmless except for minor bloat. When all requests have ended or
120 * been suspended, the GC is free to sweep the tree after marking all nodes
121 * reachable from scopes, performing remove-node operations as needed.
122 *
123 * Is the property tree worth it compared to property storage in each table's
124 * entries? To decide, we must find the relation <> between the words used
125 * with a property tree and the words required without a tree.
126 *
127 * Model all scopes as one super-scope of capacity T entries (T a power of 2).
128 * Let alpha be the load factor of this double hash-table. With the property
129 * tree, each entry in the table is a word-sized pointer to a node that can be
130 * shared by many scopes. But all such pointers are overhead compared to the
131 * situation without the property tree, where the table stores property nodes
132 * directly, as entries each of size S words. With the property tree, we need
133 * L=2 extra words per node for siblings and kids pointers. Without the tree,
134 * (1-alpha)*S*T words are wasted on free or removed sentinel-entries required
135 * by double hashing.
136 *
137 * Therefore,
138 *
139 * (property tree) <> (no property tree)
140 * N*(S+L) + T <> S*T
141 * N*(S+L) + T <> P*S + (1-alpha)*S*T
142 * N*(S+L) + alpha*T + (1-alpha)*T <> P*S + (1-alpha)*S*T
143 *
144 * Note that P is alpha*T by definition, so
145 *
146 * N*(S+L) + P + (1-alpha)*T <> P*S + (1-alpha)*S*T
147 * N*(S+L) <> P*S - P + (1-alpha)*S*T - (1-alpha)*T
148 * N*(S+L) <> (P + (1-alpha)*T) * (S-1)
149 * N*(S+L) <> (P + (1-alpha)*P/alpha) * (S-1)
150 * N*(S+L) <> P * (1/alpha) * (S-1)
151 *
152 * Let N = P*beta for a compression ratio beta, beta <= 1:
153 *
154 * P*beta*(S+L) <> P * (1/alpha) * (S-1)
155 * beta*(S+L) <> (S-1)/alpha
156 * beta <> (S-1)/((S+L)*alpha)
157 *
158 * For S = 6 (32-bit architectures) and L = 2, the property tree wins iff
159 *
160 * beta < 5/(8*alpha)
161 *
162 * We ensure that alpha <= .75, so the property tree wins if beta < .83_. An
163 * average beta from recent Mozilla browser startups was around .6.
164 *
165 * Can we reduce L? Observe that the property tree degenerates into a list of
166 * lists if at most one property Y follows X in all scopes. In or near such a
167 * case, we waste a word on the right-sibling link outside of the root ply of
168 * the tree. Note also that the root ply tends to be large, so O(n^2) growth
169 * searching it is likely, indicating the need for hashing (but with increased
170 * thread safety costs).
171 *
172 * If only K out of N nodes in the property tree have more than one child, we
173 * could eliminate the sibling link and overlay a children list or hash-table
174 * pointer on the leftmost-child link (which would then be either null or an
175 * only-child link; the overlay could be tagged in the low bit of the pointer,
176 * or flagged elsewhere in the property tree node, although such a flag must
177 * not be considered when comparing node labels during tree search).
178 *
179 * For such a system, L = 1 + (K * averageChildrenTableSize) / N instead of 2.
180 * If K << N, L approaches 1 and the property tree wins if beta < .95.
181 *
182 * We observe that fan-out below the root ply of the property tree appears to
183 * have extremely low degree (see the MeterPropertyTree code that histograms
184 * child-counts in jsscope.c), so instead of a hash-table we use a linked list
185 * of child node pointer arrays ("kid chunks"). The details are isolated in
186 * jsscope.c; others must treat JSScopeProperty.kids as opaque. We leave it
187 * strongly typed for debug-ability of the common (null or one-kid) cases.
188 *
189 * One final twist (can you stand it?): the mean number of entries per scope
190 * in Mozilla is < 5, with a large standard deviation (~8). Instead of always
191 * allocating scope->table, we leave it null while initializing all the other
192 * scope members as if it were non-null and minimal-length. Until a property
193 * is added that crosses the threshold of 6 or more entries for hashing, or
194 * until a "middle delete" occurs, we use linear search from scope->lastProp
195 * to find a given id, and save on the space overhead of a hash table.
196 */
197
198 struct JSEmptyScope;
199
200 struct JSScope : public JSObjectMap
201 {
202 #ifdef JS_THREADSAFE
203 JSTitle title; /* lock state */
204 #endif
205 JSObject *object; /* object that owns this scope */
206 jsrefcount nrefs; /* count of all referencing objects */
207 uint32 freeslot; /* index of next free slot in object */
208 JSEmptyScope *emptyScope; /* cache for getEmptyScope below */
209 uint8 flags; /* flags, see below */
210 int8 hashShift; /* multiplicative hash shift */
211
212 uint16 spare; /* reserved */
213 uint32 entryCount; /* number of entries in table */
214 uint32 removedCount; /* removed entry sentinels in table */
215 JSScopeProperty **table; /* table of ptrs to shared tree nodes */
216 JSScopeProperty *lastProp; /* pointer to last property added */
217
218 private:
219 void initMinimal(JSContext *cx, uint32 newShape);
220 bool createTable(JSContext *cx, bool report);
221 bool changeTable(JSContext *cx, int change);
222 void reportReadOnlyScope(JSContext *cx);
223 void generateOwnShape(JSContext *cx);
224 JSScopeProperty **searchTable(jsid id, bool adding);
225 inline JSScopeProperty **search(jsid id, bool adding);
226 JSEmptyScope *createEmptyScope(JSContext *cx, JSClass *clasp);
227
228 public:
229 explicit JSScope(const JSObjectOps *ops, JSObject *obj = NULL)
230 : JSObjectMap(ops, 0), object(obj) {}
231
232 /* Create a mutable, owned, empty scope. */
233 static JSScope *create(JSContext *cx, const JSObjectOps *ops, JSClass *clasp,
234 JSObject *obj, uint32 shape);
235
236 static void destroy(JSContext *cx, JSScope *scope);
237
238 inline void hold();
239 inline bool drop(JSContext *cx, JSObject *obj);
240
241 /*
242 * Return an immutable, shareable, empty scope with the same ops as this
243 * and the same freeslot as this had when empty.
244 *
245 * If |this| is the scope of an object |proto|, the resulting scope can be
246 * used as the scope of a new object whose prototype is |proto|.
247 */
248 inline JSEmptyScope *getEmptyScope(JSContext *cx, JSClass *clasp);
249
250 inline bool canProvideEmptyScope(JSObjectOps *ops, JSClass *clasp);
251
252 JSScopeProperty *lookup(jsid id);
253 bool has(JSScopeProperty *sprop);
254
255 JSScopeProperty *add(JSContext *cx, jsid id,
256 JSPropertyOp getter, JSPropertyOp setter,
257 uint32 slot, uintN attrs,
258 uintN flags, intN shortid);
259
260 JSScopeProperty *change(JSContext *cx, JSScopeProperty *sprop,
261 uintN attrs, uintN mask,
262 JSPropertyOp getter, JSPropertyOp setter);
263
264 bool remove(JSContext *cx, jsid id);
265 void clear(JSContext *cx);
266
267 void extend(JSContext *cx, JSScopeProperty *sprop);
268
269 void trace(JSTracer *trc);
270
271 void brandingShapeChange(JSContext *cx, uint32 slot, jsval v);
272 void deletingShapeChange(JSContext *cx, JSScopeProperty *sprop);
273 void methodShapeChange(JSContext *cx, uint32 slot, jsval toval);
274 void protoShapeChange(JSContext *cx);
275 void replacingShapeChange(JSContext *cx,
276 JSScopeProperty *sprop,
277 JSScopeProperty *newsprop);
278 void sealingShapeChange(JSContext *cx);
279 void shadowingShapeChange(JSContext *cx, JSScopeProperty *sprop);
280
281 /* By definition, hashShift = JS_DHASH_BITS - log2(capacity). */
282 #define SCOPE_CAPACITY(scope) JS_BIT(JS_DHASH_BITS-(scope)->hashShift)
283
284 enum {
285 MIDDLE_DELETE = 0x0001,
286 SEALED = 0x0002,
287 BRANDED = 0x0004,
288 INDEXED_PROPERTIES = 0x0008,
289 OWN_SHAPE = 0x0010,
290
291 /*
292 * This flag toggles with each shape-regenerating GC cycle.
293 * See JSRuntime::gcRegenShapesScopeFlag.
294 */
295 SHAPE_REGEN = 0x0020
296 };
297
298 bool hadMiddleDelete() { return flags & MIDDLE_DELETE; }
299 void setMiddleDelete() { flags |= MIDDLE_DELETE; }
300 void clearMiddleDelete() { flags &= ~MIDDLE_DELETE; }
301
302 /*
303 * Don't define clearSealed, as it can't be done safely because JS_LOCK_OBJ
304 * will avoid taking the lock if the object owns its scope and the scope is
305 * sealed.
306 */
307 bool sealed() { return flags & SEALED; }
308 void setSealed() { flags |= SEALED; }
309
310 /*
311 * A branded scope's object contains plain old methods (function-valued
312 * properties without magic getters and setters), and its scope->shape
313 * evolves whenever a function value changes.
314 */
315 bool branded() { return flags & BRANDED; }
316 void setBranded() { flags |= BRANDED; }
317
318 bool hadIndexedProperties() { return flags & INDEXED_PROPERTIES; }
319 void setIndexedProperties() { flags |= INDEXED_PROPERTIES; }
320
321 bool hasOwnShape() { return flags & OWN_SHAPE; }
322 void setOwnShape() { flags |= OWN_SHAPE; }
323
324 bool hasRegenFlag(uint8 regenFlag) { return (flags & SHAPE_REGEN) == regenFlag; }
325
326 bool owned() { return object != NULL; }
327 };
328
329 struct JSEmptyScope : public JSScope
330 {
331 JSClass * const clasp;
332
333 explicit JSEmptyScope(const JSObjectOps *ops, JSClass *clasp)
334 : JSScope(ops), clasp(clasp) {}
335 };
336
337 inline bool
338 JS_IS_SCOPE_LOCKED(JSContext *cx, JSScope *scope)
339 {
340 return JS_IS_TITLE_LOCKED(cx, &scope->title);
341 }
342
343 inline JSScope *
344 OBJ_SCOPE(JSObject *obj)
345 {
346 JS_ASSERT(OBJ_IS_NATIVE(obj));
347 return (JSScope *) obj->map;
348 }
349
350 inline uint32
351 OBJ_SHAPE(JSObject *obj)
352 {
353 JS_ASSERT(obj->map->shape != JSObjectMap::SHAPELESS);
354 return obj->map->shape;
355 }
356
357 /*
358 * A little information hiding for scope->lastProp, in case it ever becomes
359 * a tagged pointer again.
360 */
361 #define SCOPE_LAST_PROP(scope) ((scope)->lastProp)
362 #define SCOPE_REMOVE_LAST_PROP(scope) ((scope)->lastProp = \
363 (scope)->lastProp->parent)
364 /*
365 * Helpers for reinterpreting JSPropertyOp as JSObject* for scripted getters
366 * and setters.
367 */
368 inline JSObject *
369 js_CastAsObject(JSPropertyOp op)
370 {
371 return JS_FUNC_TO_DATA_PTR(JSObject *, op);
372 }
373
374 inline jsval
375 js_CastAsObjectJSVal(JSPropertyOp op)
376 {
377 return OBJECT_TO_JSVAL(JS_FUNC_TO_DATA_PTR(JSObject *, op));
378 }
379
380 inline JSPropertyOp
381 js_CastAsPropertyOp(JSObject *object)
382 {
383 return JS_DATA_TO_FUNC_PTR(JSPropertyOp, object);
384 }
385
386 struct JSScopeProperty {
387 jsid id; /* int-tagged jsval/untagged JSAtom* */
388 JSPropertyOp getter; /* getter and setter hooks or objects */
389 JSPropertyOp setter;
390 uint32 slot; /* abstract index in object slots */
391 uint8 attrs; /* attributes, see jsapi.h JSPROP_* */
392 uint8 flags; /* flags, see below for defines */
393 int16 shortid; /* tinyid, or local arg/var index */
394 JSScopeProperty *parent; /* parent node, reverse for..in order */
395 JSScopeProperty *kids; /* null, single child, or a tagged ptr
396 to many-kids data structure */
397 uint32 shape; /* property cache shape identifier */
398
399 void trace(JSTracer *trc);
400 };
401
402 /* JSScopeProperty pointer tag bit indicating a collision. */
403 #define SPROP_COLLISION ((jsuword)1)
404 #define SPROP_REMOVED ((JSScopeProperty *) SPROP_COLLISION)
405
406 /* Macros to get and set sprop pointer values and collision flags. */
407 #define SPROP_IS_FREE(sprop) ((sprop) == NULL)
408 #define SPROP_IS_REMOVED(sprop) ((sprop) == SPROP_REMOVED)
409 #define SPROP_IS_LIVE(sprop) ((sprop) > SPROP_REMOVED)
410 #define SPROP_FLAG_COLLISION(spp,sprop) (*(spp) = (JSScopeProperty *) \
411 ((jsuword)(sprop) | SPROP_COLLISION))
412 #define SPROP_HAD_COLLISION(sprop) ((jsuword)(sprop) & SPROP_COLLISION)
413 #define SPROP_FETCH(spp) SPROP_CLEAR_COLLISION(*(spp))
414
415 #define SPROP_CLEAR_COLLISION(sprop) \
416 ((JSScopeProperty *) ((jsuword)(sprop) & ~SPROP_COLLISION))
417
418 #define SPROP_STORE_PRESERVING_COLLISION(spp, sprop) \
419 (*(spp) = (JSScopeProperty *) ((jsuword)(sprop) \
420 | SPROP_HAD_COLLISION(*(spp))))
421
422 JS_ALWAYS_INLINE JSScopeProperty *
423 JSScope::lookup(jsid id)
424 {
425 return SPROP_FETCH(search(id, false));
426 }
427
428 JS_ALWAYS_INLINE bool
429 JSScope::has(JSScopeProperty *sprop)
430 {
431 return lookup(sprop->id) == sprop;
432 }
433
434 /* Bits stored in sprop->flags. */
435 #define SPROP_MARK 0x01
436 #define SPROP_IS_ALIAS 0x02
437 #define SPROP_HAS_SHORTID 0x04
438 #define SPROP_FLAG_SHAPE_REGEN 0x08
439
440 /*
441 * If SPROP_HAS_SHORTID is set in sprop->flags, we use sprop->shortid rather
442 * than id when calling sprop's getter or setter.
443 */
444 #define SPROP_USERID(sprop) \
445 (((sprop)->flags & SPROP_HAS_SHORTID) ? INT_TO_JSVAL((sprop)->shortid) \
446 : ID_TO_VALUE((sprop)->id))
447
448 #define SPROP_INVALID_SLOT 0xffffffff
449
450 #define SLOT_IN_SCOPE(slot,scope) ((slot) < (scope)->freeslot)
451 #define SPROP_HAS_VALID_SLOT(sprop,scope) SLOT_IN_SCOPE((sprop)->slot, scope)
452
453 #define SPROP_HAS_STUB_GETTER(sprop) (!(sprop)->getter)
454 #define SPROP_HAS_STUB_SETTER(sprop) (!(sprop)->setter)
455
456 #ifndef JS_THREADSAFE
457 # define js_GenerateShape(cx, gcLocked) js_GenerateShape (cx)
458 #endif
459
460 extern uint32
461 js_GenerateShape(JSContext *cx, bool gcLocked);
462
463 #ifdef JS_DUMP_PROPTREE_STATS
464 # define METER(x) JS_ATOMIC_INCREMENT(&js_scope_stats.x)
465 #else
466 # define METER(x) /* nothing */
467 #endif
468
469 inline JSScopeProperty **
470 JSScope::search(jsid id, bool adding)
471 {
472 JSScopeProperty *sprop, **spp;
473
474 METER(searches);
475 if (!table) {
476 /* Not enough properties to justify hashing: search from lastProp. */
477 JS_ASSERT(!hadMiddleDelete());
478 for (spp = &lastProp; (sprop = *spp); spp = &sprop->parent) {
479 if (sprop->id == id) {
480 METER(hits);
481 return spp;
482 }
483 }
484 METER(misses);
485 return spp;
486 }
487 return searchTable(id, adding);
488 }
489
490 #undef METER
491
492 inline bool
493 JSScope::canProvideEmptyScope(JSObjectOps *ops, JSClass *clasp)
494 {
495 return this->ops == ops && (!emptyScope || emptyScope->clasp == clasp);
496 }
497
498 inline JSEmptyScope *
499 JSScope::getEmptyScope(JSContext *cx, JSClass *clasp)
500 {
501 if (emptyScope) {
502 JS_ASSERT(clasp == emptyScope->clasp);
503 emptyScope->hold();
504 return emptyScope;
505 }
506 return createEmptyScope(cx, clasp);
507 }
508
509 inline void
510 JSScope::hold()
511 {
512 JS_ASSERT(nrefs >= 0);
513 JS_ATOMIC_INCREMENT(&nrefs);
514 }
515
516 inline bool
517 JSScope::drop(JSContext *cx, JSObject *obj)
518 {
519 #ifdef JS_THREADSAFE
520 /* We are called from only js_ShareWaitingTitles and js_FinalizeObject. */
521 JS_ASSERT(!obj || CX_THREAD_IS_RUNNING_GC(cx));
522 #endif
523 JS_ASSERT(nrefs > 0);
524 --nrefs;
525
526 if (nrefs == 0) {
527 destroy(cx, this);
528 return false;
529 }
530 if (object == obj)
531 object = NULL;
532 return true;
533 }
534
535 inline void
536 JSScope::extend(JSContext *cx, JSScopeProperty *sprop)
537 {
538 js_LeaveTraceIfGlobalObject(cx, object);
539 shape = (!lastProp || shape == lastProp->shape)
540 ? sprop->shape
541 : js_GenerateShape(cx, JS_FALSE);
542 ++entryCount;
543 lastProp = sprop;
544 }
545
546 inline void
547 JSScope::trace(JSTracer *trc)
548 {
549 JSContext *cx = trc->context;
550 JSScopeProperty *sprop = lastProp;
551 uint8 regenFlag = cx->runtime->gcRegenShapesScopeFlag;
552 if (IS_GC_MARKING_TRACER(trc) && cx->runtime->gcRegenShapes && !hasRegenFlag(regenFlag)) {
553 /*
554 * Either this scope has its own shape, which must be regenerated, or
555 * it must have the same shape as lastProp.
556 */
557 uint32 newShape;
558
559 if (sprop) {
560 if (!(sprop->flags & SPROP_FLAG_SHAPE_REGEN)) {
561 sprop->shape = js_RegenerateShapeForGC(cx);
562 sprop->flags |= SPROP_FLAG_SHAPE_REGEN;
563 }
564 newShape = sprop->shape;
565 }
566 if (!sprop || hasOwnShape()) {
567 newShape = js_RegenerateShapeForGC(cx);
568 JS_ASSERT_IF(sprop, newShape != sprop->shape);
569 }
570 shape = newShape;
571 flags ^= JSScope::SHAPE_REGEN;
572
573 /* Also regenerate the shapes of empty scopes, in case they are not shared. */
574 for (JSScope *empty = emptyScope;
575 empty && !empty->hasRegenFlag(regenFlag);
576 empty = empty->emptyScope) {
577 empty->shape = js_RegenerateShapeForGC(cx);
578 empty->flags ^= JSScope::SHAPE_REGEN;
579 }
580 }
581 if (sprop) {
582 JS_ASSERT(has(sprop));
583
584 /* Trace scope's property tree ancestor line. */
585 do {
586 if (hadMiddleDelete() && !has(sprop))
587 continue;
588 sprop->trace(trc);
589 } while ((sprop = sprop->parent) != NULL);
590 }
591 }
592
593
594 static JS_INLINE bool
595 js_GetSprop(JSContext* cx, JSScopeProperty* sprop, JSObject* obj, jsval* vp)
596 {
597 JS_ASSERT(!SPROP_HAS_STUB_GETTER(sprop));
598
599 if (sprop->attrs & JSPROP_GETTER) {
600 jsval fval = js_CastAsObjectJSVal(sprop->getter);
601 return js_InternalGetOrSet(cx, obj, sprop->id, fval, JSACC_READ,
602 0, 0, vp);
603 }
604
605 /*
606 * JSObjectOps is private, so we know there are only two implementations
607 * of the thisObject hook: with objects and XPConnect wrapped native
608 * objects. XPConnect objects don't expect the hook to be called here,
609 * but with objects do.
610 */
611 if (STOBJ_GET_CLASS(obj) == &js_WithClass)
612 obj = obj->map->ops->thisObject(cx, obj);
613 return sprop->getter(cx, obj, SPROP_USERID(sprop), vp);
614 }
615
616 static JS_INLINE bool
617 js_SetSprop(JSContext* cx, JSScopeProperty* sprop, JSObject* obj, jsval* vp)
618 {
619 JS_ASSERT(!(SPROP_HAS_STUB_SETTER(sprop) &&
620 !(sprop->attrs & JSPROP_GETTER)));
621
622 if (sprop->attrs & JSPROP_SETTER) {
623 jsval fval = js_CastAsObjectJSVal(sprop->setter);
624 return js_InternalGetOrSet(cx, obj, (sprop)->id, fval, JSACC_WRITE,
625 1, vp, vp);
626 }
627
628 if (sprop->attrs & JSPROP_GETTER) {
629 js_ReportGetterOnlyAssignment(cx);
630 return JS_FALSE;
631 }
632
633 /* See the comment in js_GetSprop as to why we can check for 'with'. */
634 if (STOBJ_GET_CLASS(obj) == &js_WithClass)
635 obj = obj->map->ops->thisObject(cx, obj);
636 return sprop->setter(cx, obj, SPROP_USERID(sprop), vp);
637 }
638
639 /* Macro for common expression to test for shared permanent attributes. */
640 #define SPROP_IS_SHARED_PERMANENT(sprop) \
641 ((~(sprop)->attrs & (JSPROP_SHARED | JSPROP_PERMANENT)) == 0)
642
643 extern JSScope *
644 js_GetMutableScope(JSContext *cx, JSObject *obj);
645
646 extern void
647 js_TraceId(JSTracer *trc, jsid id);
648
649 extern void
650 js_SweepScopeProperties(JSContext *cx);
651
652 extern bool
653 js_InitPropertyTree(JSRuntime *rt);
654
655 extern void
656 js_FinishPropertyTree(JSRuntime *rt);
657
658 JS_END_EXTERN_C
659
660 #endif /* jsscope_h___ */

  ViewVC Help
Powered by ViewVC 1.1.24