#include "InterpreterV8.h" #ifdef HAVE_V8 #include #include #include #include #ifdef HAVE_NOVA #include #include #include #endif #ifdef HAVE_SQL #include "Database.h" #endif #include #include "dim.h" #include "tools.h" #include "Readline.h" #include "externals/izstream.h" #include "WindowLog.h" using namespace std; using namespace v8; v8::Handle InterpreterV8::fTemplateLocal; v8::Handle InterpreterV8::fTemplateSky; v8::Handle InterpreterV8::fTemplateEvent; v8::Handle InterpreterV8::fTemplateDescription; //v8::Handle InterpreterV8::fTemplateDatabase; // ========================================================================== // Some documentation // ========================================================================== // // Threads: // -------- // In most cases Js* and other calls to native C++ code could be wrapped // with an Unlocker to allow possible other JavaScipt 'threads' to run // during that time. However, all of these calls should take much less than // the preemption time of 10ms, so it would just be a waste of tim. // // Termination: // ------------ // Each thread running V8 code needs to be signalled individually for // termination. Therefor a list of V8 thread ids is created. // // If termination has already be signalled, no thread should start running // anymore (thy could, e.g., wait for their locking). So after locking // it has to be checked if the thread was terminated already. Note // that all calls to Terminate() must be locked to ensure that fThreadId // is correct when it is checked. // // The current thread id must be added to fThreadIds _before_ any // function is called after Locking and before execution is given // back to JavaScript, e.g. in script->Run(). So until the thread // is added to the list Terminate will not be executed. If Terminate // is then executed, it is ensured that the current thread is // already in the list. If terminate has been called before // the Locking, the check for the validiy of fThreadId ensures that // nothing is executed. // // Empty handles: // -------------- // If exceution is terminated, V8 calls might return with empty handles, // e.g. Date::New(). Therefore, the returned handles of these calls have to // be checked in all placed to avoid that V8 will core dump. // // HandleScope: // ------------ // A handle scope is a garbage collector and collects all handles created // until it goes out of scope. Handles which are not needed anymore are // then deleted. To return a handle from a HandleScope you need to use // Close(). E.g., String::AsciiValue does not create a new handle and // hence does not need a HandleScope. Any ::New will need a handle scope. // Forgetting the HandleScope could in principle fill your memory, // but everything is properly deleted by the global HandleScope at // script termination. // // ========================================================================== // Simple interface // ========================================================================== Handle InterpreterV8::FuncExit(const Arguments &) { V8::TerminateExecution(fThreadId); // we have to throw an excption to make sure that the // calling thread does not go on executing until it // has realized that it should terminate return ThrowException(Null()); } Handle InterpreterV8::FuncSleep(const Arguments& args) { if (args.Length()==0) { // Theoretically, the CPU usage can be reduced by maybe a factor // of four using a larger value, but this also means that the // JavaScript is locked for a longer time. const Unlocker unlock; usleep(1000); return Undefined(); } if (args.Length()!=1) return ThrowException(String::New("Number of arguments must be exactly 1.")); if (!args[0]->IsUint32()) return ThrowException(String::New("Argument 1 must be an uint32.")); // Using a Javascript function has the advantage that it is fully // interruptable without the need of C++ code const string code = "(function(){" "var t=new Date();" "while ((new Date()-t)<"+to_string(args[0]->Int32Value())+") v8.sleep();" "})();"; return ExecuteInternal(code); } Handle InterpreterV8::FuncTimeout(const Arguments &args) { if (args.Length()<2) return ThrowException(String::New("Number of arguments must be at least two.")); if (!args[0]->IsNull() && !args[0]->IsInt32()) return ThrowException(String::New("Argument 0 not null and not an int32.")); if (!args[1]->IsFunction()) return ThrowException(String::New("Argument 1 not a function.")); const int32_t timeout = args[0]->IsNull() ? 0 : args[0]->Int32Value(); const bool null = args[0]->IsNull(); HandleScope handle_scope; TryCatch exception; const Handle