Imported Upstream version 1.0.0
[platform/upstream/js.git] / js / src / jsscopeinlines.h
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 #include "jsbool.h"
45 #include "jscntxt.h"
46 #include "jsdbgapi.h"
47 #include "jsfun.h"
48 #include "jsobj.h"
49 #include "jsscope.h"
50
51 #include "jscntxtinlines.h"
52
53 inline void
54 js::Shape::freeTable(JSContext *cx)
55 {
56     if (hasTable()) {
57         cx->destroy(getTable());
58         setTable(NULL);
59     }
60 }
61
62 inline js::EmptyShape *
63 JSObject::getEmptyShape(JSContext *cx, js::Class *aclasp,
64                         /* gc::FinalizeKind */ unsigned kind)
65 {
66     JS_ASSERT(kind >= js::gc::FINALIZE_OBJECT0 && kind <= js::gc::FINALIZE_OBJECT_LAST);
67     int i = kind - js::gc::FINALIZE_OBJECT0;
68
69     if (!emptyShapes) {
70         emptyShapes = (js::EmptyShape**)
71             cx->calloc(sizeof(js::EmptyShape*) * js::gc::JS_FINALIZE_OBJECT_LIMIT);
72         if (!emptyShapes)
73             return NULL;
74
75         /*
76          * Always fill in emptyShapes[0], so canProvideEmptyShape works.
77          * Other empty shapes are filled in lazily.
78          */
79         emptyShapes[0] = js::EmptyShape::create(cx, aclasp);
80         if (!emptyShapes[0]) {
81             cx->free(emptyShapes);
82             emptyShapes = NULL;
83             return NULL;
84         }
85     }
86
87     JS_ASSERT(aclasp == emptyShapes[0]->getClass());
88
89     if (!emptyShapes[i]) {
90         emptyShapes[i] = js::EmptyShape::create(cx, aclasp);
91         if (!emptyShapes[i])
92             return NULL;
93     }
94
95     return emptyShapes[i];
96 }
97
98 inline bool
99 JSObject::canProvideEmptyShape(js::Class *aclasp)
100 {
101     return !emptyShapes || emptyShapes[0]->getClass() == aclasp;
102 }
103
104 inline void
105 JSObject::updateShape(JSContext *cx)
106 {
107     JS_ASSERT(isNative());
108     js::LeaveTraceIfGlobalObject(cx, this);
109     if (hasOwnShape())
110         setOwnShape(js_GenerateShape(cx));
111     else
112         objShape = lastProp->shape;
113 }
114
115 inline void
116 JSObject::updateFlags(const js::Shape *shape, bool isDefinitelyAtom)
117 {
118     jsuint index;
119     if (!isDefinitelyAtom && js_IdIsIndex(shape->id, &index))
120         setIndexed();
121
122     if (shape->isMethod())
123         setMethodBarrier();
124 }
125
126 inline void
127 JSObject::extend(JSContext *cx, const js::Shape *shape, bool isDefinitelyAtom)
128 {
129     setLastProperty(shape);
130     updateFlags(shape, isDefinitelyAtom);
131     updateShape(cx);
132 }
133
134 inline void
135 JSObject::trace(JSTracer *trc)
136 {
137     if (!isNative())
138         return;
139
140     JSContext *cx = trc->context;
141     js::Shape *shape = lastProp;
142
143     if (IS_GC_MARKING_TRACER(trc) && cx->runtime->gcRegenShapes) {
144         /*
145          * Either this object has its own shape, which must be regenerated, or
146          * it must have the same shape as lastProp.
147          */
148         if (!shape->hasRegenFlag()) {
149             shape->shape = js_RegenerateShapeForGC(cx->runtime);
150             shape->setRegenFlag();
151         }
152
153         uint32 newShape = shape->shape;
154         if (hasOwnShape()) {
155             newShape = js_RegenerateShapeForGC(cx->runtime);
156             JS_ASSERT(newShape != shape->shape);
157         }
158         objShape = newShape;
159     }
160
161     /* Trace our property tree or dictionary ancestor line. */
162     do {
163         shape->trace(trc);
164     } while ((shape = shape->parent) != NULL);
165 }
166
167 namespace js {
168
169 inline
170 Shape::Shape(jsid id, js::PropertyOp getter, js::StrictPropertyOp setter, uint32 slot, uintN attrs,
171              uintN flags, intN shortid, uint32 shape, uint32 slotSpan)
172   : JSObjectMap(shape, slotSpan),
173     numLinearSearches(0), id(id), rawGetter(getter), rawSetter(setter), slot(slot),
174     attrs(uint8(attrs)), flags(uint8(flags)), shortid(int16(shortid)), parent(NULL)
175 {
176     JS_ASSERT_IF(slotSpan != SHAPE_INVALID_SLOT, slotSpan < JSObject::NSLOTS_LIMIT);
177     JS_ASSERT_IF(getter && (attrs & JSPROP_GETTER), getterObj->isCallable());
178     JS_ASSERT_IF(setter && (attrs & JSPROP_SETTER), setterObj->isCallable());
179     kids.setNull();
180 }
181
182 inline
183 Shape::Shape(JSCompartment *comp, Class *aclasp)
184   : JSObjectMap(js_GenerateShape(comp->rt), JSSLOT_FREE(aclasp)),
185     numLinearSearches(0),
186     id(JSID_EMPTY),
187     clasp(aclasp),
188     rawSetter(NULL),
189     slot(SHAPE_INVALID_SLOT),
190     attrs(0),
191     flags(SHARED_EMPTY),
192     shortid(0),
193     parent(NULL)
194 {
195     kids.setNull();
196 }
197
198 inline JSDHashNumber
199 Shape::hash() const
200 {
201     JSDHashNumber hash = 0;
202
203     /* Accumulate from least to most random so the low bits are most random. */
204     JS_ASSERT_IF(isMethod(), !rawSetter || rawSetter == js_watch_set);
205     if (rawGetter)
206         hash = JS_ROTATE_LEFT32(hash, 4) ^ jsuword(rawGetter);
207     if (rawSetter)
208         hash = JS_ROTATE_LEFT32(hash, 4) ^ jsuword(rawSetter);
209     hash = JS_ROTATE_LEFT32(hash, 4) ^ (flags & PUBLIC_FLAGS);
210     hash = JS_ROTATE_LEFT32(hash, 4) ^ attrs;
211     hash = JS_ROTATE_LEFT32(hash, 4) ^ shortid;
212     hash = JS_ROTATE_LEFT32(hash, 4) ^ slot;
213     hash = JS_ROTATE_LEFT32(hash, 4) ^ JSID_BITS(id);
214     return hash;
215 }
216
217 inline bool
218 Shape::matches(const js::Shape *other) const
219 {
220     JS_ASSERT(!JSID_IS_VOID(id));
221     JS_ASSERT(!JSID_IS_VOID(other->id));
222     return id == other->id &&
223            matchesParamsAfterId(other->rawGetter, other->rawSetter, other->slot, other->attrs,
224                                 other->flags, other->shortid);
225 }
226
227 inline bool
228 Shape::matchesParamsAfterId(js::PropertyOp agetter, js::StrictPropertyOp asetter, uint32 aslot,
229                             uintN aattrs, uintN aflags, intN ashortid) const
230 {
231     JS_ASSERT(!JSID_IS_VOID(id));
232     return rawGetter == agetter &&
233            rawSetter == asetter &&
234            slot == aslot &&
235            attrs == aattrs &&
236            ((flags ^ aflags) & PUBLIC_FLAGS) == 0 &&
237            shortid == ashortid;
238 }
239
240 inline bool
241 Shape::get(JSContext* cx, JSObject *receiver, JSObject* obj, JSObject *pobj, js::Value* vp) const
242 {
243     JS_ASSERT(!JSID_IS_VOID(this->id));
244     JS_ASSERT(!hasDefaultGetter());
245
246     if (hasGetterValue()) {
247         JS_ASSERT(!isMethod());
248         js::Value fval = getterValue();
249         return js::ExternalGetOrSet(cx, receiver, id, fval, JSACC_READ, 0, 0, vp);
250     }
251
252     if (isMethod()) {
253         vp->setObject(methodObject());
254         return pobj->methodReadBarrier(cx, *this, vp);
255     }
256
257     /*
258      * |with (it) color;| ends up here, as do XML filter-expressions.
259      * Avoid exposing the With object to native getters.
260      */
261     if (obj->getClass() == &js_WithClass)
262         obj = js_UnwrapWithObject(cx, obj);
263     return js::CallJSPropertyOp(cx, getterOp(), obj, SHAPE_USERID(this), vp);
264 }
265
266 inline bool
267 Shape::set(JSContext* cx, JSObject* obj, bool strict, js::Value* vp) const
268 {
269     JS_ASSERT_IF(hasDefaultSetter(), hasGetterValue());
270
271     if (attrs & JSPROP_SETTER) {
272         js::Value fval = setterValue();
273         return js::ExternalGetOrSet(cx, obj, id, fval, JSACC_WRITE, 1, vp, vp);
274     }
275
276     if (attrs & JSPROP_GETTER)
277         return js_ReportGetterOnlyAssignment(cx);
278
279     /* See the comment in js::Shape::get as to why we check for With. */
280     if (obj->getClass() == &js_WithClass)
281         obj = js_UnwrapWithObject(cx, obj);
282     return js::CallJSPropertyOpSetter(cx, setterOp(), obj, SHAPE_USERID(this), strict, vp);
283 }
284
285 inline
286 EmptyShape::EmptyShape(JSCompartment *comp, js::Class *aclasp)
287   : js::Shape(comp, aclasp)
288 {
289 #ifdef DEBUG
290     if (comp->rt->meterEmptyShapes())
291         comp->emptyShapes.put(this);
292 #endif
293 }
294
295 } /* namespace js */
296
297 #endif /* jsscopeinlines_h___ */