#ifndef jsshell_js_h
#define jsshell_js_h
#include "mozilla/Atomics.h"
#include "mozilla/Maybe.h"
#include "mozilla/TimeStamp.h"
#include "mozilla/Variant.h"
#include "jsapi.h"
#include "builtin/MapObject.h"
#include "js/GCVector.h"
#include "threading/ConditionVariable.h"
#include "threading/LockGuard.h"
#include "threading/Mutex.h"
#include "threading/Thread.h"
#include "vm/GeckoProfiler.h"
#include "vm/Monitor.h"
#if defined(JS_SIMULATOR_ARM) || defined(JS_SIMULATOR_MIPS64) || \
defined(JS_SIMULATOR_MIPS32)
# define SINGLESTEP_PROFILING
#endif
namespace js {
namespace shell {
enum JSShellErrNum {
#define MSG_DEF(name, count, exception, format) name,
#include "jsshell.msg"
#undef MSG_DEF
JSShellErr_Limit
};
const JSErrorFormatString* my_GetErrorMessage(void* userRef,
const unsigned errorNumber);
void WarningReporter(JSContext* cx, JSErrorReport* report);
class MOZ_STACK_CLASS AutoReportException {
JSContext* cx;
public:
explicit AutoReportException(JSContext* cx) : cx(cx) {}
~AutoReportException();
};
bool GenerateInterfaceHelp(JSContext* cx, JS::HandleObject obj,
const char* name);
JSString* FileAsString(JSContext* cx, JS::HandleString pathnameStr);
class AutoCloseFile {
private:
FILE* f_;
public:
explicit AutoCloseFile(FILE* f) : f_(f) {}
~AutoCloseFile() { (void)release(); }
bool release() {
bool success = true;
if (f_ && f_ != stdin && f_ != stdout && f_ != stderr) {
success = !fclose(f_);
}
f_ = nullptr;
return success;
}
};
struct RCFile {
FILE* fp;
uint32_t numRefs;
RCFile() : fp(nullptr), numRefs(0) {}
explicit RCFile(FILE* fp) : fp(fp), numRefs(0) {}
void acquire() { numRefs++; }
static RCFile* create(JSContext* cx, const char* filename, const char* mode);
void close();
bool isOpen() const { return fp; }
bool release();
};
bool CreateAlias(JSContext* cx, const char* dstName,
JS::HandleObject namespaceObj, const char* srcName);
enum class ScriptKind { Script, DecodeScript, Module };
class NonshrinkingGCObjectVector
: public GCVector<JSObject*, 0, SystemAllocPolicy> {
public:
void sweep() {
for (uint32_t i = 0; i < this->length(); i++) {
if (JS::GCPolicy<JSObject*>::needsSweep(&(*this)[i])) {
(*this)[i] = nullptr;
}
}
}
};
using MarkBitObservers = JS::WeakCache<NonshrinkingGCObjectVector>;
#ifdef SINGLESTEP_PROFILING
using StackChars = Vector<char16_t, 0, SystemAllocPolicy>;
#endif
class OffThreadJob;
struct ShellContext {
explicit ShellContext(JSContext* cx);
~ShellContext();
bool isWorker;
bool lastWarningEnabled;
bool trackUnhandledRejections;
double timeoutInterval;
double startTime;
mozilla::Atomic<bool> serviceInterrupt;
mozilla::Atomic<bool> haveInterruptFunc;
JS::PersistentRootedValue interruptFunc;
JS::PersistentRootedValue lastWarning;
JS::PersistentRootedValue promiseRejectionTrackerCallback;
JS::PersistentRooted<SetObject*> unhandledRejectedPromises;
#ifdef SINGLESTEP_PROFILING
Vector<StackChars, 0, SystemAllocPolicy> stacks;
#endif
js::Mutex watchdogLock;
js::ConditionVariable watchdogWakeup;
mozilla::Maybe<js::Thread> watchdogThread;
mozilla::Maybe<mozilla::TimeStamp> watchdogTimeout;
js::ConditionVariable sleepWakeup;
int exitCode;
bool quitting;
JS::UniqueChars readLineBuf;
size_t readLineBufPos;
js::shell::RCFile** errFilePtr;
js::shell::RCFile** outFilePtr;
UniquePtr<ProfilingStack> geckoProfilingStack;
JS::UniqueChars moduleLoadPath;
UniquePtr<MarkBitObservers> markObservers;
js::Monitor offThreadMonitor;
Vector<OffThreadJob*, 0, SystemAllocPolicy> offThreadJobs;
};
extern ShellContext* GetShellContext(JSContext* cx);
}
}
#endif