1 : /* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
2 : * vim: set ts=4 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 SpiderMonkey code.
18 : *
19 : * The Initial Developer of the Original Code is
20 : * Mozilla Corporation.
21 : * Portions created by the Initial Developer are Copyright (C) 2010
22 : * the Initial Developer. All Rights Reserved.
23 : *
24 : * Contributor(s):
25 : * Jeff Walden <jwalden+code@mit.edu> (original author)
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 jscntxtinlines_h___
42 : #define jscntxtinlines_h___
43 :
44 : #include "jscntxt.h"
45 : #include "jscompartment.h"
46 : #include "jsfriendapi.h"
47 : #include "jsinterp.h"
48 : #include "jsxml.h"
49 : #include "jsgc.h"
50 :
51 : #include "frontend/ParseMaps.h"
52 : #include "vm/RegExpObject.h"
53 :
54 : namespace js {
55 :
56 : struct PreserveRegsGuard
57 : {
58 13853110 : PreserveRegsGuard(JSContext *cx, FrameRegs ®s)
59 13853110 : : prevContextRegs(cx->maybeRegs()), cx(cx), regs_(regs) {
60 13853110 : cx->stack.repointRegs(®s_);
61 13853110 : }
62 13853110 : ~PreserveRegsGuard() {
63 13853110 : JS_ASSERT(cx->maybeRegs() == ®s_);
64 13853110 : *prevContextRegs = regs_;
65 13853110 : cx->stack.repointRegs(prevContextRegs);
66 13853110 : }
67 :
68 : FrameRegs *prevContextRegs;
69 :
70 : private:
71 : JSContext *cx;
72 : FrameRegs ®s_;
73 : };
74 :
75 : static inline GlobalObject *
76 912986923 : GetGlobalForScopeChain(JSContext *cx)
77 : {
78 912986923 : if (cx->hasfp())
79 912958782 : return &cx->fp()->scopeChain().global();
80 :
81 28141 : JSObject *scope = JS_ObjectToInnerObject(cx, cx->globalObject);
82 28141 : if (!scope)
83 0 : return NULL;
84 28141 : return &scope->asGlobal();
85 : }
86 :
87 : inline GSNCache *
88 35139329 : GetGSNCache(JSContext *cx)
89 : {
90 35139329 : return &cx->runtime->gsnCache;
91 : }
92 :
93 : class AutoNamespaceArray : protected AutoGCRooter {
94 : public:
95 1082 : AutoNamespaceArray(JSContext *cx)
96 1082 : : AutoGCRooter(cx, NAMESPACES), context(cx) {
97 1082 : array.init();
98 1082 : }
99 :
100 2164 : ~AutoNamespaceArray() {
101 1082 : array.finish(context);
102 1082 : }
103 :
104 234 : uint32_t length() const { return array.length; }
105 :
106 : private:
107 : JSContext *context;
108 : friend void AutoGCRooter::trace(JSTracer *trc);
109 :
110 : public:
111 : JSXMLArray<JSObject> array;
112 : };
113 :
114 : template <typename T>
115 : class AutoPtr
116 : {
117 : JSContext *cx;
118 : T *value;
119 :
120 : AutoPtr(const AutoPtr &other) MOZ_DELETE;
121 :
122 : public:
123 978344 : explicit AutoPtr(JSContext *cx) : cx(cx), value(NULL) {}
124 978344 : ~AutoPtr() {
125 978344 : cx->delete_<T>(value);
126 978344 : }
127 :
128 978344 : void operator=(T *ptr) { value = ptr; }
129 :
130 : typedef void ***** ConvertibleToBool;
131 978344 : operator ConvertibleToBool() const { return (ConvertibleToBool) value; }
132 :
133 : const T *operator->() const { return value; }
134 7826752 : T *operator->() { return value; }
135 :
136 978344 : T *get() { return value; }
137 : };
138 :
139 : #ifdef DEBUG
140 : class CompartmentChecker
141 : {
142 : JSContext *context;
143 : JSCompartment *compartment;
144 :
145 : public:
146 914082901 : explicit CompartmentChecker(JSContext *cx) : context(cx), compartment(cx->compartment) {
147 914082901 : check(cx->hasfp() ? JS_GetGlobalForScopeChain(cx) : cx->globalObject);
148 914082901 : }
149 :
150 : /*
151 : * Set a breakpoint here (break js::CompartmentChecker::fail) to debug
152 : * compartment mismatches.
153 : */
154 0 : static void fail(JSCompartment *c1, JSCompartment *c2) {
155 0 : printf("*** Compartment mismatch %p vs. %p\n", (void *) c1, (void *) c2);
156 0 : JS_NOT_REACHED("compartment mismatched");
157 : }
158 :
159 : /* Note: should only be used when neither c1 nor c2 may be the default compartment. */
160 : static void check(JSCompartment *c1, JSCompartment *c2) {
161 : JS_ASSERT(c1 != c1->rt->atomsCompartment);
162 : JS_ASSERT(c2 != c2->rt->atomsCompartment);
163 : if (c1 != c2)
164 : fail(c1, c2);
165 : }
166 :
167 1290192446 : void check(JSCompartment *c) {
168 1290192446 : if (c && c != context->runtime->atomsCompartment) {
169 1290192446 : if (!compartment)
170 0 : compartment = c;
171 1290192446 : else if (c != compartment)
172 0 : fail(compartment, c);
173 : }
174 1290192446 : }
175 :
176 53468 : void check(JSPrincipals *) { /* nothing for now */ }
177 :
178 1305787984 : void check(JSObject *obj) {
179 1305787984 : if (obj)
180 1268384670 : check(obj->compartment());
181 1305787984 : }
182 :
183 56616588 : void check(JSString *str) {
184 56616588 : if (!str->isAtom())
185 21751540 : check(str->compartment());
186 56616588 : }
187 :
188 941648262 : void check(const js::Value &v) {
189 941648262 : if (v.isObject())
190 277187169 : check(&v.toObject());
191 664461093 : else if (v.isString())
192 54195762 : check(v.toString());
193 941648262 : }
194 :
195 : void check(const ValueArray &arr) {
196 : for (size_t i = 0; i < arr.length; i++)
197 : check(arr.array[i]);
198 : }
199 :
200 741146 : void check(const JSValueArray &arr) {
201 1683383 : for (size_t i = 0; i < arr.length; i++)
202 942237 : check(arr.array[i]);
203 741146 : }
204 :
205 24342607 : void check(const CallArgs &args) {
206 107931812 : for (Value *p = args.base(); p != args.end(); ++p)
207 83589205 : check(*p);
208 24342607 : }
209 :
210 32030143 : void check(jsid id) {
211 32030143 : if (JSID_IS_OBJECT(id))
212 27 : check(JSID_TO_OBJECT(id));
213 32030143 : }
214 :
215 0 : void check(JSIdArray *ida) {
216 0 : if (ida) {
217 0 : for (int i = 0; i < ida->length; i++) {
218 0 : if (JSID_IS_OBJECT(ida->vector[i]))
219 0 : check(ida->vector[i]);
220 : }
221 : }
222 0 : }
223 :
224 56236 : void check(JSScript *script) {
225 56236 : if (script) {
226 56236 : check(script->compartment());
227 56236 : if (!script->isCachedEval && script->globalObject)
228 55584 : check(script->globalObject);
229 : }
230 56236 : }
231 :
232 4702 : void check(StackFrame *fp) {
233 4702 : if (fp)
234 4702 : check(&fp->scopeChain());
235 4702 : }
236 : };
237 :
238 : #endif
239 :
240 : /*
241 : * Don't perform these checks when called from a finalizer. The checking
242 : * depends on other objects not having been swept yet.
243 : */
244 : #define START_ASSERT_SAME_COMPARTMENT() \
245 : if (cx->runtime->gcRunning) \
246 : return; \
247 : CompartmentChecker c(cx)
248 :
249 : template <class T1> inline void
250 865149181 : assertSameCompartment(JSContext *cx, T1 t1)
251 : {
252 : #ifdef DEBUG
253 865149181 : START_ASSERT_SAME_COMPARTMENT();
254 865149181 : c.check(t1);
255 : #endif
256 : }
257 :
258 : template <class T1, class T2> inline void
259 19934680 : assertSameCompartment(JSContext *cx, T1 t1, T2 t2)
260 : {
261 : #ifdef DEBUG
262 19934680 : START_ASSERT_SAME_COMPARTMENT();
263 19934680 : c.check(t1);
264 19934680 : c.check(t2);
265 : #endif
266 : }
267 :
268 : template <class T1, class T2, class T3> inline void
269 9395096 : assertSameCompartment(JSContext *cx, T1 t1, T2 t2, T3 t3)
270 : {
271 : #ifdef DEBUG
272 9395096 : START_ASSERT_SAME_COMPARTMENT();
273 9395096 : c.check(t1);
274 9395096 : c.check(t2);
275 9395096 : c.check(t3);
276 : #endif
277 : }
278 :
279 : template <class T1, class T2, class T3, class T4> inline void
280 : assertSameCompartment(JSContext *cx, T1 t1, T2 t2, T3 t3, T4 t4)
281 : {
282 : #ifdef DEBUG
283 : START_ASSERT_SAME_COMPARTMENT();
284 : c.check(t1);
285 : c.check(t2);
286 : c.check(t3);
287 : c.check(t4);
288 : #endif
289 : }
290 :
291 : template <class T1, class T2, class T3, class T4, class T5> inline void
292 19603944 : assertSameCompartment(JSContext *cx, T1 t1, T2 t2, T3 t3, T4 t4, T5 t5)
293 : {
294 : #ifdef DEBUG
295 19603944 : START_ASSERT_SAME_COMPARTMENT();
296 19603944 : c.check(t1);
297 19603944 : c.check(t2);
298 19603944 : c.check(t3);
299 19603944 : c.check(t4);
300 19603944 : c.check(t5);
301 : #endif
302 : }
303 :
304 : #undef START_ASSERT_SAME_COMPARTMENT
305 :
306 : STATIC_PRECONDITION_ASSUME(ubound(args.argv_) >= argc)
307 : JS_ALWAYS_INLINE bool
308 24342607 : CallJSNative(JSContext *cx, Native native, const CallArgs &args)
309 : {
310 : #ifdef DEBUG
311 24342607 : JSBool alreadyThrowing = cx->isExceptionPending();
312 : #endif
313 24342607 : assertSameCompartment(cx, args);
314 24342607 : bool ok = native(cx, args.length(), args.base());
315 24342607 : if (ok) {
316 24259609 : assertSameCompartment(cx, args.rval());
317 24259609 : JS_ASSERT_IF(!alreadyThrowing, !cx->isExceptionPending());
318 : }
319 24342607 : return ok;
320 : }
321 :
322 : extern JSBool CallOrConstructBoundFunction(JSContext *, unsigned, js::Value *);
323 :
324 : STATIC_PRECONDITION(ubound(args.argv_) >= argc)
325 : JS_ALWAYS_INLINE bool
326 265922 : CallJSNativeConstructor(JSContext *cx, Native native, const CallArgs &args)
327 : {
328 : #ifdef DEBUG
329 265922 : JSObject &callee = args.callee();
330 : #endif
331 :
332 265922 : JS_ASSERT(args.thisv().isMagic());
333 265922 : if (!CallJSNative(cx, native, args))
334 443 : return false;
335 :
336 : /*
337 : * Native constructors must return non-primitive values on success.
338 : * Although it is legal, if a constructor returns the callee, there is a
339 : * 99.9999% chance it is a bug. If any valid code actually wants the
340 : * constructor to return the callee, the assertion can be removed or
341 : * (another) conjunct can be added to the antecedent.
342 : *
343 : * Proxies are exceptions to both rules: they can return primitives and
344 : * they allow content to return the callee.
345 : *
346 : * CallOrConstructBoundFunction is an exception as well because we
347 : * might have used bind on a proxy function.
348 : *
349 : * (new Object(Object)) returns the callee.
350 : */
351 1006907 : JS_ASSERT_IF(native != FunctionProxyClass.construct &&
352 : native != CallableObjectClass.construct &&
353 : native != js::CallOrConstructBoundFunction &&
354 : (!callee.isFunction() || callee.toFunction()->u.n.clasp != &ObjectClass),
355 1272386 : !args.rval().isPrimitive() && callee != args.rval().toObject());
356 :
357 265479 : return true;
358 : }
359 :
360 : JS_ALWAYS_INLINE bool
361 8584431 : CallJSPropertyOp(JSContext *cx, PropertyOp op, JSObject *receiver, jsid id, Value *vp)
362 : {
363 8584431 : assertSameCompartment(cx, receiver, id, *vp);
364 8584431 : JSBool ok = op(cx, receiver, id, vp);
365 8584431 : if (ok)
366 8584381 : assertSameCompartment(cx, receiver, *vp);
367 8584431 : return ok;
368 : }
369 :
370 : JS_ALWAYS_INLINE bool
371 202824 : CallJSPropertyOpSetter(JSContext *cx, StrictPropertyOp op, JSObject *obj, jsid id,
372 : JSBool strict, Value *vp)
373 : {
374 202824 : assertSameCompartment(cx, obj, id, *vp);
375 202824 : return op(cx, obj, id, strict, vp);
376 : }
377 :
378 : inline bool
379 0 : CallSetter(JSContext *cx, JSObject *obj, jsid id, StrictPropertyOp op, unsigned attrs,
380 : unsigned shortid, JSBool strict, Value *vp)
381 : {
382 0 : if (attrs & JSPROP_SETTER)
383 0 : return InvokeGetterOrSetter(cx, obj, CastAsObjectJsval(op), 1, vp, vp);
384 :
385 0 : if (attrs & JSPROP_GETTER)
386 0 : return js_ReportGetterOnlyAssignment(cx);
387 :
388 0 : if (attrs & JSPROP_SHORTID)
389 0 : id = INT_TO_JSID(shortid);
390 0 : return CallJSPropertyOpSetter(cx, op, obj, id, strict, vp);
391 : }
392 :
393 : static inline JSAtom **
394 24597319 : FrameAtomBase(JSContext *cx, js::StackFrame *fp)
395 : {
396 24597319 : return fp->script()->atoms;
397 : }
398 :
399 : } /* namespace js */
400 :
401 : inline JSVersion
402 5282192 : JSContext::findVersion() const
403 : {
404 5282192 : if (hasVersionOverride)
405 148 : return versionOverride;
406 :
407 5282044 : if (stack.hasfp()) {
408 : /* There may be a scripted function somewhere on the stack! */
409 4045644 : js::StackFrame *f = fp();
410 8106138 : while (f && !f->isScriptFrame())
411 14850 : f = f->prev();
412 4045644 : if (f)
413 4045235 : return f->script()->getVersion();
414 : }
415 :
416 1236809 : return defaultVersion;
417 : }
418 :
419 : inline bool
420 25862 : JSContext::canSetDefaultVersion() const
421 : {
422 25862 : return !stack.hasfp() && !hasVersionOverride;
423 : }
424 :
425 : inline void
426 61 : JSContext::overrideVersion(JSVersion newVersion)
427 : {
428 61 : JS_ASSERT(!canSetDefaultVersion());
429 61 : versionOverride = newVersion;
430 61 : hasVersionOverride = true;
431 61 : }
432 :
433 : inline bool
434 25801 : JSContext::maybeOverrideVersion(JSVersion newVersion)
435 : {
436 25801 : if (canSetDefaultVersion()) {
437 25741 : setDefaultVersion(newVersion);
438 25741 : return false;
439 : }
440 60 : overrideVersion(newVersion);
441 60 : return true;
442 : }
443 :
444 : inline unsigned
445 5011016 : JSContext::getCompileOptions() const { return js::VersionFlagsToOptions(findVersion()); }
446 :
447 : inline unsigned
448 3583334 : JSContext::allOptions() const { return getRunOptions() | getCompileOptions(); }
449 :
450 : inline void
451 1329240 : JSContext::setCompileOptions(unsigned newcopts)
452 : {
453 1329240 : JS_ASSERT((newcopts & JSCOMPILEOPTION_MASK) == newcopts);
454 1329240 : if (JS_LIKELY(getCompileOptions() == newcopts))
455 1328272 : return;
456 968 : JSVersion version = findVersion();
457 968 : JSVersion newVersion = js::OptionFlagsToVersion(newcopts, version);
458 968 : maybeOverrideVersion(newVersion);
459 : }
460 :
461 : inline void
462 : JSContext::assertValidStackDepth(unsigned depth)
463 : {
464 : #ifdef DEBUG
465 : JS_ASSERT(0 <= regs().sp - fp()->base());
466 : JS_ASSERT(depth <= uintptr_t(regs().sp - fp()->base()));
467 : #endif
468 : }
469 :
470 : #ifdef JS_METHODJIT
471 202 : inline js::mjit::JaegerCompartment *JSContext::jaegerCompartment()
472 : {
473 202 : return compartment->jaegerCompartment();
474 : }
475 : #endif
476 :
477 : inline js::LifoAlloc &
478 11813112 : JSContext::typeLifoAlloc()
479 : {
480 11813112 : return compartment->typeLifoAlloc;
481 : }
482 :
483 : inline bool
484 30834 : JSContext::ensureGeneratorStackSpace()
485 : {
486 30834 : bool ok = genStack.reserve(genStack.length() + 1);
487 30834 : if (!ok)
488 0 : js_ReportOutOfMemory(this);
489 30834 : return ok;
490 : }
491 :
492 : inline void
493 138391 : JSContext::setPendingException(js::Value v) {
494 138391 : this->throwing = true;
495 138391 : this->exception = v;
496 138391 : js::assertSameCompartment(this, v);
497 138391 : }
498 :
499 : inline bool
500 134271 : JSContext::ensureParseMapPool()
501 : {
502 134271 : if (parseMapPool_)
503 111773 : return true;
504 22498 : parseMapPool_ = js::OffTheBooks::new_<js::ParseMapPool>(this);
505 22498 : return parseMapPool_;
506 : }
507 :
508 : /* Get the current frame, first lazily instantiating stack frames if needed. */
509 : static inline js::StackFrame *
510 3552954 : js_GetTopStackFrame(JSContext *cx, FrameExpandKind expand)
511 : {
512 : #ifdef JS_METHODJIT
513 3552954 : if (expand)
514 3551012 : js::mjit::ExpandInlineFrames(cx->compartment);
515 : #endif
516 :
517 3552954 : return cx->maybefp();
518 : }
519 :
520 : #endif /* jscntxtinlines_h___ */
|