Bumping manifests a=b2g-bump
[gecko.git] / js / src / jscntxtinlines.h
blob8e285a40bbfc7029ce1c23bd6fd5880bb6cf6dfb
1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
2 * vim: set ts=8 sts=4 et sw=4 tw=99:
3 * This Source Code Form is subject to the terms of the Mozilla Public
4 * License, v. 2.0. If a copy of the MPL was not distributed with this
5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
7 #ifndef jscntxtinlines_h
8 #define jscntxtinlines_h
10 #include "jscntxt.h"
11 #include "jscompartment.h"
13 #include "jsiter.h"
15 #include "builtin/Object.h"
16 #include "jit/JitFrames.h"
17 #include "vm/ForkJoin.h"
18 #include "vm/HelperThreads.h"
19 #include "vm/Interpreter.h"
20 #include "vm/ProxyObject.h"
21 #include "vm/Symbol.h"
23 namespace js {
25 #ifdef JS_CRASH_DIAGNOSTICS
26 class CompartmentChecker
28 JSCompartment* compartment;
30 public:
31 explicit CompartmentChecker(ExclusiveContext* cx)
32 : compartment(cx->compartment())
34 #ifdef DEBUG
35 // In debug builds, make sure the embedder passed the cx it claimed it
36 // was going to use.
37 JSContext* activeContext = nullptr;
38 if (cx->isJSContext())
39 activeContext = cx->asJSContext()->runtime()->activeContext;
40 MOZ_ASSERT_IF(activeContext, cx == activeContext);
41 #endif
45 * Set a breakpoint here (break js::CompartmentChecker::fail) to debug
46 * compartment mismatches.
48 static void fail(JSCompartment* c1, JSCompartment* c2) {
49 printf("*** Compartment mismatch %p vs. %p\n", (void*) c1, (void*) c2);
50 MOZ_CRASH();
53 static void fail(JS::Zone* z1, JS::Zone* z2) {
54 printf("*** Zone mismatch %p vs. %p\n", (void*) z1, (void*) z2);
55 MOZ_CRASH();
58 /* Note: should only be used when neither c1 nor c2 may be the atoms compartment. */
59 static void check(JSCompartment* c1, JSCompartment* c2) {
60 MOZ_ASSERT(!c1->runtimeFromAnyThread()->isAtomsCompartment(c1));
61 MOZ_ASSERT(!c2->runtimeFromAnyThread()->isAtomsCompartment(c2));
62 if (c1 != c2)
63 fail(c1, c2);
66 void check(JSCompartment* c) {
67 if (c && !compartment->runtimeFromAnyThread()->isAtomsCompartment(c)) {
68 if (!compartment)
69 compartment = c;
70 else if (c != compartment)
71 fail(compartment, c);
75 void checkZone(JS::Zone* z) {
76 if (compartment && z != compartment->zone())
77 fail(compartment->zone(), z);
80 void check(JSObject* obj) {
81 if (obj)
82 check(obj->compartment());
85 template<typename T>
86 void check(const Rooted<T>& rooted) {
87 check(rooted.get());
90 template<typename T>
91 void check(Handle<T> handle) {
92 check(handle.get());
95 void check(JSString* str) {
96 if (!str->isAtom())
97 checkZone(str->zone());
100 void check(const js::Value& v) {
101 if (v.isObject())
102 check(&v.toObject());
103 else if (v.isString())
104 check(v.toString());
107 void check(const ValueArray& arr) {
108 for (size_t i = 0; i < arr.length; i++)
109 check(arr.array[i]);
112 void check(const JSValueArray& arr) {
113 for (size_t i = 0; i < arr.length; i++)
114 check(arr.array[i]);
117 void check(const JS::HandleValueArray& arr) {
118 for (size_t i = 0; i < arr.length(); i++)
119 check(arr[i]);
122 void check(const CallArgs& args) {
123 for (Value* p = args.base(); p != args.end(); ++p)
124 check(*p);
127 void check(jsid id) {}
129 void check(JSScript* script) {
130 if (script)
131 check(script->compartment());
134 void check(InterpreterFrame* fp);
135 void check(AbstractFramePtr frame);
136 void check(SavedStacks* stacks);
138 #endif /* JS_CRASH_DIAGNOSTICS */
141 * Don't perform these checks when called from a finalizer. The checking
142 * depends on other objects not having been swept yet.
144 #define START_ASSERT_SAME_COMPARTMENT() \
145 if (cx->isJSContext() && cx->asJSContext()->runtime()->isHeapBusy()) \
146 return; \
147 CompartmentChecker c(cx)
149 template <class T1> inline void
150 assertSameCompartment(ExclusiveContext* cx, const T1& t1)
152 #ifdef JS_CRASH_DIAGNOSTICS
153 START_ASSERT_SAME_COMPARTMENT();
154 c.check(t1);
155 #endif
158 template <class T1> inline void
159 assertSameCompartmentDebugOnly(ExclusiveContext* cx, const T1& t1)
161 #if defined(DEBUG) && defined(JS_CRASH_DIAGNOSTICS)
162 START_ASSERT_SAME_COMPARTMENT();
163 c.check(t1);
164 #endif
167 template <class T1, class T2> inline void
168 assertSameCompartment(ExclusiveContext* cx, const T1& t1, const T2& t2)
170 #ifdef JS_CRASH_DIAGNOSTICS
171 START_ASSERT_SAME_COMPARTMENT();
172 c.check(t1);
173 c.check(t2);
174 #endif
177 template <class T1, class T2, class T3> inline void
178 assertSameCompartment(ExclusiveContext* cx, const T1& t1, const T2& t2, const T3& t3)
180 #ifdef JS_CRASH_DIAGNOSTICS
181 START_ASSERT_SAME_COMPARTMENT();
182 c.check(t1);
183 c.check(t2);
184 c.check(t3);
185 #endif
188 template <class T1, class T2, class T3, class T4> inline void
189 assertSameCompartment(ExclusiveContext* cx,
190 const T1& t1, const T2& t2, const T3& t3, const T4& t4)
192 #ifdef JS_CRASH_DIAGNOSTICS
193 START_ASSERT_SAME_COMPARTMENT();
194 c.check(t1);
195 c.check(t2);
196 c.check(t3);
197 c.check(t4);
198 #endif
201 template <class T1, class T2, class T3, class T4, class T5> inline void
202 assertSameCompartment(ExclusiveContext* cx,
203 const T1& t1, const T2& t2, const T3& t3, const T4& t4, const T5& t5)
205 #ifdef JS_CRASH_DIAGNOSTICS
206 START_ASSERT_SAME_COMPARTMENT();
207 c.check(t1);
208 c.check(t2);
209 c.check(t3);
210 c.check(t4);
211 c.check(t5);
212 #endif
215 #undef START_ASSERT_SAME_COMPARTMENT
217 STATIC_PRECONDITION_ASSUME(ubound(args.argv_) >= argc)
218 MOZ_ALWAYS_INLINE bool
219 CallJSNative(JSContext* cx, Native native, const CallArgs& args)
221 JS_CHECK_RECURSION(cx, return false);
223 #ifdef DEBUG
224 bool alreadyThrowing = cx->isExceptionPending();
225 #endif
226 assertSameCompartment(cx, args);
227 bool ok = native(cx, args.length(), args.base());
228 if (ok) {
229 assertSameCompartment(cx, args.rval());
230 MOZ_ASSERT_IF(!alreadyThrowing, !cx->isExceptionPending());
232 return ok;
235 STATIC_PRECONDITION_ASSUME(ubound(args.argv_) >= argc)
236 MOZ_ALWAYS_INLINE bool
237 CallNativeImpl(JSContext* cx, NativeImpl impl, const CallArgs& args)
239 #ifdef DEBUG
240 bool alreadyThrowing = cx->isExceptionPending();
241 #endif
242 assertSameCompartment(cx, args);
243 bool ok = impl(cx, args);
244 if (ok) {
245 assertSameCompartment(cx, args.rval());
246 MOZ_ASSERT_IF(!alreadyThrowing, !cx->isExceptionPending());
248 return ok;
251 STATIC_PRECONDITION(ubound(args.argv_) >= argc)
252 MOZ_ALWAYS_INLINE bool
253 CallJSNativeConstructor(JSContext* cx, Native native, const CallArgs& args)
255 #ifdef DEBUG
256 RootedObject callee(cx, &args.callee());
257 #endif
259 MOZ_ASSERT(args.thisv().isMagic());
260 if (!CallJSNative(cx, native, args))
261 return false;
264 * Native constructors must return non-primitive values on success.
265 * Although it is legal, if a constructor returns the callee, there is a
266 * 99.9999% chance it is a bug. If any valid code actually wants the
267 * constructor to return the callee, the assertion can be removed or
268 * (another) conjunct can be added to the antecedent.
270 * Exceptions:
272 * - Proxies are exceptions to both rules: they can return primitives and
273 * they allow content to return the callee.
275 * - CallOrConstructBoundFunction is an exception as well because we might
276 * have used bind on a proxy function.
278 * - new Iterator(x) is user-hookable; it returns x.__iterator__() which
279 * could be any object.
281 * - (new Object(Object)) returns the callee.
283 MOZ_ASSERT_IF(native != js::proxy_Construct &&
284 native != js::CallOrConstructBoundFunction &&
285 native != js::IteratorConstructor &&
286 (!callee->is<JSFunction>() || callee->as<JSFunction>().native() != obj_construct),
287 args.rval().isObject() && callee != &args.rval().toObject());
289 return true;
292 MOZ_ALWAYS_INLINE bool
293 CallJSPropertyOp(JSContext* cx, PropertyOp op, HandleObject receiver, HandleId id, MutableHandleValue vp)
295 JS_CHECK_RECURSION(cx, return false);
297 assertSameCompartment(cx, receiver, id, vp);
298 bool ok = op(cx, receiver, id, vp);
299 if (ok)
300 assertSameCompartment(cx, vp);
301 return ok;
304 MOZ_ALWAYS_INLINE bool
305 CallJSPropertyOpSetter(JSContext* cx, StrictPropertyOp op, HandleObject obj, HandleId id,
306 bool strict, MutableHandleValue vp)
308 JS_CHECK_RECURSION(cx, return false);
310 assertSameCompartment(cx, obj, id, vp);
311 return op(cx, obj, id, strict, vp);
314 static inline bool
315 CallJSDeletePropertyOp(JSContext* cx, JSDeletePropertyOp op, HandleObject receiver, HandleId id,
316 bool* succeeded)
318 JS_CHECK_RECURSION(cx, return false);
320 assertSameCompartment(cx, receiver, id);
321 if (op)
322 return op(cx, receiver, id, succeeded);
323 *succeeded = true;
324 return true;
327 inline bool
328 CallSetter(JSContext* cx, HandleObject obj, HandleId id, StrictPropertyOp op, unsigned attrs,
329 bool strict, MutableHandleValue vp)
331 if (attrs & JSPROP_SETTER) {
332 RootedValue opv(cx, CastAsObjectJsval(op));
333 return InvokeGetterOrSetter(cx, obj, opv, 1, vp.address(), vp);
336 if (attrs & JSPROP_GETTER)
337 return js_ReportGetterOnlyAssignment(cx, strict);
339 if (!op)
340 return true;
342 return CallJSPropertyOpSetter(cx, op, obj, id, strict, vp);
345 inline uintptr_t
346 GetNativeStackLimit(ExclusiveContext* cx)
348 StackKind kind;
349 if (cx->isJSContext()) {
350 kind = cx->asJSContext()->runningWithTrustedPrincipals()
351 ? StackForTrustedScript : StackForUntrustedScript;
352 } else {
353 // For other threads, we just use the trusted stack depth, since it's
354 // unlikely that we'll be mixing trusted and untrusted code together.
355 kind = StackForTrustedScript;
357 return cx->perThreadData->nativeStackLimit[kind];
360 inline LifoAlloc&
361 ExclusiveContext::typeLifoAlloc()
363 return zone()->types.typeLifoAlloc;
366 } /* namespace js */
368 inline void
369 JSContext::setPendingException(js::Value v)
371 MOZ_ASSERT(!IsPoisonedValue(v));
372 // overRecursed_ is set after the fact by js_ReportOverRecursed.
373 this->overRecursed_ = false;
374 this->throwing = true;
375 this->unwrappedException_ = v;
376 // We don't use assertSameCompartment here to allow
377 // js::SetPendingExceptionCrossContext to work.
378 MOZ_ASSERT_IF(v.isObject(), v.toObject().compartment() == compartment());
381 inline bool
382 JSContext::runningWithTrustedPrincipals() const
384 return !compartment() || compartment()->principals == runtime()->trustedPrincipals();
387 inline void
388 js::ExclusiveContext::enterCompartment(JSCompartment* c)
390 enterCompartmentDepth_++;
391 c->enter();
392 setCompartment(c);
395 inline void
396 js::ExclusiveContext::enterNullCompartment()
398 enterCompartmentDepth_++;
399 setCompartment(nullptr);
402 inline void
403 js::ExclusiveContext::leaveCompartment(JSCompartment* oldCompartment)
405 MOZ_ASSERT(hasEnteredCompartment());
406 enterCompartmentDepth_--;
408 // Only call leave() after we've setCompartment()-ed away from the current
409 // compartment.
410 JSCompartment* startingCompartment = compartment_;
411 setCompartment(oldCompartment);
412 if (startingCompartment)
413 startingCompartment->leave();
416 inline void
417 js::ExclusiveContext::setCompartment(JSCompartment* comp)
419 // ExclusiveContexts can only be in the atoms zone or in exclusive zones.
420 MOZ_ASSERT_IF(!isJSContext() && !runtime_->isAtomsCompartment(comp),
421 comp->zone()->usedByExclusiveThread);
423 // Normal JSContexts cannot enter exclusive zones.
424 MOZ_ASSERT_IF(isJSContext() && comp,
425 !comp->zone()->usedByExclusiveThread);
427 // Only one thread can be in the atoms compartment at a time.
428 MOZ_ASSERT_IF(runtime_->isAtomsCompartment(comp),
429 runtime_->currentThreadHasExclusiveAccess());
431 // Make sure that the atoms compartment has its own zone.
432 MOZ_ASSERT_IF(comp && !runtime_->isAtomsCompartment(comp),
433 !runtime_->isAtomsZone(comp->zone()));
435 // Both the current and the new compartment should be properly marked as
436 // entered at this point.
437 MOZ_ASSERT_IF(compartment_, compartment_->hasBeenEntered());
438 MOZ_ASSERT_IF(comp, comp->hasBeenEntered());
440 compartment_ = comp;
441 zone_ = comp ? comp->zone() : nullptr;
442 allocator_ = zone_ ? &zone_->allocator : nullptr;
445 inline JSScript*
446 JSContext::currentScript(jsbytecode** ppc,
447 MaybeAllowCrossCompartment allowCrossCompartment) const
449 if (ppc)
450 *ppc = nullptr;
452 js::Activation* act = mainThread().activation();
453 while (act && (act->cx() != this || (act->isJit() && !act->asJit()->isActive())))
454 act = act->prev();
456 if (!act)
457 return nullptr;
459 MOZ_ASSERT(act->cx() == this);
461 if (act->isJit()) {
462 JSScript* script = nullptr;
463 js::jit::GetPcScript(const_cast<JSContext*>(this), &script, ppc);
464 if (!allowCrossCompartment && script->compartment() != compartment())
465 return nullptr;
466 return script;
469 if (act->isAsmJS())
470 return nullptr;
472 MOZ_ASSERT(act->isInterpreter());
474 js::InterpreterFrame* fp = act->asInterpreter()->current();
475 MOZ_ASSERT(!fp->runningInJit());
477 JSScript* script = fp->script();
478 if (!allowCrossCompartment && script->compartment() != compartment())
479 return nullptr;
481 if (ppc) {
482 *ppc = act->asInterpreter()->regs().pc;
483 MOZ_ASSERT(script->containsPC(*ppc));
485 return script;
488 template <JSThreadSafeNative threadSafeNative>
489 inline bool
490 JSNativeThreadSafeWrapper(JSContext* cx, unsigned argc, JS::Value* vp)
492 return threadSafeNative(cx, argc, vp);
495 template <JSThreadSafeNative threadSafeNative>
496 inline bool
497 JSParallelNativeThreadSafeWrapper(js::ForkJoinContext* cx, unsigned argc, JS::Value* vp)
499 return threadSafeNative(cx, argc, vp);
502 /* static */ inline JSContext*
503 js::ExecutionModeTraits<js::SequentialExecution>::toContextType(ExclusiveContext* cx)
505 return cx->asJSContext();
508 #endif /* jscntxtinlines_h */