/** * Copyright (C) 2015 MongoDB Inc. * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU Affero General Public License, version 3, * as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Affero General Public License for more details. * * You should have received a copy of the GNU Affero General Public License * along with this program. If not, see . * * As a special exception, the copyright holders give permission to link the * code of portions of this program with the OpenSSL library under certain * conditions as described in each individual source file and distribute * linked combinations including the program with the OpenSSL library. You * must comply with the GNU Affero General Public License in all respects * for all of the code used other than as permitted herein. If you modify * file(s) with this exception, you may extend this exception to your * version of the file(s), but you are not obligated to do so. If you do not * wish to do so, delete this exception statement from your version. If you * delete this exception statement from all source files in the program, * then also delete it in the license file. */ #pragma once #include #include #include "mongo/client/dbclientcursor.h" #include "mongo/scripting/mozjs/bindata.h" #include "mongo/scripting/mozjs/bson.h" #include "mongo/scripting/mozjs/countdownlatch.h" #include "mongo/scripting/mozjs/cursor.h" #include "mongo/scripting/mozjs/cursor_handle.h" #include "mongo/scripting/mozjs/db.h" #include "mongo/scripting/mozjs/dbcollection.h" #include "mongo/scripting/mozjs/dbpointer.h" #include "mongo/scripting/mozjs/dbquery.h" #include "mongo/scripting/mozjs/dbref.h" #include "mongo/scripting/mozjs/engine.h" #include "mongo/scripting/mozjs/error.h" #include "mongo/scripting/mozjs/global.h" #include "mongo/scripting/mozjs/internedstring.h" #include "mongo/scripting/mozjs/jsthread.h" #include "mongo/scripting/mozjs/maxkey.h" #include "mongo/scripting/mozjs/minkey.h" #include "mongo/scripting/mozjs/mongo.h" #include "mongo/scripting/mozjs/mongohelpers.h" #include "mongo/scripting/mozjs/nativefunction.h" #include "mongo/scripting/mozjs/numberint.h" #include "mongo/scripting/mozjs/numberlong.h" #include "mongo/scripting/mozjs/numberdecimal.h" #include "mongo/scripting/mozjs/object.h" #include "mongo/scripting/mozjs/oid.h" #include "mongo/scripting/mozjs/regexp.h" #include "mongo/scripting/mozjs/timestamp.h" namespace mongo { namespace mozjs { /** * Implementation Scope for MozJS * * The Implementation scope holds the actual mozjs runtime and context objects, * along with a number of global prototypes for mongoDB specific types. Each * ImplScope requires it's own thread and cannot be accessed from any thread * other than the one it was created on (this is a detail inherited from the * JSRuntime). If you need a scope that can be accessed by different threads * over the course of it's lifetime, see MozJSProxyScope * * For more information about overriden fields, see mongo::Scope */ class MozJSImplScope final : public Scope { MONGO_DISALLOW_COPYING(MozJSImplScope); public: static const std::size_t kMaxStackBytes = (1024 * 1024); explicit MozJSImplScope(MozJSScriptEngine* engine); ~MozJSImplScope(); void init(const BSONObj* data) override; void reset() override; void kill(); bool isKillPending() const override; OperationContext* getOpContext() const; void registerOperation(OperationContext* txn) override; void unregisterOperation() override; void localConnectForDbEval(OperationContext* txn, const char* dbName) override; void externalSetup() override; std::string getError() override; bool hasOutOfMemoryException() override; void gc() override; double getNumber(const char* field) override; int getNumberInt(const char* field) override; long long getNumberLongLong(const char* field) override; Decimal128 getNumberDecimal(const char* field) override; std::string getString(const char* field) override; bool getBoolean(const char* field) override; BSONObj getObject(const char* field) override; void setNumber(const char* field, double val) override; void setString(const char* field, StringData val) override; void setBoolean(const char* field, bool val) override; void setElement(const char* field, const BSONElement& e, const BSONObj& parent) override; void setObject(const char* field, const BSONObj& obj, bool readOnly) override; void setFunction(const char* field, const char* code) override; int type(const char* field) override; void rename(const char* from, const char* to) override; int invoke(ScriptingFunction func, const BSONObj* args, const BSONObj* recv, int timeoutMs = 0, bool ignoreReturn = false, bool readOnlyArgs = false, bool readOnlyRecv = false) override; bool exec(StringData code, const std::string& name, bool printResult, bool reportError, bool assertOnError, int timeoutMs) override; void injectNative(const char* field, NativeFunction func, void* data = 0) override; ScriptingFunction _createFunction(const char* code, ScriptingFunction functionNumber = 0) override; void newFunction(StringData code, JS::MutableHandleValue out); BSONObj callThreadArgs(const BSONObj& obj); template typename std::enable_if::value, WrapType&>::type getProto() { return _binDataProto; } template typename std::enable_if::value, WrapType&>::type getProto() { return _bsonProto; } template typename std::enable_if::value, WrapType&>::type getProto() { return _countDownLatchProto; } template typename std::enable_if::value, WrapType&>::type getProto() { return _cursorProto; } template typename std::enable_if::value, WrapType&>::type getProto() { return _cursorHandleProto; } template typename std::enable_if::value, WrapType&>::type getProto() { return _dbCollectionProto; } template typename std::enable_if::value, WrapType&>::type getProto() { return _dbPointerProto; } template typename std::enable_if::value, WrapType&>::type getProto() { return _dbQueryProto; } template typename std::enable_if::value, WrapType&>::type getProto() { return _dbProto; } template typename std::enable_if::value, WrapType&>::type getProto() { return _dbRefProto; } template typename std::enable_if::value, WrapType&>::type getProto() { return _errorProto; } template typename std::enable_if::value, WrapType&>::type getProto() { return _jsThreadProto; } template typename std::enable_if::value, WrapType&>::type getProto() { return _maxKeyProto; } template typename std::enable_if::value, WrapType&>::type getProto() { return _minKeyProto; } template typename std::enable_if::value, WrapType&>::type getProto() { return _mongoExternalProto; } template typename std::enable_if::value, WrapType&>::type getProto() { return _mongoHelpersProto; } template typename std::enable_if::value, WrapType&>::type getProto() { return _mongoLocalProto; } template typename std::enable_if::value, WrapType&>::type getProto() { return _nativeFunctionProto; } template typename std::enable_if::value, WrapType&>::type getProto() { return _numberIntProto; } template typename std::enable_if::value, WrapType&>::type getProto() { return _numberLongProto; } template typename std::enable_if::value, WrapType&>::type getProto() { return _numberDecimalProto; } template typename std::enable_if::value, WrapType&>::type getProto() { return _objectProto; } template typename std::enable_if::value, WrapType&>::type getProto() { return _oidProto; } template typename std::enable_if::value, WrapType&>::type getProto() { return _regExpProto; } template typename std::enable_if::value, WrapType&>::type getProto() { return _timestampProto; } void setQuickExit(int exitCode); bool getQuickExit(int* exitCode); static const char* const kExecResult; static const char* const kInvokeResult; static MozJSImplScope* getThreadScope(); void setOOM(); void setParentStack(std::string); const std::string& getParentStack() const; std::size_t getGeneration() const; void advanceGeneration() override; JS::HandleId getInternedStringId(InternedString name) { return _internedStrings.getInternedString(name); } private: void _MozJSCreateFunction(const char* raw, ScriptingFunction functionNumber, JS::MutableHandleValue fun); /** * This structure exists exclusively to construct the runtime and context * ahead of the various global prototypes in the ImplScope construction. * Basically, we have to call some c apis on the way up and down and this * takes care of that */ struct MozRuntime { public: MozRuntime(); ~MozRuntime(); PRThread* _thread = nullptr; JSRuntime* _runtime = nullptr; JSContext* _context = nullptr; }; /** * The connection state of the scope. * * This is for dbeval and the shell */ enum class ConnectState : char { Not, Local, External, }; struct MozJSEntry; friend struct MozJSEntry; static void _reportError(JSContext* cx, const char* message, JSErrorReport* report); static bool _interruptCallback(JSContext* cx); static void _gcCallback(JSRuntime* rt, JSGCStatus status, void* data); bool _checkErrorState(bool success, bool reportError = true, bool assertOnError = true); void installDBAccess(); void installBSONTypes(); void installFork(); void setCompileOptions(JS::CompileOptions* co); MozJSScriptEngine* _engine; MozRuntime _mr; JSRuntime* _runtime; JSContext* _context; WrapType _globalProto; JS::HandleObject _global; std::vector _funcs; InternedStringTable _internedStrings; std::atomic _pendingKill; std::string _error; unsigned int _opId; // op id for this scope OperationContext* _opCtx; // Op context for DbEval std::atomic _pendingGC; ConnectState _connectState; Status _status; int _exitCode; bool _quickExit; std::string _parentStack; std::size_t _generation; WrapType _binDataProto; WrapType _bsonProto; WrapType _countDownLatchProto; WrapType _cursorProto; WrapType _cursorHandleProto; WrapType _dbCollectionProto; WrapType _dbPointerProto; WrapType _dbQueryProto; WrapType _dbProto; WrapType _dbRefProto; WrapType _errorProto; WrapType _jsThreadProto; WrapType _maxKeyProto; WrapType _minKeyProto; WrapType _mongoExternalProto; WrapType _mongoHelpersProto; WrapType _mongoLocalProto; WrapType _nativeFunctionProto; WrapType _numberIntProto; WrapType _numberLongProto; WrapType _numberDecimalProto; WrapType _objectProto; WrapType _oidProto; WrapType _regExpProto; WrapType _timestampProto; }; inline MozJSImplScope* getScope(JSContext* cx) { return static_cast(JS_GetContextPrivate(cx)); } } // namespace mozjs } // namespace mongo