Browse Source

src: make IsolateData creation explicit

Make it easier to reason about the lifetime and the ownership of the
IsolateData instance by making its creation explicit and by removing
reference counting logic.

The creator of the Environment is now responsible for passing in the
IsolateData instance and for keeping it alive as long as the Environment
is alive.

PR-URL: https://github.com/nodejs/node/pull/7082
Reviewed-By: James M Snell <jasnell@gmail.com>
Reviewed-By: Trevor Norris <trev.norris@gmail.com>
v7.x
Ben Noordhuis 9 years ago
parent
commit
c3cd453cba
  1. 10
      src/debug-agent.cc
  2. 54
      src/env-inl.h
  3. 23
      src/env.h
  4. 69
      src/node.cc
  5. 20
      src/node.h

10
src/debug-agent.cc

@ -172,9 +172,15 @@ void Agent::WorkerRun() {
Local<Context> context = Context::New(isolate); Local<Context> context = Context::New(isolate);
Context::Scope context_scope(context); Context::Scope context_scope(context);
// FIXME(bnoordhuis) Work around V8 bug: v8::Private::ForApi() dereferences
// a nullptr when a context hasn't been entered first. The symbol registry
// is a lazily created JS object but object instantiation does not work
// without a context.
IsolateData isolate_data(isolate, &child_loop_);
Environment* env = CreateEnvironment( Environment* env = CreateEnvironment(
isolate, &isolate_data,
&child_loop_,
context, context,
arraysize(argv), arraysize(argv),
argv, argv,

54
src/env-inl.h

@ -15,28 +15,6 @@
namespace node { namespace node {
inline IsolateData* IsolateData::Get(v8::Isolate* isolate) {
return static_cast<IsolateData*>(isolate->GetData(kIsolateSlot));
}
inline IsolateData* IsolateData::GetOrCreate(v8::Isolate* isolate,
uv_loop_t* loop) {
IsolateData* isolate_data = Get(isolate);
if (isolate_data == nullptr) {
isolate_data = new IsolateData(isolate, loop);
isolate->SetData(kIsolateSlot, isolate_data);
}
isolate_data->ref_count_ += 1;
return isolate_data;
}
inline void IsolateData::Put() {
if (--ref_count_ == 0) {
isolate()->SetData(kIsolateSlot, nullptr);
delete this;
}
}
// Create string properties as internalized one byte strings. // Create string properties as internalized one byte strings.
// //
// Internalized because it makes property lookups a little faster and because // Internalized because it makes property lookups a little faster and because
@ -46,9 +24,8 @@ inline void IsolateData::Put() {
// //
// One byte because our strings are ASCII and we can safely skip V8's UTF-8 // One byte because our strings are ASCII and we can safely skip V8's UTF-8
// decoding step. It's a one-time cost, but why pay it when you don't have to? // decoding step. It's a one-time cost, but why pay it when you don't have to?
inline IsolateData::IsolateData(v8::Isolate* isolate, uv_loop_t* loop) inline IsolateData::IsolateData(v8::Isolate* isolate, uv_loop_t* event_loop)
: event_loop_(loop), :
isolate_(isolate),
#define V(PropertyName, StringValue) \ #define V(PropertyName, StringValue) \
PropertyName ## _( \ PropertyName ## _( \
isolate, \ isolate, \
@ -71,16 +48,12 @@ inline IsolateData::IsolateData(v8::Isolate* isolate, uv_loop_t* loop)
sizeof(StringValue) - 1).ToLocalChecked()), sizeof(StringValue) - 1).ToLocalChecked()),
PER_ISOLATE_STRING_PROPERTIES(V) PER_ISOLATE_STRING_PROPERTIES(V)
#undef V #undef V
ref_count_(0) {} isolate_(isolate), event_loop_(event_loop) {}
inline uv_loop_t* IsolateData::event_loop() const { inline uv_loop_t* IsolateData::event_loop() const {
return event_loop_; return event_loop_;
} }
inline v8::Isolate* IsolateData::isolate() const {
return isolate_;
}
inline Environment::AsyncHooks::AsyncHooks() { inline Environment::AsyncHooks::AsyncHooks() {
for (int i = 0; i < kFieldsCount; i++) fields_[i] = 0; for (int i = 0; i < kFieldsCount; i++) fields_[i] = 0;
} }
@ -176,9 +149,9 @@ inline void Environment::ArrayBufferAllocatorInfo::reset_fill_flag() {
fields_[kNoZeroFill] = 0; fields_[kNoZeroFill] = 0;
} }
inline Environment* Environment::New(v8::Local<v8::Context> context, inline Environment* Environment::New(IsolateData* isolate_data,
uv_loop_t* loop) { v8::Local<v8::Context> context) {
Environment* env = new Environment(context, loop); Environment* env = new Environment(isolate_data, context);
env->AssignToContext(context); env->AssignToContext(context);
return env; return env;
} }
@ -212,11 +185,11 @@ inline Environment* Environment::GetCurrent(
return static_cast<Environment*>(data.As<v8::External>()->Value()); return static_cast<Environment*>(data.As<v8::External>()->Value());
} }
inline Environment::Environment(v8::Local<v8::Context> context, inline Environment::Environment(IsolateData* isolate_data,
uv_loop_t* loop) v8::Local<v8::Context> context)
: isolate_(context->GetIsolate()), : isolate_(context->GetIsolate()),
isolate_data_(IsolateData::GetOrCreate(context->GetIsolate(), loop)), isolate_data_(isolate_data),
timer_base_(uv_now(loop)), timer_base_(uv_now(isolate_data->event_loop())),
using_domains_(false), using_domains_(false),
printed_error_(false), printed_error_(false),
trace_sync_io_(false), trace_sync_io_(false),
@ -253,7 +226,6 @@ inline Environment::~Environment() {
#define V(PropertyName, TypeName) PropertyName ## _.Reset(); #define V(PropertyName, TypeName) PropertyName ## _.Reset();
ENVIRONMENT_STRONG_PERSISTENT_PROPERTIES(V) ENVIRONMENT_STRONG_PERSISTENT_PROPERTIES(V)
#undef V #undef V
isolate_data()->Put();
delete[] heap_statistics_buffer_; delete[] heap_statistics_buffer_;
delete[] heap_space_statistics_buffer_; delete[] heap_space_statistics_buffer_;
@ -541,9 +513,9 @@ inline v8::Local<v8::Object> Environment::NewInternalFieldObject() {
#define VS(PropertyName, StringValue) V(v8::String, PropertyName, StringValue) #define VS(PropertyName, StringValue) V(v8::String, PropertyName, StringValue)
#define V(TypeName, PropertyName, StringValue) \ #define V(TypeName, PropertyName, StringValue) \
inline \ inline \
v8::Local<TypeName> IsolateData::PropertyName() const { \ v8::Local<TypeName> IsolateData::PropertyName(v8::Isolate* isolate) const { \
/* Strings are immutable so casting away const-ness here is okay. */ \ /* Strings are immutable so casting away const-ness here is okay. */ \
return const_cast<IsolateData*>(this)->PropertyName ## _.Get(isolate()); \ return const_cast<IsolateData*>(this)->PropertyName ## _.Get(isolate); \
} }
PER_ISOLATE_PRIVATE_SYMBOL_PROPERTIES(VP) PER_ISOLATE_PRIVATE_SYMBOL_PROPERTIES(VP)
PER_ISOLATE_STRING_PROPERTIES(VS) PER_ISOLATE_STRING_PROPERTIES(VS)
@ -555,7 +527,7 @@ inline v8::Local<v8::Object> Environment::NewInternalFieldObject() {
#define VS(PropertyName, StringValue) V(v8::String, PropertyName, StringValue) #define VS(PropertyName, StringValue) V(v8::String, PropertyName, StringValue)
#define V(TypeName, PropertyName, StringValue) \ #define V(TypeName, PropertyName, StringValue) \
inline v8::Local<TypeName> Environment::PropertyName() const { \ inline v8::Local<TypeName> Environment::PropertyName() const { \
return isolate_data()->PropertyName(); \ return isolate_data()->PropertyName(isolate()); \
} }
PER_ISOLATE_PRIVATE_SYMBOL_PROPERTIES(VP) PER_ISOLATE_PRIVATE_SYMBOL_PROPERTIES(VP)
PER_ISOLATE_STRING_PROPERTIES(VS) PER_ISOLATE_STRING_PROPERTIES(VS)

23
src/env.h

@ -304,14 +304,13 @@ RB_HEAD(ares_task_list, ares_task_t);
class IsolateData { class IsolateData {
public: public:
static inline IsolateData* GetOrCreate(v8::Isolate* isolate, uv_loop_t* loop); inline IsolateData(v8::Isolate* isolate, uv_loop_t* event_loop);
inline void Put();
inline uv_loop_t* event_loop() const; inline uv_loop_t* event_loop() const;
#define VP(PropertyName, StringValue) V(v8::Private, PropertyName, StringValue) #define VP(PropertyName, StringValue) V(v8::Private, PropertyName, StringValue)
#define VS(PropertyName, StringValue) V(v8::String, PropertyName, StringValue) #define VS(PropertyName, StringValue) V(v8::String, PropertyName, StringValue)
#define V(TypeName, PropertyName, StringValue) \ #define V(TypeName, PropertyName, StringValue) \
inline v8::Local<TypeName> PropertyName() const; inline v8::Local<TypeName> PropertyName(v8::Isolate* isolate) const;
PER_ISOLATE_PRIVATE_SYMBOL_PROPERTIES(VP) PER_ISOLATE_PRIVATE_SYMBOL_PROPERTIES(VP)
PER_ISOLATE_STRING_PROPERTIES(VS) PER_ISOLATE_STRING_PROPERTIES(VS)
#undef V #undef V
@ -319,15 +318,6 @@ class IsolateData {
#undef VP #undef VP
private: private:
static const int kIsolateSlot = NODE_ISOLATE_SLOT;
inline static IsolateData* Get(v8::Isolate* isolate);
inline explicit IsolateData(v8::Isolate* isolate, uv_loop_t* loop);
inline v8::Isolate* isolate() const;
uv_loop_t* const event_loop_;
v8::Isolate* const isolate_;
#define VP(PropertyName, StringValue) V(v8::Private, PropertyName, StringValue) #define VP(PropertyName, StringValue) V(v8::Private, PropertyName, StringValue)
#define VS(PropertyName, StringValue) V(v8::String, PropertyName, StringValue) #define VS(PropertyName, StringValue) V(v8::String, PropertyName, StringValue)
#define V(TypeName, PropertyName, StringValue) \ #define V(TypeName, PropertyName, StringValue) \
@ -338,7 +328,8 @@ class IsolateData {
#undef VS #undef VS
#undef VP #undef VP
unsigned int ref_count_; v8::Isolate* const isolate_;
uv_loop_t* const event_loop_;
DISALLOW_COPY_AND_ASSIGN(IsolateData); DISALLOW_COPY_AND_ASSIGN(IsolateData);
}; };
@ -474,8 +465,8 @@ class Environment {
const v8::PropertyCallbackInfo<T>& info); const v8::PropertyCallbackInfo<T>& info);
// See CreateEnvironment() in src/node.cc. // See CreateEnvironment() in src/node.cc.
static inline Environment* New(v8::Local<v8::Context> context, static inline Environment* New(IsolateData* isolate_data,
uv_loop_t* loop); v8::Local<v8::Context> context);
inline void CleanupHandles(); inline void CleanupHandles();
inline void Dispose(); inline void Dispose();
@ -609,7 +600,7 @@ class Environment {
static const int kContextEmbedderDataIndex = NODE_CONTEXT_EMBEDDER_DATA_INDEX; static const int kContextEmbedderDataIndex = NODE_CONTEXT_EMBEDDER_DATA_INDEX;
private: private:
inline Environment(v8::Local<v8::Context> context, uv_loop_t* loop); inline Environment(IsolateData* isolate_data, v8::Local<v8::Context> context);
inline ~Environment(); inline ~Environment();
inline IsolateData* isolate_data() const; inline IsolateData* isolate_data() const;

69
src/node.cc

@ -4264,42 +4264,6 @@ int EmitExit(Environment* env) {
} }
// Just a convenience method
Environment* CreateEnvironment(Isolate* isolate,
Local<Context> context,
int argc,
const char* const* argv,
int exec_argc,
const char* const* exec_argv) {
Environment* env;
Context::Scope context_scope(context);
env = CreateEnvironment(isolate,
uv_default_loop(),
context,
argc,
argv,
exec_argc,
exec_argv);
LoadEnvironment(env);
return env;
}
static Environment* CreateEnvironment(Isolate* isolate,
Local<Context> context,
NodeInstanceData* instance_data) {
return CreateEnvironment(isolate,
instance_data->event_loop(),
context,
instance_data->argc(),
instance_data->argv(),
instance_data->exec_argc(),
instance_data->exec_argv());
}
static void HandleCloseCb(uv_handle_t* handle) { static void HandleCloseCb(uv_handle_t* handle) {
Environment* env = reinterpret_cast<Environment*>(handle->data); Environment* env = reinterpret_cast<Environment*>(handle->data);
env->FinishHandleCleanup(handle); env->FinishHandleCleanup(handle);
@ -4314,17 +4278,27 @@ static void HandleCleanup(Environment* env,
} }
Environment* CreateEnvironment(Isolate* isolate, IsolateData* CreateIsolateData(Isolate* isolate, uv_loop_t* loop) {
uv_loop_t* loop, return new IsolateData(isolate, loop);
}
void FreeIsolateData(IsolateData* isolate_data) {
delete isolate_data;
}
Environment* CreateEnvironment(IsolateData* isolate_data,
Local<Context> context, Local<Context> context,
int argc, int argc,
const char* const* argv, const char* const* argv,
int exec_argc, int exec_argc,
const char* const* exec_argv) { const char* const* exec_argv) {
Isolate* isolate = context->GetIsolate();
HandleScope handle_scope(isolate); HandleScope handle_scope(isolate);
Context::Scope context_scope(context); Context::Scope context_scope(context);
Environment* env = Environment::New(context, loop); Environment* env = Environment::New(isolate_data, context);
isolate->SetAutorunMicrotasks(false); isolate->SetAutorunMicrotasks(false);
@ -4412,10 +4386,23 @@ static void StartNodeInstance(void* arg) {
Isolate::Scope isolate_scope(isolate); Isolate::Scope isolate_scope(isolate);
HandleScope handle_scope(isolate); HandleScope handle_scope(isolate);
Local<Context> context = Context::New(isolate); Local<Context> context = Context::New(isolate);
Environment* env = CreateEnvironment(isolate, context, instance_data);
array_buffer_allocator->set_env(env);
Context::Scope context_scope(context); Context::Scope context_scope(context);
// FIXME(bnoordhuis) Work around V8 bug: v8::Private::ForApi() dereferences
// a nullptr when a context hasn't been entered first. The symbol registry
// is a lazily created JS object but object instantiation does not work
// without a context.
IsolateData isolate_data(isolate, instance_data->event_loop());
Environment* env = CreateEnvironment(&isolate_data,
context,
instance_data->argc(),
instance_data->argv(),
instance_data->exec_argc(),
instance_data->exec_argv());
array_buffer_allocator->set_env(env);
isolate->SetAbortOnUncaughtExceptionCallback( isolate->SetAbortOnUncaughtExceptionCallback(
ShouldAbortOnUncaughtException); ShouldAbortOnUncaughtException);

20
src/node.h

@ -190,28 +190,22 @@ NODE_EXTERN void Init(int* argc,
int* exec_argc, int* exec_argc,
const char*** exec_argv); const char*** exec_argv);
class IsolateData;
class Environment; class Environment;
NODE_EXTERN Environment* CreateEnvironment(v8::Isolate* isolate, NODE_EXTERN IsolateData* CreateIsolateData(v8::Isolate* isolate,
struct uv_loop_s* loop, struct uv_loop_s* loop);
v8::Local<v8::Context> context, NODE_EXTERN void FreeIsolateData(IsolateData* isolate_data);
int argc,
const char* const* argv,
int exec_argc,
const char* const* exec_argv);
NODE_EXTERN void LoadEnvironment(Environment* env);
NODE_EXTERN void FreeEnvironment(Environment* env);
// NOTE: Calling this is the same as calling NODE_EXTERN Environment* CreateEnvironment(IsolateData* isolate_data,
// CreateEnvironment() + LoadEnvironment() from above.
// `uv_default_loop()` will be passed as `loop`.
NODE_EXTERN Environment* CreateEnvironment(v8::Isolate* isolate,
v8::Local<v8::Context> context, v8::Local<v8::Context> context,
int argc, int argc,
const char* const* argv, const char* const* argv,
int exec_argc, int exec_argc,
const char* const* exec_argv); const char* const* exec_argv);
NODE_EXTERN void LoadEnvironment(Environment* env);
NODE_EXTERN void FreeEnvironment(Environment* env);
NODE_EXTERN void EmitBeforeExit(Environment* env); NODE_EXTERN void EmitBeforeExit(Environment* env);
NODE_EXTERN int EmitExit(Environment* env); NODE_EXTERN int EmitExit(Environment* env);

Loading…
Cancel
Save