Skip to content

Commit b2682b5

Browse files
joyeecheungantsmartian
authored andcommitted
src: move public C++ APIs into src/api/*.cc
This patch moves most of the public C++ APIs into src/api/*.cc so that it's easier to tell that we need to be careful about the compatibility of these code. Some APIs, like `node::LoadEnvironmet()`, `node::Start()` and `node::Init()` still stay in `node.cc` because they are still very specific to our use cases and do not work quite well yet for embedders anyway - we could not even manage to write cctest for them at the moment. PR-URL: nodejs#25541 Reviewed-By: Gus Caplan <me@gus.host>
1 parent d24da95 commit b2682b5

11 files changed

+557
-528
lines changed

node.gyp

+7-3
Original file line numberDiff line numberDiff line change
@@ -355,14 +355,19 @@
355355
'dependencies': [ 'deps/histogram/histogram.gyp:histogram' ],
356356

357357
'sources': [
358+
'src/api/callback.cc',
359+
'src/api/encoding.cc',
360+
'src/api/environment.cc',
361+
'src/api/exceptions.cc',
362+
'src/api/hooks.cc',
363+
'src/api/utils.cc',
364+
358365
'src/async_wrap.cc',
359-
'src/callback_scope.cc',
360366
'src/cares_wrap.cc',
361367
'src/connect_wrap.cc',
362368
'src/connection_wrap.cc',
363369
'src/debug_utils.cc',
364370
'src/env.cc',
365-
'src/exceptions.cc',
366371
'src/fs_event_wrap.cc',
367372
'src/handle_wrap.cc',
368373
'src/heap_utils.cc',
@@ -382,7 +387,6 @@
382387
'src/node_contextify.cc',
383388
'src/node_credentials.cc',
384389
'src/node_domain.cc',
385-
'src/node_encoding.cc',
386390
'src/node_env_var.cc',
387391
'src/node_errors.cc',
388392
'src/node_file.cc',
File renamed without changes.
File renamed without changes.

src/api/environment.cc

+214
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,214 @@
1+
#include "env.h"
2+
#include "node.h"
3+
#include "node_context_data.h"
4+
#include "node_errors.h"
5+
#include "node_internals.h"
6+
#include "node_native_module.h"
7+
#include "node_platform.h"
8+
#include "node_process.h"
9+
#include "node_v8_platform-inl.h"
10+
#include "uv.h"
11+
12+
namespace node {
13+
using v8::Context;
14+
using v8::Function;
15+
using v8::HandleScope;
16+
using v8::Isolate;
17+
using v8::Local;
18+
using v8::MaybeLocal;
19+
using v8::Message;
20+
using v8::MicrotasksPolicy;
21+
using v8::ObjectTemplate;
22+
using v8::String;
23+
using v8::Value;
24+
25+
static bool AllowWasmCodeGenerationCallback(Local<Context> context,
26+
Local<String>) {
27+
Local<Value> wasm_code_gen =
28+
context->GetEmbedderData(ContextEmbedderIndex::kAllowWasmCodeGeneration);
29+
return wasm_code_gen->IsUndefined() || wasm_code_gen->IsTrue();
30+
}
31+
32+
static bool ShouldAbortOnUncaughtException(Isolate* isolate) {
33+
HandleScope scope(isolate);
34+
Environment* env = Environment::GetCurrent(isolate);
35+
return env != nullptr && env->should_abort_on_uncaught_toggle()[0] &&
36+
!env->inside_should_not_abort_on_uncaught_scope();
37+
}
38+
39+
static void OnMessage(Local<Message> message, Local<Value> error) {
40+
Isolate* isolate = message->GetIsolate();
41+
switch (message->ErrorLevel()) {
42+
case Isolate::MessageErrorLevel::kMessageWarning: {
43+
Environment* env = Environment::GetCurrent(isolate);
44+
if (!env) {
45+
break;
46+
}
47+
Utf8Value filename(isolate, message->GetScriptOrigin().ResourceName());
48+
// (filename):(line) (message)
49+
std::stringstream warning;
50+
warning << *filename;
51+
warning << ":";
52+
warning << message->GetLineNumber(env->context()).FromMaybe(-1);
53+
warning << " ";
54+
v8::String::Utf8Value msg(isolate, message->Get());
55+
warning << *msg;
56+
USE(ProcessEmitWarningGeneric(env, warning.str().c_str(), "V8"));
57+
break;
58+
}
59+
case Isolate::MessageErrorLevel::kMessageError:
60+
FatalException(isolate, error, message);
61+
break;
62+
}
63+
}
64+
65+
void* ArrayBufferAllocator::Allocate(size_t size) {
66+
if (zero_fill_field_ || per_process::cli_options->zero_fill_all_buffers)
67+
return UncheckedCalloc(size);
68+
else
69+
return UncheckedMalloc(size);
70+
}
71+
72+
ArrayBufferAllocator* CreateArrayBufferAllocator() {
73+
return new ArrayBufferAllocator();
74+
}
75+
76+
void FreeArrayBufferAllocator(ArrayBufferAllocator* allocator) {
77+
delete allocator;
78+
}
79+
80+
Isolate* NewIsolate(ArrayBufferAllocator* allocator, uv_loop_t* event_loop) {
81+
Isolate::CreateParams params;
82+
params.array_buffer_allocator = allocator;
83+
#ifdef NODE_ENABLE_VTUNE_PROFILING
84+
params.code_event_handler = vTune::GetVtuneCodeEventHandler();
85+
#endif
86+
87+
Isolate* isolate = Isolate::Allocate();
88+
if (isolate == nullptr) return nullptr;
89+
90+
// Register the isolate on the platform before the isolate gets initialized,
91+
// so that the isolate can access the platform during initialization.
92+
per_process::v8_platform.Platform()->RegisterIsolate(isolate, event_loop);
93+
Isolate::Initialize(isolate, params);
94+
95+
isolate->AddMessageListenerWithErrorLevel(
96+
OnMessage,
97+
Isolate::MessageErrorLevel::kMessageError |
98+
Isolate::MessageErrorLevel::kMessageWarning);
99+
isolate->SetAbortOnUncaughtExceptionCallback(ShouldAbortOnUncaughtException);
100+
isolate->SetMicrotasksPolicy(MicrotasksPolicy::kExplicit);
101+
isolate->SetFatalErrorHandler(OnFatalError);
102+
isolate->SetAllowWasmCodeGenerationCallback(AllowWasmCodeGenerationCallback);
103+
v8::CpuProfiler::UseDetailedSourcePositionsForProfiling(isolate);
104+
105+
return isolate;
106+
}
107+
108+
IsolateData* CreateIsolateData(Isolate* isolate,
109+
uv_loop_t* loop,
110+
MultiIsolatePlatform* platform,
111+
ArrayBufferAllocator* allocator) {
112+
return new IsolateData(
113+
isolate,
114+
loop,
115+
platform,
116+
allocator != nullptr ? allocator->zero_fill_field() : nullptr);
117+
}
118+
119+
void FreeIsolateData(IsolateData* isolate_data) {
120+
delete isolate_data;
121+
}
122+
123+
Environment* CreateEnvironment(IsolateData* isolate_data,
124+
Local<Context> context,
125+
int argc,
126+
const char* const* argv,
127+
int exec_argc,
128+
const char* const* exec_argv) {
129+
Isolate* isolate = context->GetIsolate();
130+
HandleScope handle_scope(isolate);
131+
Context::Scope context_scope(context);
132+
// TODO(addaleax): This is a much better place for parsing per-Environment
133+
// options than the global parse call.
134+
std::vector<std::string> args(argv, argv + argc);
135+
std::vector<std::string> exec_args(exec_argv, exec_argv + exec_argc);
136+
Environment* env = new Environment(isolate_data, context);
137+
env->Start(per_process::v8_is_profiling);
138+
env->ProcessCliArgs(args, exec_args);
139+
return env;
140+
}
141+
142+
void FreeEnvironment(Environment* env) {
143+
env->RunCleanup();
144+
delete env;
145+
}
146+
147+
Environment* GetCurrentEnvironment(Local<Context> context) {
148+
return Environment::GetCurrent(context);
149+
}
150+
151+
MultiIsolatePlatform* GetMainThreadMultiIsolatePlatform() {
152+
return per_process::v8_platform.Platform();
153+
}
154+
155+
MultiIsolatePlatform* CreatePlatform(
156+
int thread_pool_size,
157+
node::tracing::TracingController* tracing_controller) {
158+
return new NodePlatform(thread_pool_size, tracing_controller);
159+
}
160+
161+
MultiIsolatePlatform* InitializeV8Platform(int thread_pool_size) {
162+
per_process::v8_platform.Initialize(thread_pool_size);
163+
return per_process::v8_platform.Platform();
164+
}
165+
166+
void FreePlatform(MultiIsolatePlatform* platform) {
167+
delete platform;
168+
}
169+
170+
Local<Context> NewContext(Isolate* isolate,
171+
Local<ObjectTemplate> object_template) {
172+
auto context = Context::New(isolate, nullptr, object_template);
173+
if (context.IsEmpty()) return context;
174+
HandleScope handle_scope(isolate);
175+
176+
context->SetEmbedderData(ContextEmbedderIndex::kAllowWasmCodeGeneration,
177+
True(isolate));
178+
179+
{
180+
// Run lib/internal/per_context.js
181+
Context::Scope context_scope(context);
182+
183+
std::vector<Local<String>> parameters = {
184+
FIXED_ONE_BYTE_STRING(isolate, "global")};
185+
Local<Value> arguments[] = {context->Global()};
186+
MaybeLocal<Function> maybe_fn =
187+
per_process::native_module_loader.LookupAndCompile(
188+
context, "internal/per_context", &parameters, nullptr);
189+
if (maybe_fn.IsEmpty()) {
190+
return Local<Context>();
191+
}
192+
Local<Function> fn = maybe_fn.ToLocalChecked();
193+
MaybeLocal<Value> result =
194+
fn->Call(context, Undefined(isolate), arraysize(arguments), arguments);
195+
// Execution failed during context creation.
196+
// TODO(joyeecheung): deprecate this signature and return a MaybeLocal.
197+
if (result.IsEmpty()) {
198+
return Local<Context>();
199+
}
200+
}
201+
202+
return context;
203+
}
204+
205+
uv_loop_t* GetCurrentEventLoop(Isolate* isolate) {
206+
HandleScope handle_scope(isolate);
207+
Local<Context> context = isolate->GetCurrentContext();
208+
if (context.IsEmpty()) return nullptr;
209+
Environment* env = Environment::GetCurrent(context);
210+
if (env == nullptr) return nullptr;
211+
return env->event_loop();
212+
}
213+
214+
} // namespace node

src/exceptions.cc src/api/exceptions.cc

+14
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@
1212
namespace node {
1313

1414
using v8::Exception;
15+
using v8::HandleScope;
1516
using v8::Integer;
1617
using v8::Isolate;
1718
using v8::Local;
@@ -228,4 +229,17 @@ Local<Value> WinapiErrnoException(Isolate* isolate,
228229
}
229230
#endif
230231

232+
void FatalException(Isolate* isolate, const v8::TryCatch& try_catch) {
233+
// If we try to print out a termination exception, we'd just get 'null',
234+
// so just crashing here with that information seems like a better idea,
235+
// and in particular it seems like we should handle terminations at the call
236+
// site for this function rather than by printing them out somewhere.
237+
CHECK(!try_catch.HasTerminated());
238+
239+
HandleScope scope(isolate);
240+
if (!try_catch.IsVerbose()) {
241+
FatalException(isolate, try_catch.Exception(), try_catch.Message());
242+
}
243+
}
244+
231245
} // namespace node

0 commit comments

Comments
 (0)