|
91 | 91 |
|
92 | 92 | #include <string> |
93 | 93 | #include <vector> |
| 94 | +#include <iostream> |
| 95 | +#include <cstring> |
| 96 | +#include <sstream> |
94 | 97 |
|
95 | 98 | #if defined(NODE_HAVE_I18N_SUPPORT) |
96 | 99 | #include <unicode/uvernum.h> |
@@ -4798,7 +4801,7 @@ Local<Context> NewContext(Isolate* isolate, |
4798 | 4801 |
|
4799 | 4802 | inline static bool TickEventLoop(Environment & env) { |
4800 | 4803 | bool more; |
4801 | | - uv_run(env.event_loop(), UV_RUN_DEFAULT); |
| 4804 | + uv_run(env.event_loop(), UV_RUN_ONCE); |
4802 | 4805 |
|
4803 | 4806 | v8_platform.DrainVMTasks(); |
4804 | 4807 |
|
@@ -4988,25 +4991,258 @@ int Start(int argc, char** argv) { |
4988 | 4991 | } |
4989 | 4992 |
|
4990 | 4993 | namespace lib { |
| 4994 | + ArrayBufferAllocator *allocator; |
| 4995 | + Isolate::CreateParams params; |
| 4996 | + Locker *locker; |
| 4997 | + Isolate *isolate; |
| 4998 | + IsolateData *isolate_data; |
| 4999 | + Isolate::Scope *isolate_scope; |
| 5000 | + Environment *env; |
| 5001 | + Local<Context> context; |
| 5002 | + Context::Scope *context_scope; |
| 5003 | + Environment::AsyncCallbackScope *callback_scope; |
| 5004 | + |
| 5005 | + void Initialize(int argc, char **argv) { |
| 5006 | + ////////// |
| 5007 | + // Start 1 |
| 5008 | + ////////// |
| 5009 | + atexit([] () { uv_tty_reset_mode(); }); |
| 5010 | + PlatformInit(); |
| 5011 | + node::performance::performance_node_start = PERFORMANCE_NOW(); |
| 5012 | + |
| 5013 | + // Hack around with the argv pointer. Used for process.title = "blah". |
| 5014 | + argv = uv_setup_args(argc, argv); |
| 5015 | + |
| 5016 | + // This needs to run *before* V8::Initialize(). The const_cast is not |
| 5017 | + // optional, in case you're wondering. |
| 5018 | + int exec_argc; |
| 5019 | + const char** exec_argv; |
| 5020 | + Init(&argc, const_cast<const char**>(argv), &exec_argc, &exec_argv); |
| 5021 | + |
| 5022 | + #if HAVE_OPENSSL |
| 5023 | + { |
| 5024 | + std::string extra_ca_certs; |
| 5025 | + if (SafeGetenv("NODE_EXTRA_CA_CERTS", &extra_ca_certs)) |
| 5026 | + crypto::UseExtraCaCerts(extra_ca_certs); |
| 5027 | + } |
| 5028 | + #ifdef NODE_FIPS_MODE |
| 5029 | + // In the case of FIPS builds we should make sure |
| 5030 | + // the random source is properly initialized first. |
| 5031 | + OPENSSL_init(); |
| 5032 | + #endif // NODE_FIPS_MODE |
| 5033 | + // V8 on Windows doesn't have a good source of entropy. Seed it from |
| 5034 | + // OpenSSL's pool. |
| 5035 | + V8::SetEntropySource(crypto::EntropySource); |
| 5036 | + #endif // HAVE_OPENSSL |
| 5037 | + |
| 5038 | + |
| 5039 | + v8_platform.Initialize(v8_thread_pool_size, uv_default_loop()); |
| 5040 | + // Enable tracing when argv has --trace-events-enabled. |
| 5041 | + if (trace_enabled) { |
| 5042 | + fprintf(stderr, "Warning: Trace event is an experimental feature " |
| 5043 | + "and could change at any time.\n"); |
| 5044 | + v8_platform.StartTracingAgent(); |
| 5045 | + } |
| 5046 | + V8::Initialize(); |
| 5047 | + node::performance::performance_v8_start = PERFORMANCE_NOW(); |
| 5048 | + v8_initialized = true; |
| 5049 | + |
| 5050 | + |
| 5051 | + ////////// |
| 5052 | + // Start 2 |
| 5053 | + ////////// |
| 5054 | + |
| 5055 | + allocator = new ArrayBufferAllocator(); |
| 5056 | + params.array_buffer_allocator = allocator; |
| 5057 | + #ifdef NODE_ENABLE_VTUNE_PROFILING |
| 5058 | + params.code_event_handler = vTune::GetVtuneCodeEventHandler(); |
| 5059 | + #endif |
| 5060 | + |
| 5061 | + isolate = Isolate::New(params); |
| 5062 | + if (isolate == nullptr) { |
| 5063 | + return; // TODO: Handle error |
| 5064 | + //return 12; // Signal internal error. |
| 5065 | + } |
4991 | 5066 |
|
4992 | | -void RunEventLoop(const RunUserLoop & callback){ |
4993 | | - while (false/*events in queue*/) { // TODO: condition |
4994 | | - ProcessEvents(); |
4995 | | - callback(); |
| 5067 | + isolate->AddMessageListener(OnMessage); |
| 5068 | + isolate->SetAbortOnUncaughtExceptionCallback(ShouldAbortOnUncaughtException); |
| 5069 | + isolate->SetAutorunMicrotasks(false); |
| 5070 | + isolate->SetFatalErrorHandler(OnFatalError); |
| 5071 | + |
| 5072 | + if (track_heap_objects) { |
| 5073 | + isolate->GetHeapProfiler()->StartTrackingHeapObjects(true); |
| 5074 | + } |
| 5075 | + |
| 5076 | + |
| 5077 | + |
| 5078 | + { |
| 5079 | + Mutex::ScopedLock scoped_lock(node_isolate_mutex); |
| 5080 | + CHECK_EQ(node_isolate, nullptr); |
| 5081 | + node_isolate = isolate; |
| 5082 | + } |
| 5083 | + |
| 5084 | + int exit_code; |
| 5085 | + { |
| 5086 | + locker = new Locker(isolate); |
| 5087 | + isolate_scope = new Isolate::Scope(isolate); |
| 5088 | + static HandleScope handle_scope(isolate); |
| 5089 | + isolate_data = new IsolateData(isolate, uv_default_loop(), allocator->zero_fill_field()); |
| 5090 | + |
| 5091 | + ////////// |
| 5092 | + // Start 3 |
| 5093 | + ////////// |
| 5094 | + //HandleScope handle_scope(isolate); |
| 5095 | + context = NewContext(isolate); |
| 5096 | + context_scope = new Context::Scope(context); |
| 5097 | + env = new Environment(isolate_data, context); |
| 5098 | + CHECK_EQ(0, uv_key_create(&thread_local_env)); |
| 5099 | + uv_key_set(&thread_local_env, env); |
| 5100 | + |
| 5101 | + ////////// |
| 5102 | + // Start environment |
| 5103 | + ////////// |
| 5104 | + std::string scriptName = "./build-unix/node-embed"; // TODO?! |
| 5105 | + int length = scriptName.length() + 1; |
| 5106 | + |
| 5107 | + char *buf = new char[length]; |
| 5108 | + std::strcpy(buf, scriptName.c_str()); |
| 5109 | + |
| 5110 | + int argc = 1; |
| 5111 | + char *argv[] = {buf}; |
| 5112 | + int exec_argc = 0; |
| 5113 | + const char* const* exec_argv = nullptr; |
| 5114 | + _StartEnv(argc, (const char* const*)argv, exec_argc, exec_argv); |
| 5115 | + } |
4996 | 5116 | } |
4997 | | -} |
4998 | 5117 |
|
| 5118 | + void _StartEnv(int argc, |
| 5119 | + const char* const* argv, |
| 5120 | + int exec_argc, |
| 5121 | + const char* const* exec_argv) { |
| 5122 | + std::cout << "Starting environment" << std::endl; |
| 5123 | + /*std::cout << "argv" << std::endl; |
| 5124 | + for (int i = 0; i < argc; i++) { |
| 5125 | + std::cout << argv[i] << std::endl; |
| 5126 | + } |
| 5127 | + std::cout << "exec_argv" << std::endl; |
| 5128 | + for (int i = 0; i < exec_argc; i++) { |
| 5129 | + std::cout << exec_argv[i] << std::endl; |
| 5130 | + }*/ |
| 5131 | + |
| 5132 | + env->Start(argc, argv, exec_argc, exec_argv, v8_is_profiling); |
| 5133 | + |
| 5134 | + const char* path = argc > 1 ? argv[1] : nullptr; |
| 5135 | + StartInspector(env, path, debug_options); |
4999 | 5136 |
|
5000 | | -void Terminate() { |
5001 | | - RequestTerminate(); |
5002 | | - while (false/*events in queue*/) { // TODO: condition |
5003 | | - ProcessEvents(); |
| 5137 | + if (debug_options.inspector_enabled() && !v8_platform.InspectorStarted(env)) { |
| 5138 | + return; // TODO: Handle error |
| 5139 | + //return 12; // Signal internal error. |
| 5140 | + } |
| 5141 | + |
| 5142 | + env->set_abort_on_uncaught_exception(abort_on_uncaught_exception); |
| 5143 | + |
| 5144 | + if (no_force_async_hooks_checks) { |
| 5145 | + env->async_hooks()->no_force_checks(); |
| 5146 | + } |
| 5147 | + |
| 5148 | + { |
| 5149 | + callback_scope = new Environment::AsyncCallbackScope(env); |
| 5150 | + env->async_hooks()->push_async_ids(1, 0); |
| 5151 | + LoadEnvironment(env); |
| 5152 | + env->async_hooks()->pop_async_id(1); |
| 5153 | + } |
| 5154 | + |
| 5155 | + env->set_trace_sync_io(trace_sync_io); |
5004 | 5156 | } |
5005 | | -} |
5006 | 5157 |
|
5007 | | -void RequestTerminate() { |
5008 | | -// Evaluate("process.exit()"); // TODO: why does the linker complain here? |
5009 | | -} |
| 5158 | + v8::Local<v8::Value> Run(const std::string & path) { |
| 5159 | + // Read entire file into string. There is most certainly a better way ;) |
| 5160 | + // https://stackoverflow.com/a/2602258/2560557 |
| 5161 | + std::ifstream t(path); |
| 5162 | + std::stringstream buffer; |
| 5163 | + buffer << t.rdbuf(); |
| 5164 | + |
| 5165 | + return Evaluate(buffer.str().c_str()); |
| 5166 | + } |
| 5167 | + |
| 5168 | + v8::Local<v8::Value> Evaluate(const std::string & java_script_code) { |
| 5169 | + EscapableHandleScope scope(env->isolate()); |
| 5170 | + TryCatch try_catch(env->isolate()); |
| 5171 | + |
| 5172 | + // try_catch must be nonverbose to disable FatalException() handler, |
| 5173 | + // we will handle exceptions ourself. |
| 5174 | + try_catch.SetVerbose(false); |
| 5175 | + |
| 5176 | + //ScriptOrigin origin(filename); |
| 5177 | + MaybeLocal<v8::Script> script = v8::Script::Compile(env->context(), v8::String::NewFromUtf8(isolate, java_script_code.c_str())/*, origin*/); |
| 5178 | + if (script.IsEmpty()) { |
| 5179 | + ReportException(env, try_catch); |
| 5180 | + exit(3); |
| 5181 | + } |
| 5182 | + |
| 5183 | + Local<Value> result = script.ToLocalChecked()->Run(); |
| 5184 | + if (result.IsEmpty()) { |
| 5185 | + ReportException(env, try_catch); |
| 5186 | + exit(4); |
| 5187 | + } |
| 5188 | + |
| 5189 | + return scope.Escape(result); |
| 5190 | + } |
| 5191 | + |
| 5192 | + void RunEventLoop(const RunUserLoop & callback){ |
| 5193 | + bool more; |
| 5194 | + do { |
| 5195 | + more = ProcessEvents(); |
| 5196 | + callback(); |
| 5197 | + } while (more); |
| 5198 | + } |
| 5199 | + |
| 5200 | + // TODO: Might not be working. |
| 5201 | + v8::Local<v8::Object> GetRootObject() { |
| 5202 | + return context->Global(); |
| 5203 | + } |
| 5204 | + |
| 5205 | + // TODO: Node.js has exceptions disabled. |
| 5206 | + // TODO: Doesn't work yet. |
| 5207 | + v8::Local<v8::Value> Call(v8::Local<v8::Object> object, const std::string & function_name, const std::vector<v8::Local<v8::Value>> & args) { |
| 5208 | + Local<v8::String> func = v8::String::NewFromUtf8(isolate, function_name.c_str()); |
| 5209 | + |
| 5210 | + Local<v8::Value> value = object->Get(func); |
| 5211 | + if (!value->IsFunction()) { |
| 5212 | + //throw new Exception(":(("); |
| 5213 | + } |
| 5214 | + Local<v8::Function> _func = v8::Local<v8::Function>::Cast(value); |
| 5215 | + |
| 5216 | + _func->Call(object, 1, const_cast<v8::Local<v8::Value>*>(&args[0])); |
| 5217 | + } |
| 5218 | + |
| 5219 | + // TODO: Node.js has exceptions disabled. |
| 5220 | + // TODO: Doesn't work yet. |
| 5221 | + v8::Local<v8::Object> IncludeModule(const std::string & module_name) { |
| 5222 | + std::vector<v8::Local<v8::Value>> args; |
| 5223 | + args.push_back(v8::String::NewFromUtf8(isolate, module_name.c_str())); |
| 5224 | + |
| 5225 | + auto module = Call(GetRootObject(), "require", args); |
| 5226 | + if (!module->IsObject()) { |
| 5227 | + //throw new Exception(":(("); |
| 5228 | + } |
| 5229 | + |
| 5230 | + return v8::Local<v8::Object>::Cast(module); |
| 5231 | + } |
| 5232 | + |
| 5233 | + |
| 5234 | + void Terminate() { |
| 5235 | + RequestTerminate(); |
| 5236 | + while (ProcessEvents()) { } |
| 5237 | + } |
| 5238 | + |
| 5239 | + void RequestTerminate() { |
| 5240 | + Evaluate("process.exit()"); |
| 5241 | + } |
| 5242 | + |
| 5243 | + bool ProcessEvents() { |
| 5244 | + return TickEventLoop(*env); |
| 5245 | + } |
5010 | 5246 |
|
5011 | 5247 | } // namespace node::lib |
5012 | 5248 |
|
|
0 commit comments