js/src/jscntxt.h

branch
TOR_BUG_3246
changeset 7
129ffea94266
equal deleted inserted replaced
-1:000000000000 0:4a00887258ff
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/. */
6
7 /* JS execution context. */
8
9 #ifndef jscntxt_h
10 #define jscntxt_h
11
12 #include "mozilla/MemoryReporting.h"
13
14 #include "js/Vector.h"
15 #include "vm/Runtime.h"
16
17 #ifdef _MSC_VER
18 #pragma warning(push)
19 #pragma warning(disable:4100) /* Silence unreferenced formal parameter warnings */
20 #endif
21
22 struct DtoaState;
23
24 extern void
25 js_ReportOutOfMemory(js::ThreadSafeContext *cx);
26
27 extern void
28 js_ReportAllocationOverflow(js::ThreadSafeContext *cx);
29
30 extern void
31 js_ReportOverRecursed(js::ThreadSafeContext *cx);
32
33 namespace js {
34
35 namespace jit {
36 class IonContext;
37 class CompileCompartment;
38 }
39
40 struct CallsiteCloneKey {
41 /* The original function that we are cloning. */
42 JSFunction *original;
43
44 /* The script of the call. */
45 JSScript *script;
46
47 /* The offset of the call. */
48 uint32_t offset;
49
50 CallsiteCloneKey(JSFunction *f, JSScript *s, uint32_t o) : original(f), script(s), offset(o) {}
51
52 typedef CallsiteCloneKey Lookup;
53
54 static inline uint32_t hash(CallsiteCloneKey key) {
55 return uint32_t(size_t(key.script->offsetToPC(key.offset)) ^ size_t(key.original));
56 }
57
58 static inline bool match(const CallsiteCloneKey &a, const CallsiteCloneKey &b) {
59 return a.script == b.script && a.offset == b.offset && a.original == b.original;
60 }
61 };
62
63 typedef HashMap<CallsiteCloneKey,
64 ReadBarriered<JSFunction>,
65 CallsiteCloneKey,
66 SystemAllocPolicy> CallsiteCloneTable;
67
68 JSFunction *
69 ExistingCloneFunctionAtCallsite(const CallsiteCloneTable &table, JSFunction *fun,
70 JSScript *script, jsbytecode *pc);
71
72 JSFunction *CloneFunctionAtCallsite(JSContext *cx, HandleFunction fun,
73 HandleScript script, jsbytecode *pc);
74
75 typedef HashSet<JSObject *> ObjectSet;
76 typedef HashSet<Shape *> ShapeSet;
77
78 /* Detects cycles when traversing an object graph. */
79 class AutoCycleDetector
80 {
81 JSContext *cx;
82 RootedObject obj;
83 bool cyclic;
84 uint32_t hashsetGenerationAtInit;
85 ObjectSet::AddPtr hashsetAddPointer;
86 MOZ_DECL_USE_GUARD_OBJECT_NOTIFIER
87
88 public:
89 AutoCycleDetector(JSContext *cx, HandleObject objArg
90 MOZ_GUARD_OBJECT_NOTIFIER_PARAM)
91 : cx(cx), obj(cx, objArg), cyclic(true)
92 {
93 MOZ_GUARD_OBJECT_NOTIFIER_INIT;
94 }
95
96 ~AutoCycleDetector();
97
98 bool init();
99
100 bool foundCycle() { return cyclic; }
101 };
102
103 /* Updates references in the cycle detection set if the GC moves them. */
104 extern void
105 TraceCycleDetectionSet(JSTracer *trc, ObjectSet &set);
106
107 struct AutoResolving;
108 class DtoaCache;
109 class ForkJoinContext;
110 class RegExpCompartment;
111 class RegExpStatics;
112
113 namespace frontend { struct CompileError; }
114
115 /*
116 * Execution Context Overview:
117 *
118 * Several different structures may be used to provide a context for operations
119 * on the VM. Each context is thread local, but varies in what data it can
120 * access and what other threads may be running.
121 *
122 * - ThreadSafeContext is used by threads operating in one compartment which
123 * may run in parallel with other threads operating on the same or other
124 * compartments.
125 *
126 * - ExclusiveContext is used by threads operating in one compartment/zone,
127 * where other threads may operate in other compartments, but *not* the same
128 * compartment or zone which the ExclusiveContext is in. A thread with an
129 * ExclusiveContext may enter the atoms compartment and atomize strings, in
130 * which case a lock is used.
131 *
132 * - JSContext is used only by the runtime's main thread. The context may
133 * operate in any compartment or zone which is not used by an ExclusiveContext
134 * or ThreadSafeContext, and will only run in parallel with threads using such
135 * contexts.
136 *
137 * An ExclusiveContext coerces to a ThreadSafeContext, and a JSContext coerces
138 * to an ExclusiveContext or ThreadSafeContext.
139 *
140 * Contexts which are a ThreadSafeContext but not an ExclusiveContext are used
141 * to represent a ForkJoinContext, the per-thread parallel context used in PJS.
142 */
143
144 struct ThreadSafeContext : ContextFriendFields,
145 public MallocProvider<ThreadSafeContext>
146 {
147 friend struct StackBaseShape;
148 friend UnownedBaseShape *BaseShape::lookupUnowned(ThreadSafeContext *cx,
149 const StackBaseShape &base);
150 friend Shape *JSObject::lookupChildProperty(ThreadSafeContext *cx,
151 JS::HandleObject obj, js::HandleShape parent,
152 js::StackShape &child);
153
154 public:
155 enum ContextKind {
156 Context_JS,
157 Context_Exclusive,
158 Context_ForkJoin
159 };
160
161 private:
162 ContextKind contextKind_;
163
164 public:
165 PerThreadData *perThreadData;
166
167 ThreadSafeContext(JSRuntime *rt, PerThreadData *pt, ContextKind kind);
168
169 bool isJSContext() const {
170 return contextKind_ == Context_JS;
171 }
172
173 JSContext *maybeJSContext() const {
174 if (isJSContext())
175 return (JSContext *) this;
176 return nullptr;
177 }
178
179 JSContext *asJSContext() const {
180 // Note: there is no way to perform an unchecked coercion from a
181 // ThreadSafeContext to a JSContext. This ensures that trying to use
182 // the context as a JSContext off the main thread will nullptr crash
183 // rather than race.
184 JS_ASSERT(isJSContext());
185 return maybeJSContext();
186 }
187
188 // In some cases we could potentially want to do operations that require a
189 // JSContext while running off the main thread. While this should never
190 // actually happen, the wide enough API for working off the main thread
191 // makes such operations impossible to rule out. Rather than blindly using
192 // asJSContext() and crashing afterwards, this method may be used to watch
193 // for such cases and produce either a soft failure in release builds or
194 // an assertion failure in debug builds.
195 bool shouldBeJSContext() const {
196 JS_ASSERT(isJSContext());
197 return isJSContext();
198 }
199
200 bool isExclusiveContext() const {
201 return contextKind_ == Context_JS || contextKind_ == Context_Exclusive;
202 }
203
204 ExclusiveContext *maybeExclusiveContext() const {
205 if (isExclusiveContext())
206 return (ExclusiveContext *) this;
207 return nullptr;
208 }
209
210 ExclusiveContext *asExclusiveContext() const {
211 JS_ASSERT(isExclusiveContext());
212 return maybeExclusiveContext();
213 }
214
215 bool isForkJoinContext() const;
216 ForkJoinContext *asForkJoinContext();
217
218 // The generational GC nursery may only be used on the main thread.
219 #ifdef JSGC_GENERATIONAL
220 inline bool hasNursery() const {
221 return isJSContext();
222 }
223
224 inline js::Nursery &nursery() {
225 JS_ASSERT(hasNursery());
226 return runtime_->gcNursery;
227 }
228 #endif
229
230 /*
231 * Allocator used when allocating GCThings on this context. If we are a
232 * JSContext, this is the Zone allocator of the JSContext's zone.
233 * Otherwise, this is a per-thread allocator.
234 *
235 * This does not live in PerThreadData because the notion of an allocator
236 * is only per-thread when off the main thread. The runtime (and the main
237 * thread) can have more than one zone, each with its own allocator, and
238 * it's up to the context to specify what compartment and zone we are
239 * operating in.
240 */
241 protected:
242 Allocator *allocator_;
243
244 public:
245 static size_t offsetOfAllocator() { return offsetof(ThreadSafeContext, allocator_); }
246
247 inline Allocator *const allocator();
248
249 // Allocations can only trigger GC when running on the main thread.
250 inline AllowGC allowGC() const { return isJSContext() ? CanGC : NoGC; }
251
252 template <typename T>
253 bool isInsideCurrentZone(T thing) const {
254 return thing->zoneFromAnyThread() == zone_;
255 }
256
257 template <typename T>
258 inline bool isInsideCurrentCompartment(T thing) const {
259 return thing->compartment() == compartment_;
260 }
261
262 template <typename T>
263 inline bool isThreadLocal(T thing) const;
264
265 void *onOutOfMemory(void *p, size_t nbytes) {
266 return runtime_->onOutOfMemory(p, nbytes, maybeJSContext());
267 }
268
269 /* Clear the pending exception (if any) due to OOM. */
270 void recoverFromOutOfMemory();
271
272 inline void updateMallocCounter(size_t nbytes) {
273 // Note: this is racy.
274 runtime_->updateMallocCounter(zone_, nbytes);
275 }
276
277 void reportAllocationOverflow() {
278 js_ReportAllocationOverflow(this);
279 }
280
281 // Accessors for immutable runtime data.
282 JSAtomState &names() { return *runtime_->commonNames; }
283 StaticStrings &staticStrings() { return *runtime_->staticStrings; }
284 AtomSet &permanentAtoms() { return *runtime_->permanentAtoms; }
285 const JS::AsmJSCacheOps &asmJSCacheOps() { return runtime_->asmJSCacheOps; }
286 PropertyName *emptyString() { return runtime_->emptyString; }
287 FreeOp *defaultFreeOp() { return runtime_->defaultFreeOp(); }
288 bool useHelperThreads() { return runtime_->useHelperThreads(); }
289 void *runtimeAddressForJit() { return runtime_; }
290 void *stackLimitAddress(StackKind kind) { return &runtime_->mainThread.nativeStackLimit[kind]; }
291 void *stackLimitAddressForJitCode(StackKind kind);
292 size_t gcSystemPageSize() { return runtime_->gcSystemPageSize; }
293 bool signalHandlersInstalled() const { return runtime_->signalHandlersInstalled(); }
294 bool jitSupportsFloatingPoint() const { return runtime_->jitSupportsFloatingPoint; }
295
296 // Thread local data that may be accessed freely.
297 DtoaState *dtoaState() {
298 return perThreadData->dtoaState;
299 }
300 };
301
302 struct WorkerThread;
303
304 class ExclusiveContext : public ThreadSafeContext
305 {
306 friend class gc::ArenaLists;
307 friend class AutoCompartment;
308 friend class AutoLockForExclusiveAccess;
309 friend struct StackBaseShape;
310 friend void JSScript::initCompartment(ExclusiveContext *cx);
311 friend class jit::IonContext;
312
313 // The worker on which this context is running, if this is not a JSContext.
314 WorkerThread *workerThread_;
315
316 public:
317
318 ExclusiveContext(JSRuntime *rt, PerThreadData *pt, ContextKind kind)
319 : ThreadSafeContext(rt, pt, kind),
320 workerThread_(nullptr),
321 enterCompartmentDepth_(0)
322 {}
323
324 /*
325 * "Entering" a compartment changes cx->compartment (which changes
326 * cx->global). Note that this does not push any InterpreterFrame which means
327 * that it is possible for cx->fp()->compartment() != cx->compartment.
328 * This is not a problem since, in general, most places in the VM cannot
329 * know that they were called from script (e.g., they may have been called
330 * through the JSAPI via JS_CallFunction) and thus cannot expect fp.
331 *
332 * Compartments should be entered/left in a LIFO fasion. The depth of this
333 * enter/leave stack is maintained by enterCompartmentDepth_ and queried by
334 * hasEnteredCompartment.
335 *
336 * To enter a compartment, code should prefer using AutoCompartment over
337 * manually calling cx->enterCompartment/leaveCompartment.
338 */
339 protected:
340 unsigned enterCompartmentDepth_;
341 inline void setCompartment(JSCompartment *comp);
342 public:
343 bool hasEnteredCompartment() const {
344 return enterCompartmentDepth_ > 0;
345 }
346 #ifdef DEBUG
347 unsigned getEnterCompartmentDepth() const {
348 return enterCompartmentDepth_;
349 }
350 #endif
351
352 inline void enterCompartment(JSCompartment *c);
353 inline void enterNullCompartment();
354 inline void leaveCompartment(JSCompartment *oldCompartment);
355
356 void setWorkerThread(WorkerThread *workerThread);
357 WorkerThread *workerThread() const { return workerThread_; }
358
359 // Threads with an ExclusiveContext may freely access any data in their
360 // compartment and zone.
361 JSCompartment *compartment() const {
362 JS_ASSERT_IF(runtime_->isAtomsCompartment(compartment_),
363 runtime_->currentThreadHasExclusiveAccess());
364 return compartment_;
365 }
366 JS::Zone *zone() const {
367 JS_ASSERT_IF(!compartment(), !zone_);
368 JS_ASSERT_IF(compartment(), js::GetCompartmentZone(compartment()) == zone_);
369 return zone_;
370 }
371
372 // Zone local methods that can be used freely from an ExclusiveContext.
373 types::TypeObject *getNewType(const Class *clasp, TaggedProto proto, JSFunction *fun = nullptr);
374 types::TypeObject *getSingletonType(const Class *clasp, TaggedProto proto);
375 inline js::LifoAlloc &typeLifoAlloc();
376
377 // Current global. This is only safe to use within the scope of the
378 // AutoCompartment from which it's called.
379 inline js::Handle<js::GlobalObject*> global() const;
380
381 // Methods to access runtime data that must be protected by locks.
382 frontend::ParseMapPool &parseMapPool() {
383 return runtime_->parseMapPool();
384 }
385 AtomSet &atoms() {
386 return runtime_->atoms();
387 }
388 JSCompartment *atomsCompartment() {
389 return runtime_->atomsCompartment();
390 }
391 ScriptDataTable &scriptDataTable() {
392 return runtime_->scriptDataTable();
393 }
394
395 // Methods specific to any WorkerThread for the context.
396 frontend::CompileError &addPendingCompileError();
397 void addPendingOverRecursed();
398 };
399
400 } /* namespace js */
401
402 struct JSContext : public js::ExclusiveContext,
403 public mozilla::LinkedListElement<JSContext>
404 {
405 explicit JSContext(JSRuntime *rt);
406 ~JSContext();
407
408 JSRuntime *runtime() const { return runtime_; }
409 js::PerThreadData &mainThread() const { return runtime()->mainThread; }
410
411 static size_t offsetOfRuntime() {
412 return offsetof(JSContext, runtime_);
413 }
414
415 friend class js::ExclusiveContext;
416 friend class JS::AutoSaveExceptionState;
417
418 private:
419 /* Exception state -- the exception member is a GC root by definition. */
420 bool throwing; /* is there a pending exception? */
421 js::Value unwrappedException_; /* most-recently-thrown exception */
422
423 /* Per-context options. */
424 JS::ContextOptions options_;
425
426 public:
427 int32_t reportGranularity; /* see vm/Probes.h */
428
429 js::AutoResolving *resolvingList;
430
431 /* True if generating an error, to prevent runaway recursion. */
432 bool generatingError;
433
434 /* See JS_SaveFrameChain/JS_RestoreFrameChain. */
435 private:
436 struct SavedFrameChain {
437 SavedFrameChain(JSCompartment *comp, unsigned count)
438 : compartment(comp), enterCompartmentCount(count) {}
439 JSCompartment *compartment;
440 unsigned enterCompartmentCount;
441 };
442 typedef js::Vector<SavedFrameChain, 1, js::SystemAllocPolicy> SaveStack;
443 SaveStack savedFrameChains_;
444 public:
445 bool saveFrameChain();
446 void restoreFrameChain();
447
448 /*
449 * When no compartments have been explicitly entered, the context's
450 * compartment will be set to the compartment of the "default compartment
451 * object".
452 */
453 private:
454 JSObject *defaultCompartmentObject_;
455 public:
456 inline void setDefaultCompartmentObject(JSObject *obj);
457 inline void setDefaultCompartmentObjectIfUnset(JSObject *obj);
458 JSObject *maybeDefaultCompartmentObject() const {
459 JS_ASSERT(!options().noDefaultCompartmentObject());
460 return defaultCompartmentObject_;
461 }
462
463 /* State for object and array toSource conversion. */
464 js::ObjectSet cycleDetectorSet;
465
466 /* Per-context optional error reporter. */
467 JSErrorReporter errorReporter;
468
469 /* Client opaque pointers. */
470 void *data;
471 void *data2;
472
473 public:
474
475 /*
476 * Return:
477 * - The newest scripted frame's version, if there is such a frame.
478 * - The version from the compartment.
479 * - The default version.
480 *
481 * Note: if this ever shows up in a profile, just add caching!
482 */
483 JSVersion findVersion() const;
484
485 const JS::ContextOptions &options() const {
486 return options_;
487 }
488
489 JS::ContextOptions &options() {
490 return options_;
491 }
492
493 js::LifoAlloc &tempLifoAlloc() { return runtime()->tempLifoAlloc; }
494
495 #ifdef JS_THREADSAFE
496 unsigned outstandingRequests;/* number of JS_BeginRequest calls
497 without the corresponding
498 JS_EndRequest. */
499 #endif
500
501 /* Location to stash the iteration value between JSOP_MOREITER and JSOP_ITERNEXT. */
502 js::Value iterValue;
503
504 bool jitIsBroken;
505
506 void updateJITEnabled();
507
508 /* Whether this context has JS frames on the stack. */
509 bool currentlyRunning() const;
510
511 bool currentlyRunningInInterpreter() const {
512 return mainThread().activation()->isInterpreter();
513 }
514 bool currentlyRunningInJit() const {
515 return mainThread().activation()->isJit();
516 }
517 js::InterpreterFrame *interpreterFrame() const {
518 return mainThread().activation()->asInterpreter()->current();
519 }
520 js::InterpreterRegs &interpreterRegs() const {
521 return mainThread().activation()->asInterpreter()->regs();
522 }
523
524 /*
525 * Get the topmost script and optional pc on the stack. By default, this
526 * function only returns a JSScript in the current compartment, returning
527 * nullptr if the current script is in a different compartment. This
528 * behavior can be overridden by passing ALLOW_CROSS_COMPARTMENT.
529 */
530 enum MaybeAllowCrossCompartment {
531 DONT_ALLOW_CROSS_COMPARTMENT = false,
532 ALLOW_CROSS_COMPARTMENT = true
533 };
534 inline JSScript *currentScript(jsbytecode **pc = nullptr,
535 MaybeAllowCrossCompartment = DONT_ALLOW_CROSS_COMPARTMENT) const;
536
537 #ifdef MOZ_TRACE_JSCALLS
538 /* Function entry/exit debugging callback. */
539 JSFunctionCallback functionCallback;
540
541 void doFunctionCallback(const JSFunction *fun,
542 const JSScript *scr,
543 int entering) const
544 {
545 if (functionCallback)
546 functionCallback(fun, scr, this, entering);
547 }
548 #endif
549
550 private:
551 /* Innermost-executing generator or null if no generator are executing. */
552 JSGenerator *innermostGenerator_;
553 public:
554 JSGenerator *innermostGenerator() const { return innermostGenerator_; }
555 void enterGenerator(JSGenerator *gen);
556 void leaveGenerator(JSGenerator *gen);
557
558 bool isExceptionPending() {
559 return throwing;
560 }
561
562 MOZ_WARN_UNUSED_RESULT
563 bool getPendingException(JS::MutableHandleValue rval);
564
565 bool isThrowingOutOfMemory();
566
567 void setPendingException(js::Value v);
568
569 void clearPendingException() {
570 throwing = false;
571 unwrappedException_.setUndefined();
572 }
573
574 #ifdef DEBUG
575 /*
576 * Controls whether a quadratic-complexity assertion is performed during
577 * stack iteration; defaults to true.
578 */
579 bool stackIterAssertionEnabled;
580 #endif
581
582 /*
583 * See JS_SetTrustedPrincipals in jsapi.h.
584 * Note: !cx->compartment is treated as trusted.
585 */
586 bool runningWithTrustedPrincipals() const;
587
588 JS_FRIEND_API(size_t) sizeOfIncludingThis(mozilla::MallocSizeOf mallocSizeOf) const;
589
590 void mark(JSTracer *trc);
591
592 private:
593 /*
594 * The allocation code calls the function to indicate either OOM failure
595 * when p is null or that a memory pressure counter has reached some
596 * threshold when p is not null. The function takes the pointer and not
597 * a boolean flag to minimize the amount of code in its inlined callers.
598 */
599 JS_FRIEND_API(void) checkMallocGCPressure(void *p);
600 }; /* struct JSContext */
601
602 namespace js {
603
604 struct AutoResolving {
605 public:
606 enum Kind {
607 LOOKUP,
608 WATCH
609 };
610
611 AutoResolving(JSContext *cx, HandleObject obj, HandleId id, Kind kind = LOOKUP
612 MOZ_GUARD_OBJECT_NOTIFIER_PARAM)
613 : context(cx), object(obj), id(id), kind(kind), link(cx->resolvingList)
614 {
615 MOZ_GUARD_OBJECT_NOTIFIER_INIT;
616 JS_ASSERT(obj);
617 cx->resolvingList = this;
618 }
619
620 ~AutoResolving() {
621 JS_ASSERT(context->resolvingList == this);
622 context->resolvingList = link;
623 }
624
625 bool alreadyStarted() const {
626 return link && alreadyStartedSlow();
627 }
628
629 private:
630 bool alreadyStartedSlow() const;
631
632 JSContext *const context;
633 HandleObject object;
634 HandleId id;
635 Kind const kind;
636 AutoResolving *const link;
637 MOZ_DECL_USE_GUARD_OBJECT_NOTIFIER
638 };
639
640 /*
641 * Enumerate all contexts in a runtime.
642 */
643 class ContextIter {
644 JSContext *iter;
645
646 public:
647 explicit ContextIter(JSRuntime *rt) {
648 iter = rt->contextList.getFirst();
649 }
650
651 bool done() const {
652 return !iter;
653 }
654
655 void next() {
656 JS_ASSERT(!done());
657 iter = iter->getNext();
658 }
659
660 JSContext *get() const {
661 JS_ASSERT(!done());
662 return iter;
663 }
664
665 operator JSContext *() const {
666 return get();
667 }
668
669 JSContext *operator ->() const {
670 return get();
671 }
672 };
673
674 /*
675 * Create and destroy functions for JSContext, which is manually allocated
676 * and exclusively owned.
677 */
678 extern JSContext *
679 NewContext(JSRuntime *rt, size_t stackChunkSize);
680
681 enum DestroyContextMode {
682 DCM_NO_GC,
683 DCM_FORCE_GC,
684 DCM_NEW_FAILED
685 };
686
687 extern void
688 DestroyContext(JSContext *cx, DestroyContextMode mode);
689
690 enum ErrorArgumentsType {
691 ArgumentsAreUnicode,
692 ArgumentsAreASCII
693 };
694
695
696 /*
697 * Loads and returns a self-hosted function by name. For performance, define
698 * the property name in vm/CommonPropertyNames.h.
699 *
700 * Defined in SelfHosting.cpp.
701 */
702 JSFunction *
703 SelfHostedFunction(JSContext *cx, HandlePropertyName propName);
704
705 } /* namespace js */
706
707 #ifdef va_start
708 extern bool
709 js_ReportErrorVA(JSContext *cx, unsigned flags, const char *format, va_list ap);
710
711 extern bool
712 js_ReportErrorNumberVA(JSContext *cx, unsigned flags, JSErrorCallback callback,
713 void *userRef, const unsigned errorNumber,
714 js::ErrorArgumentsType argumentsType, va_list ap);
715
716 extern bool
717 js_ReportErrorNumberUCArray(JSContext *cx, unsigned flags, JSErrorCallback callback,
718 void *userRef, const unsigned errorNumber,
719 const jschar **args);
720 #endif
721
722 extern bool
723 js_ExpandErrorArguments(js::ExclusiveContext *cx, JSErrorCallback callback,
724 void *userRef, const unsigned errorNumber,
725 char **message, JSErrorReport *reportp,
726 js::ErrorArgumentsType argumentsType, va_list ap);
727
728 namespace js {
729
730 /* |callee| requires a usage string provided by JS_DefineFunctionsWithHelp. */
731 extern void
732 ReportUsageError(JSContext *cx, HandleObject callee, const char *msg);
733
734 /*
735 * Prints a full report and returns true if the given report is non-nullptr
736 * and the report doesn't have the JSREPORT_WARNING flag set or reportWarnings
737 * is true.
738 * Returns false otherwise, printing just the message if the report is nullptr.
739 */
740 extern bool
741 PrintError(JSContext *cx, FILE *file, const char *message, JSErrorReport *report,
742 bool reportWarnings);
743
744 /*
745 * Send a JSErrorReport to the errorReporter callback.
746 */
747 void
748 CallErrorReporter(JSContext *cx, const char *message, JSErrorReport *report);
749
750 } /* namespace js */
751
752 extern void
753 js_ReportIsNotDefined(JSContext *cx, const char *name);
754
755 /*
756 * Report an attempt to access the property of a null or undefined value (v).
757 */
758 extern bool
759 js_ReportIsNullOrUndefined(JSContext *cx, int spindex, js::HandleValue v,
760 js::HandleString fallback);
761
762 extern void
763 js_ReportMissingArg(JSContext *cx, js::HandleValue v, unsigned arg);
764
765 /*
766 * Report error using js_DecompileValueGenerator(cx, spindex, v, fallback) as
767 * the first argument for the error message. If the error message has less
768 * then 3 arguments, use null for arg1 or arg2.
769 */
770 extern bool
771 js_ReportValueErrorFlags(JSContext *cx, unsigned flags, const unsigned errorNumber,
772 int spindex, js::HandleValue v, js::HandleString fallback,
773 const char *arg1, const char *arg2);
774
775 #define js_ReportValueError(cx,errorNumber,spindex,v,fallback) \
776 ((void)js_ReportValueErrorFlags(cx, JSREPORT_ERROR, errorNumber, \
777 spindex, v, fallback, nullptr, nullptr))
778
779 #define js_ReportValueError2(cx,errorNumber,spindex,v,fallback,arg1) \
780 ((void)js_ReportValueErrorFlags(cx, JSREPORT_ERROR, errorNumber, \
781 spindex, v, fallback, arg1, nullptr))
782
783 #define js_ReportValueError3(cx,errorNumber,spindex,v,fallback,arg1,arg2) \
784 ((void)js_ReportValueErrorFlags(cx, JSREPORT_ERROR, errorNumber, \
785 spindex, v, fallback, arg1, arg2))
786
787 extern const JSErrorFormatString js_ErrorFormatString[JSErr_Limit];
788
789 char *
790 js_strdup(js::ExclusiveContext *cx, const char *s);
791
792 #ifdef JS_THREADSAFE
793 # define JS_ASSERT_REQUEST_DEPTH(cx) JS_ASSERT((cx)->runtime()->requestDepth >= 1)
794 #else
795 # define JS_ASSERT_REQUEST_DEPTH(cx) ((void) 0)
796 #endif
797
798 namespace js {
799
800 /*
801 * Invoke the interrupt callback and return false if the current execution
802 * is to be terminated.
803 */
804 bool
805 InvokeInterruptCallback(JSContext *cx);
806
807 bool
808 HandleExecutionInterrupt(JSContext *cx);
809
810 /*
811 * Process any pending interrupt requests. Long-running inner loops in C++ must
812 * call this periodically to make sure they are interruptible --- that is, to
813 * make sure they do not prevent the slow script dialog from appearing.
814 *
815 * This can run a full GC or call the interrupt callback, which could do
816 * anything. In the browser, it displays the slow script dialog.
817 *
818 * If this returns true, the caller can continue; if false, the caller must
819 * break out of its loop. This happens if, for example, the user clicks "Stop
820 * script" on the slow script dialog; treat it as an uncatchable error.
821 */
822 inline bool
823 CheckForInterrupt(JSContext *cx)
824 {
825 JS_ASSERT_REQUEST_DEPTH(cx);
826 return !cx->runtime()->interrupt || InvokeInterruptCallback(cx);
827 }
828
829 /************************************************************************/
830
831 class AutoStringVector : public AutoVectorRooter<JSString *>
832 {
833 public:
834 explicit AutoStringVector(JSContext *cx
835 MOZ_GUARD_OBJECT_NOTIFIER_PARAM)
836 : AutoVectorRooter<JSString *>(cx, STRINGVECTOR)
837 {
838 MOZ_GUARD_OBJECT_NOTIFIER_INIT;
839 }
840
841 MOZ_DECL_USE_GUARD_OBJECT_NOTIFIER
842 };
843
844 class AutoPropertyNameVector : public AutoVectorRooter<PropertyName *>
845 {
846 public:
847 explicit AutoPropertyNameVector(JSContext *cx
848 MOZ_GUARD_OBJECT_NOTIFIER_PARAM)
849 : AutoVectorRooter<PropertyName *>(cx, STRINGVECTOR)
850 {
851 MOZ_GUARD_OBJECT_NOTIFIER_INIT;
852 }
853
854 MOZ_DECL_USE_GUARD_OBJECT_NOTIFIER
855 };
856
857 class AutoShapeVector : public AutoVectorRooter<Shape *>
858 {
859 public:
860 explicit AutoShapeVector(JSContext *cx
861 MOZ_GUARD_OBJECT_NOTIFIER_PARAM)
862 : AutoVectorRooter<Shape *>(cx, SHAPEVECTOR)
863 {
864 MOZ_GUARD_OBJECT_NOTIFIER_INIT;
865 }
866
867 MOZ_DECL_USE_GUARD_OBJECT_NOTIFIER
868 };
869
870 class AutoObjectObjectHashMap : public AutoHashMapRooter<JSObject *, JSObject *>
871 {
872 public:
873 explicit AutoObjectObjectHashMap(JSContext *cx
874 MOZ_GUARD_OBJECT_NOTIFIER_PARAM)
875 : AutoHashMapRooter<JSObject *, JSObject *>(cx, OBJOBJHASHMAP)
876 {
877 MOZ_GUARD_OBJECT_NOTIFIER_INIT;
878 }
879
880 MOZ_DECL_USE_GUARD_OBJECT_NOTIFIER
881 };
882
883 class AutoObjectUnsigned32HashMap : public AutoHashMapRooter<JSObject *, uint32_t>
884 {
885 public:
886 explicit AutoObjectUnsigned32HashMap(JSContext *cx
887 MOZ_GUARD_OBJECT_NOTIFIER_PARAM)
888 : AutoHashMapRooter<JSObject *, uint32_t>(cx, OBJU32HASHMAP)
889 {
890 MOZ_GUARD_OBJECT_NOTIFIER_INIT;
891 }
892
893 MOZ_DECL_USE_GUARD_OBJECT_NOTIFIER
894 };
895
896 class AutoObjectHashSet : public AutoHashSetRooter<JSObject *>
897 {
898 public:
899 explicit AutoObjectHashSet(JSContext *cx
900 MOZ_GUARD_OBJECT_NOTIFIER_PARAM)
901 : AutoHashSetRooter<JSObject *>(cx, OBJHASHSET)
902 {
903 MOZ_GUARD_OBJECT_NOTIFIER_INIT;
904 }
905
906 MOZ_DECL_USE_GUARD_OBJECT_NOTIFIER
907 };
908
909 /* AutoArrayRooter roots an external array of Values. */
910 class AutoArrayRooter : private AutoGCRooter
911 {
912 public:
913 AutoArrayRooter(JSContext *cx, size_t len, Value *vec
914 MOZ_GUARD_OBJECT_NOTIFIER_PARAM)
915 : AutoGCRooter(cx, len), array(vec)
916 {
917 MOZ_GUARD_OBJECT_NOTIFIER_INIT;
918 JS_ASSERT(tag_ >= 0);
919 }
920
921 void changeLength(size_t newLength) {
922 tag_ = ptrdiff_t(newLength);
923 JS_ASSERT(tag_ >= 0);
924 }
925
926 void changeArray(Value *newArray, size_t newLength) {
927 changeLength(newLength);
928 array = newArray;
929 }
930
931 Value *start() {
932 return array;
933 }
934
935 size_t length() {
936 JS_ASSERT(tag_ >= 0);
937 return size_t(tag_);
938 }
939
940 MutableHandleValue handleAt(size_t i) {
941 JS_ASSERT(i < size_t(tag_));
942 return MutableHandleValue::fromMarkedLocation(&array[i]);
943 }
944 HandleValue handleAt(size_t i) const {
945 JS_ASSERT(i < size_t(tag_));
946 return HandleValue::fromMarkedLocation(&array[i]);
947 }
948 MutableHandleValue operator[](size_t i) {
949 JS_ASSERT(i < size_t(tag_));
950 return MutableHandleValue::fromMarkedLocation(&array[i]);
951 }
952 HandleValue operator[](size_t i) const {
953 JS_ASSERT(i < size_t(tag_));
954 return HandleValue::fromMarkedLocation(&array[i]);
955 }
956
957 friend void AutoGCRooter::trace(JSTracer *trc);
958
959 private:
960 Value *array;
961 MOZ_DECL_USE_GUARD_OBJECT_NOTIFIER
962 };
963
964 class AutoAssertNoException
965 {
966 #ifdef DEBUG
967 JSContext *cx;
968 bool hadException;
969 #endif
970
971 public:
972 AutoAssertNoException(JSContext *cx)
973 #ifdef DEBUG
974 : cx(cx),
975 hadException(cx->isExceptionPending())
976 #endif
977 {
978 }
979
980 ~AutoAssertNoException()
981 {
982 JS_ASSERT_IF(!hadException, !cx->isExceptionPending());
983 }
984 };
985
986 /*
987 * FIXME bug 647103 - replace these *AllocPolicy names.
988 */
989 class ContextAllocPolicy
990 {
991 ThreadSafeContext *const cx_;
992
993 public:
994 ContextAllocPolicy(ThreadSafeContext *cx) : cx_(cx) {}
995 ThreadSafeContext *context() const { return cx_; }
996 void *malloc_(size_t bytes) { return cx_->malloc_(bytes); }
997 void *calloc_(size_t bytes) { return cx_->calloc_(bytes); }
998 void *realloc_(void *p, size_t oldBytes, size_t bytes) { return cx_->realloc_(p, oldBytes, bytes); }
999 void free_(void *p) { js_free(p); }
1000 void reportAllocOverflow() const { js_ReportAllocationOverflow(cx_); }
1001 };
1002
1003 /* Exposed intrinsics so that Ion may inline them. */
1004 bool intrinsic_ToObject(JSContext *cx, unsigned argc, Value *vp);
1005 bool intrinsic_IsCallable(JSContext *cx, unsigned argc, Value *vp);
1006 bool intrinsic_ThrowError(JSContext *cx, unsigned argc, Value *vp);
1007 bool intrinsic_NewDenseArray(JSContext *cx, unsigned argc, Value *vp);
1008
1009 bool intrinsic_UnsafePutElements(JSContext *cx, unsigned argc, Value *vp);
1010 bool intrinsic_DefineValueProperty(JSContext *cx, unsigned argc, Value *vp);
1011 bool intrinsic_UnsafeSetReservedSlot(JSContext *cx, unsigned argc, Value *vp);
1012 bool intrinsic_UnsafeGetReservedSlot(JSContext *cx, unsigned argc, Value *vp);
1013 bool intrinsic_HaveSameClass(JSContext *cx, unsigned argc, Value *vp);
1014 bool intrinsic_IsPackedArray(JSContext *cx, unsigned argc, Value *vp);
1015
1016 bool intrinsic_ShouldForceSequential(JSContext *cx, unsigned argc, Value *vp);
1017 bool intrinsic_NewParallelArray(JSContext *cx, unsigned argc, Value *vp);
1018 bool intrinsic_ForkJoinGetSlice(JSContext *cx, unsigned argc, Value *vp);
1019 bool intrinsic_InParallelSection(JSContext *cx, unsigned argc, Value *vp);
1020
1021 bool intrinsic_ObjectIsTypedObject(JSContext *cx, unsigned argc, Value *vp);
1022 bool intrinsic_ObjectIsTransparentTypedObject(JSContext *cx, unsigned argc, Value *vp);
1023 bool intrinsic_ObjectIsOpaqueTypedObject(JSContext *cx, unsigned argc, Value *vp);
1024 bool intrinsic_ObjectIsTypeDescr(JSContext *cx, unsigned argc, Value *vp);
1025 bool intrinsic_TypeDescrIsSimpleType(JSContext *cx, unsigned argc, Value *vp);
1026 bool intrinsic_TypeDescrIsArrayType(JSContext *cx, unsigned argc, Value *vp);
1027 bool intrinsic_TypeDescrIsUnsizedArrayType(JSContext *cx, unsigned argc, Value *vp);
1028 bool intrinsic_TypeDescrIsSizedArrayType(JSContext *cx, unsigned argc, Value *vp);
1029
1030 class AutoLockForExclusiveAccess
1031 {
1032 #ifdef JS_THREADSAFE
1033 JSRuntime *runtime;
1034
1035 void init(JSRuntime *rt) {
1036 runtime = rt;
1037 if (runtime->numExclusiveThreads) {
1038 runtime->assertCanLock(ExclusiveAccessLock);
1039 PR_Lock(runtime->exclusiveAccessLock);
1040 #ifdef DEBUG
1041 runtime->exclusiveAccessOwner = PR_GetCurrentThread();
1042 #endif
1043 } else {
1044 JS_ASSERT(!runtime->mainThreadHasExclusiveAccess);
1045 runtime->mainThreadHasExclusiveAccess = true;
1046 }
1047 }
1048
1049 public:
1050 AutoLockForExclusiveAccess(ExclusiveContext *cx MOZ_GUARD_OBJECT_NOTIFIER_PARAM) {
1051 MOZ_GUARD_OBJECT_NOTIFIER_INIT;
1052 init(cx->runtime_);
1053 }
1054 AutoLockForExclusiveAccess(JSRuntime *rt MOZ_GUARD_OBJECT_NOTIFIER_PARAM) {
1055 MOZ_GUARD_OBJECT_NOTIFIER_INIT;
1056 init(rt);
1057 }
1058 ~AutoLockForExclusiveAccess() {
1059 if (runtime->numExclusiveThreads) {
1060 JS_ASSERT(runtime->exclusiveAccessOwner == PR_GetCurrentThread());
1061 runtime->exclusiveAccessOwner = nullptr;
1062 PR_Unlock(runtime->exclusiveAccessLock);
1063 } else {
1064 JS_ASSERT(runtime->mainThreadHasExclusiveAccess);
1065 runtime->mainThreadHasExclusiveAccess = false;
1066 }
1067 }
1068 #else // JS_THREADSAFE
1069 public:
1070 AutoLockForExclusiveAccess(ExclusiveContext *cx MOZ_GUARD_OBJECT_NOTIFIER_PARAM) {
1071 MOZ_GUARD_OBJECT_NOTIFIER_INIT;
1072 }
1073 AutoLockForExclusiveAccess(JSRuntime *rt MOZ_GUARD_OBJECT_NOTIFIER_PARAM) {
1074 MOZ_GUARD_OBJECT_NOTIFIER_INIT;
1075 }
1076 ~AutoLockForExclusiveAccess() {
1077 // An empty destructor is needed to avoid warnings from clang about
1078 // unused local variables of this type.
1079 }
1080 #endif // JS_THREADSAFE
1081
1082 MOZ_DECL_USE_GUARD_OBJECT_NOTIFIER
1083 };
1084
1085 void
1086 CrashAtUnhandlableOOM(const char *reason);
1087
1088 } /* namespace js */
1089
1090 #ifdef _MSC_VER
1091 #pragma warning(pop)
1092 #endif
1093
1094 #endif /* jscntxt_h */

mercurial