Skip to content

Commit 2fae0db

Browse files
committed
Implemented Initialize(), Run() and Evaluate()
1 parent 6ed7163 commit 2fae0db

2 files changed

Lines changed: 266 additions & 22 deletions

File tree

src/node.cc

Lines changed: 250 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -91,6 +91,9 @@
9191

9292
#include <string>
9393
#include <vector>
94+
#include <iostream>
95+
#include <cstring>
96+
#include <sstream>
9497

9598
#if defined(NODE_HAVE_I18N_SUPPORT)
9699
#include <unicode/uvernum.h>
@@ -4798,7 +4801,7 @@ Local<Context> NewContext(Isolate* isolate,
47984801

47994802
inline static bool TickEventLoop(Environment & env) {
48004803
bool more;
4801-
uv_run(env.event_loop(), UV_RUN_DEFAULT);
4804+
uv_run(env.event_loop(), UV_RUN_ONCE);
48024805

48034806
v8_platform.DrainVMTasks();
48044807

@@ -4988,25 +4991,258 @@ int Start(int argc, char** argv) {
49884991
}
49894992

49904993
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+
}
49915066

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+
}
49965116
}
4997-
}
49985117

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);
49995136

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);
50045156
}
5005-
}
50065157

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+
}
50105246

50115247
} // namespace node::lib
50125248

src/node_lib.h

Lines changed: 16 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,15 @@
66
#include <initializer_list>
77
#include "v8.h"
88

9-
namespace node{ namespace lib {
9+
namespace node { namespace lib {
10+
void _StartEnv(int argc,
11+
const char* const* argv,
12+
int exec_argc,
13+
const char* const* exec_argv);
14+
15+
int _StopEnv();
16+
17+
1018
/*********************************************************
1119
* Function types
1220
*********************************************************/
@@ -28,7 +36,7 @@ namespace node{ namespace lib {
2836
Starts the Node.js engine without a concrete script file to execute.
2937
*Important*: This requires the C++ developer to call `ProcessEvents()` periodically OR call `Run()` to start the uv event loop.
3038
*/
31-
bool Initialize();
39+
NODE_EXTERN void Initialize(int argc, char **argv);
3240

3341
/*
3442
Starts the Node.js engine with a given JavaScript file. Additionally, the Node.js engine will be kept alive
@@ -38,11 +46,11 @@ namespace node{ namespace lib {
3846
//bool StartMainLoop(const std::string & path, const RunUserLoop & callback);
3947

4048
/*
41-
Executes a given JavaScript file and returns once the execution has finished.
49+
Executes a given JavaScript file and returns once the execution has finished.
4250
*Important*: Node.js has to have been initialized by calling Initialize().
4351
*/
4452

45-
bool Run(const std::string & path);
53+
v8::Local<v8::Value> Run(const std::string & path);
4654

4755
/*********************************************************
4856
* Handle JavaScript events
@@ -83,12 +91,12 @@ namespace node{ namespace lib {
8391
/*
8492
Executes a given piece of JavaScript code, using the *running* Node.js engine.
8593
*/
86-
bool Evaluate(const std::string & java_script_code);
94+
v8::Local<v8::Value> Evaluate(const std::string & java_script_code);
8795

8896
/*
8997
Returns the JavaScript root object for the running application
9098
*/
91-
v8::MaybeLocal<v8::Object> GetRootObject();
99+
v8::Local<v8::Object> GetRootObject();
92100

93101
/*
94102
Registers a C++ module in the *running* Node.js engine.
@@ -109,7 +117,7 @@ namespace node{ namespace lib {
109117
/*
110118
Adds a new JavaScript module to the *running* Node.js engine.
111119
*/
112-
v8::MaybeLocal<v8::Object> IncludeModule(const std::string & modul_name);
120+
v8::Local<v8::Object> IncludeModule(const std::string & modul_name);
113121

114122
/*
115123
Returns the local value (specified by its name) of the module (defined in the `exports`-object).
@@ -120,7 +128,7 @@ namespace node{ namespace lib {
120128
Calls a function (specified by its name) on a given object passing the given arguments.
121129
*Important*: Throws an exception if the receiver does not define the specified function.
122130
*/
123-
v8::Local<v8::Value> Call(v8::MaybeLocal<v8::Object> object, const std::string & function_name, const std::vector<v8::MaybeLocal<v8::Value>> & args = {});
131+
v8::Local<v8::Value> Call(v8::Local<v8::Object> object, const std::string & function_name, const std::vector<v8::Local<v8::Value>> & args = {});
124132

125133
/*
126134
Calls a function (specified by its name) on a given object passing the given arguments.

0 commit comments

Comments
 (0)