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 #ifndef jsshell_js_h
8 #define jsshell_js_h
9 
10 #include "mozilla/Atomics.h"
11 #include "mozilla/Maybe.h"
12 #include "mozilla/TimeStamp.h"
13 #include "mozilla/Variant.h"
14 
15 #include "jsapi.h"
16 
17 #include "js/GCVector.h"
18 #include "threading/ConditionVariable.h"
19 #include "threading/LockGuard.h"
20 #include "threading/Mutex.h"
21 #include "threading/Thread.h"
22 #include "vm/GeckoProfiler.h"
23 #include "vm/Monitor.h"
24 
25 // Some platform hooks must be implemented for single-step profiling.
26 #if defined(JS_SIMULATOR_ARM) || defined(JS_SIMULATOR_MIPS64)
27 #define SINGLESTEP_PROFILING
28 #endif
29 
30 namespace js {
31 namespace shell {
32 
33 enum JSShellErrNum {
34 #define MSG_DEF(name, count, exception, format) name,
35 #include "jsshell.msg"
36 #undef MSG_DEF
37   JSShellErr_Limit
38 };
39 
40 const JSErrorFormatString* my_GetErrorMessage(void* userRef,
41                                               const unsigned errorNumber);
42 
43 void WarningReporter(JSContext* cx, JSErrorReport* report);
44 
45 class MOZ_STACK_CLASS AutoReportException {
46   JSContext* cx;
47 
48  public:
AutoReportException(JSContext * cx)49   explicit AutoReportException(JSContext* cx) : cx(cx) {}
50   ~AutoReportException();
51 };
52 
53 bool GenerateInterfaceHelp(JSContext* cx, JS::HandleObject obj,
54                            const char* name);
55 
56 JSString* FileAsString(JSContext* cx, JS::HandleString pathnameStr);
57 
58 class AutoCloseFile {
59  private:
60   FILE* f_;
61 
62  public:
AutoCloseFile(FILE * f)63   explicit AutoCloseFile(FILE* f) : f_(f) {}
~AutoCloseFile()64   ~AutoCloseFile() { (void)release(); }
release()65   bool release() {
66     bool success = true;
67     if (f_ && f_ != stdin && f_ != stdout && f_ != stderr)
68       success = !fclose(f_);
69     f_ = nullptr;
70     return success;
71   }
72 };
73 
74 // Reference counted file.
75 struct RCFile {
76   FILE* fp;
77   uint32_t numRefs;
78 
RCFileRCFile79   RCFile() : fp(nullptr), numRefs(0) {}
RCFileRCFile80   explicit RCFile(FILE* fp) : fp(fp), numRefs(0) {}
81 
acquireRCFile82   void acquire() { numRefs++; }
83 
84   // Starts out with a ref count of zero.
85   static RCFile* create(JSContext* cx, const char* filename, const char* mode);
86 
87   void close();
isOpenRCFile88   bool isOpen() const { return fp; }
89   bool release();
90 };
91 
92 // Alias the global dstName to namespaceObj.srcName. For example, if dstName is
93 // "snarf", namespaceObj represents "os.file", and srcName is "readFile", then
94 // this is equivalent to the JS code:
95 //
96 //   snarf = os.file.readFile;
97 //
98 // This provides a mechanism for namespacing the various JS shell helper
99 // functions without breaking backwards compatibility with things that use the
100 // global names.
101 bool CreateAlias(JSContext* cx, const char* dstName,
102                  JS::HandleObject namespaceObj, const char* srcName);
103 
104 enum class ScriptKind { Script, DecodeScript, Module };
105 
106 class NonshrinkingGCObjectVector
107     : public GCVector<JSObject*, 0, SystemAllocPolicy> {
108  public:
sweep()109   void sweep() {
110     for (uint32_t i = 0; i < this->length(); i++) {
111       if (JS::GCPolicy<JSObject*>::needsSweep(&(*this)[i]))
112         (*this)[i] = nullptr;
113     }
114   }
115 };
116 
117 using MarkBitObservers = JS::WeakCache<NonshrinkingGCObjectVector>;
118 
119 #ifdef SINGLESTEP_PROFILING
120 using StackChars = Vector<char16_t, 0, SystemAllocPolicy>;
121 #endif
122 
123 class OffThreadJob;
124 
125 // Per-context shell state.
126 struct ShellContext {
127   explicit ShellContext(JSContext* cx);
128   ~ShellContext();
129 
130   bool isWorker;
131   double timeoutInterval;
132   double startTime;
133   mozilla::Atomic<bool> serviceInterrupt;
134   mozilla::Atomic<bool> haveInterruptFunc;
135   JS::PersistentRootedValue interruptFunc;
136   bool lastWarningEnabled;
137   JS::PersistentRootedValue lastWarning;
138   JS::PersistentRootedValue promiseRejectionTrackerCallback;
139 #ifdef SINGLESTEP_PROFILING
140   Vector<StackChars, 0, SystemAllocPolicy> stacks;
141 #endif
142 
143   /*
144    * Watchdog thread state.
145    */
146   js::Mutex watchdogLock;
147   js::ConditionVariable watchdogWakeup;
148   mozilla::Maybe<js::Thread> watchdogThread;
149   mozilla::Maybe<mozilla::TimeStamp> watchdogTimeout;
150 
151   js::ConditionVariable sleepWakeup;
152 
153   int exitCode;
154   bool quitting;
155 
156   JS::UniqueChars readLineBuf;
157   size_t readLineBufPos;
158 
159   js::shell::RCFile** errFilePtr;
160   js::shell::RCFile** outFilePtr;
161 
162   UniquePtr<PseudoStack> geckoProfilingStack;
163 
164   JS::UniqueChars moduleLoadPath;
165   UniquePtr<MarkBitObservers> markObservers;
166 
167   // Off-thread parse state.
168   js::Monitor offThreadMonitor;
169   Vector<OffThreadJob*, 0, SystemAllocPolicy> offThreadJobs;
170 };
171 
172 extern ShellContext* GetShellContext(JSContext* cx);
173 
174 } /* namespace shell */
175 } /* namespace js */
176 
177 #endif
178