summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorJoyee Cheung <joyeec9h3@gmail.com>2019-02-08 19:56:08 +0800
committerJoyee Cheung <joyeec9h3@gmail.com>2019-02-18 17:37:33 +0800
commit2ae45d3b17f9c51fccffc4041e195e04b4b18c15 (patch)
treea2ce198ab594bc50ba510dcd3be8037ab0dc6eb3 /src
parent584dc4893c8c5be0a3c39c0179809e60b774cb95 (diff)
downloadandroid-node-v8-2ae45d3b17f9c51fccffc4041e195e04b4b18c15.tar.gz
android-node-v8-2ae45d3b17f9c51fccffc4041e195e04b4b18c15.tar.bz2
android-node-v8-2ae45d3b17f9c51fccffc4041e195e04b4b18c15.zip
process: start coverage collection before bootstrap
This patch moves the dispatch of `Profiler.takePreciseCoverage` to a point before the bootstrap scripts are run to ensure that we can collect coverage data for all the scripts run after the inspector agent is ready. Before this patch `lib/internal/bootstrap/primordials.js` was not covered by `make coverage`, after this patch it is. PR-URL: https://github.com/nodejs/node/pull/26006 Reviewed-By: Anna Henningsen <anna@addaleax.net> Reviewed-By: Ben Coe <bencoe@gmail.com> Reviewed-By: James M Snell <jasnell@gmail.com>
Diffstat (limited to 'src')
-rw-r--r--src/env.h9
-rw-r--r--src/inspector/node_inspector.gypi1
-rw-r--r--src/inspector_coverage.cc168
-rw-r--r--src/node.cc13
-rw-r--r--src/node_binding.cc9
-rw-r--r--src/node_internals.h4
6 files changed, 199 insertions, 5 deletions
diff --git a/src/env.h b/src/env.h
index 5cf2ee2c8b..b892eac26b 100644
--- a/src/env.h
+++ b/src/env.h
@@ -331,6 +331,7 @@ constexpr size_t kFsStatsBufferLength = kFsStatsFieldsNumber * 2;
V(async_wrap_ctor_template, v8::FunctionTemplate) \
V(async_wrap_object_ctor_template, v8::FunctionTemplate) \
V(buffer_prototype_object, v8::Object) \
+ V(coverage_connection, v8::Object) \
V(context, v8::Context) \
V(crypto_key_object_constructor, v8::Function) \
V(domain_callback, v8::Function) \
@@ -366,6 +367,7 @@ constexpr size_t kFsStatsBufferLength = kFsStatsFieldsNumber * 2;
V(message_event_object_template, v8::ObjectTemplate) \
V(message_port_constructor_template, v8::FunctionTemplate) \
V(native_module_require, v8::Function) \
+ V(on_coverage_message_function, v8::Function) \
V(performance_entry_callback, v8::Function) \
V(performance_entry_template, v8::Function) \
V(pipe_constructor_template, v8::FunctionTemplate) \
@@ -450,9 +452,10 @@ struct ContextInfo {
// Listing the AsyncWrap provider types first enables us to cast directly
// from a provider type to a debug category.
-#define DEBUG_CATEGORY_NAMES(V) \
- NODE_ASYNC_PROVIDER_TYPES(V) \
- V(INSPECTOR_SERVER)
+#define DEBUG_CATEGORY_NAMES(V) \
+ NODE_ASYNC_PROVIDER_TYPES(V) \
+ V(INSPECTOR_SERVER) \
+ V(COVERAGE)
enum class DebugCategory {
#define V(name) name,
diff --git a/src/inspector/node_inspector.gypi b/src/inspector/node_inspector.gypi
index 21f98cd900..9483a0712e 100644
--- a/src/inspector/node_inspector.gypi
+++ b/src/inspector/node_inspector.gypi
@@ -45,6 +45,7 @@
'../../src/inspector_io.cc',
'../../src/inspector_agent.h',
'../../src/inspector_io.h',
+ '../../src/inspector_coverage.cc',
'../../src/inspector_js_api.cc',
'../../src/inspector_socket.cc',
'../../src/inspector_socket.h',
diff --git a/src/inspector_coverage.cc b/src/inspector_coverage.cc
new file mode 100644
index 0000000000..8cbec586fb
--- /dev/null
+++ b/src/inspector_coverage.cc
@@ -0,0 +1,168 @@
+#include "base_object-inl.h"
+#include "debug_utils.h"
+#include "inspector_agent.h"
+#include "node_internals.h"
+#include "v8-inspector.h"
+
+namespace node {
+namespace coverage {
+
+using v8::Context;
+using v8::Function;
+using v8::FunctionCallbackInfo;
+using v8::HandleScope;
+using v8::Isolate;
+using v8::Local;
+using v8::MaybeLocal;
+using v8::NewStringType;
+using v8::Object;
+using v8::ObjectTemplate;
+using v8::String;
+using v8::Value;
+
+using v8_inspector::StringBuffer;
+using v8_inspector::StringView;
+
+std::unique_ptr<StringBuffer> ToProtocolString(Isolate* isolate,
+ Local<Value> value) {
+ TwoByteValue buffer(isolate, value);
+ return StringBuffer::create(StringView(*buffer, buffer.length()));
+}
+
+class V8CoverageConnection : public BaseObject {
+ public:
+ class V8CoverageSessionDelegate : public inspector::InspectorSessionDelegate {
+ public:
+ explicit V8CoverageSessionDelegate(V8CoverageConnection* connection)
+ : connection_(connection) {}
+
+ void SendMessageToFrontend(
+ const v8_inspector::StringView& message) override {
+ Environment* env = connection_->env();
+ Local<Function> fn = connection_->env()->on_coverage_message_function();
+ bool ending = !fn.IsEmpty();
+ Debug(env,
+ DebugCategory::COVERAGE,
+ "Sending message to frontend, ending = %s\n",
+ ending ? "true" : "false");
+ if (!ending) {
+ return;
+ }
+ Isolate* isolate = env->isolate();
+
+ HandleScope handle_scope(isolate);
+ Context::Scope context_scope(env->context());
+ MaybeLocal<String> v8string =
+ String::NewFromTwoByte(isolate,
+ message.characters16(),
+ NewStringType::kNormal,
+ message.length());
+ Local<Value> args[] = {v8string.ToLocalChecked().As<Value>()};
+ USE(MakeCallback(isolate,
+ connection_->object(),
+ fn,
+ arraysize(args),
+ args,
+ async_context{0, 0}));
+ }
+
+ private:
+ V8CoverageConnection* connection_;
+ };
+
+ SET_MEMORY_INFO_NAME(V8CoverageConnection)
+ SET_SELF_SIZE(V8CoverageConnection)
+
+ void MemoryInfo(MemoryTracker* tracker) const override {
+ tracker->TrackFieldWithSize(
+ "session", sizeof(*session_), "InspectorSession");
+ }
+
+ explicit V8CoverageConnection(Environment* env)
+ : BaseObject(env, env->coverage_connection()), session_(nullptr) {
+ inspector::Agent* inspector = env->inspector_agent();
+ std::unique_ptr<inspector::InspectorSession> session = inspector->Connect(
+ std::make_unique<V8CoverageSessionDelegate>(this), false);
+ session_ = std::move(session);
+ MakeWeak();
+ }
+
+ void Start() {
+ Debug(this->env(),
+ DebugCategory::COVERAGE,
+ "Sending Profiler.startPreciseCoverage\n");
+ Isolate* isolate = this->env()->isolate();
+ Local<Value> enable = FIXED_ONE_BYTE_STRING(
+ isolate, "{\"id\": 1, \"method\": \"Profiler.enable\"}");
+ Local<Value> start = FIXED_ONE_BYTE_STRING(
+ isolate,
+ "{"
+ "\"id\": 2,"
+ "\"method\": \"Profiler.startPreciseCoverage\","
+ "\"params\": {\"callCount\": true, \"detailed\": true}"
+ "}");
+ session_->Dispatch(ToProtocolString(isolate, enable)->string());
+ session_->Dispatch(ToProtocolString(isolate, start)->string());
+ }
+
+ void End() {
+ Debug(this->env(),
+ DebugCategory::COVERAGE,
+ "Sending Profiler.takePreciseCoverage\n");
+ Isolate* isolate = this->env()->isolate();
+ Local<Value> end =
+ FIXED_ONE_BYTE_STRING(isolate,
+ "{"
+ "\"id\": 3,"
+ "\"method\": \"Profiler.takePreciseCoverage\""
+ "}");
+ session_->Dispatch(ToProtocolString(isolate, end)->string());
+ }
+
+ friend class V8CoverageSessionDelegate;
+
+ private:
+ std::unique_ptr<inspector::InspectorSession> session_;
+};
+
+bool StartCoverageCollection(Environment* env) {
+ HandleScope scope(env->isolate());
+
+ Local<ObjectTemplate> t = ObjectTemplate::New(env->isolate());
+ t->SetInternalFieldCount(1);
+ Local<Object> obj;
+ if (!t->NewInstance(env->context()).ToLocal(&obj)) {
+ return false;
+ }
+
+ obj->SetAlignedPointerInInternalField(0, nullptr);
+
+ CHECK(env->coverage_connection().IsEmpty());
+ env->set_coverage_connection(obj);
+ V8CoverageConnection* connection = new V8CoverageConnection(env);
+ connection->Start();
+ return true;
+}
+
+static void EndCoverageCollection(const FunctionCallbackInfo<Value>& args) {
+ Environment* env = Environment::GetCurrent(args);
+ CHECK(args[0]->IsFunction());
+ Debug(env, DebugCategory::COVERAGE, "Ending coverage collection\n");
+ env->set_on_coverage_message_function(args[0].As<Function>());
+ V8CoverageConnection* connection =
+ Unwrap<V8CoverageConnection>(env->coverage_connection());
+ CHECK_NOT_NULL(connection);
+ connection->End();
+}
+
+static void Initialize(Local<Object> target,
+ Local<Value> unused,
+ Local<Context> context,
+ void* priv) {
+ Environment* env = Environment::GetCurrent(context);
+ env->SetMethod(target, "end", EndCoverageCollection);
+}
+} // namespace coverage
+} // namespace node
+
+NODE_MODULE_CONTEXT_AWARE_INTERNAL(coverage, node::coverage::Initialize)
diff --git a/src/node.cc b/src/node.cc
index f257495a13..82282e202b 100644
--- a/src/node.cc
+++ b/src/node.cc
@@ -19,6 +19,7 @@
// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
// USE OR OTHER DEALINGS IN THE SOFTWARE.
+#include "debug_utils.h"
#include "node_binding.h"
#include "node_buffer.h"
#include "node_constants.h"
@@ -230,6 +231,18 @@ MaybeLocal<Value> RunBootstrapping(Environment* env) {
Isolate* isolate = env->isolate();
Local<Context> context = env->context();
+ std::string coverage;
+ bool rc = credentials::SafeGetenv("NODE_V8_COVERAGE", &coverage);
+ if (rc && !coverage.empty()) {
+#if HAVE_INSPECTOR
+ if (!coverage::StartCoverageCollection(env)) {
+ return MaybeLocal<Value>();
+ }
+#else
+ fprintf(stderr, "NODE_V8_COVERAGE cannot be used without inspector");
+#endif // HAVE_INSPECTOR
+ }
+
// Add a reference to the global object
Local<Object> global = context->Global();
diff --git a/src/node_binding.cc b/src/node_binding.cc
index 08d55567d4..c9ff7be46f 100644
--- a/src/node_binding.cc
+++ b/src/node_binding.cc
@@ -21,6 +21,12 @@
#define NODE_BUILTIN_REPORT_MODULES(V)
#endif
+#if HAVE_INSPECTOR
+#define NODE_BUILTIN_COVERAGE_MODULES(V) V(coverage)
+#else
+#define NODE_BUILTIN_COVERAGE_MODULES(V)
+#endif
+
// A list of built-in modules. In order to do module registration
// in node::Init(), need to add built-in modules in the following list.
// Then in binding::RegisterBuiltinModules(), it calls modules' registration
@@ -77,7 +83,8 @@
NODE_BUILTIN_STANDARD_MODULES(V) \
NODE_BUILTIN_OPENSSL_MODULES(V) \
NODE_BUILTIN_ICU_MODULES(V) \
- NODE_BUILTIN_REPORT_MODULES(V)
+ NODE_BUILTIN_REPORT_MODULES(V) \
+ NODE_BUILTIN_COVERAGE_MODULES(V)
// This is used to load built-in modules. Instead of using
// __attribute__((constructor)), we call the _register_<modname>
diff --git a/src/node_internals.h b/src/node_internals.h
index 6cbad89594..01ebd8b40a 100644
--- a/src/node_internals.h
+++ b/src/node_internals.h
@@ -269,7 +269,9 @@ void DefineZlibConstants(v8::Local<v8::Object> target);
v8::MaybeLocal<v8::Value> RunBootstrapping(Environment* env);
v8::MaybeLocal<v8::Value> StartExecution(Environment* env,
const char* main_script_id);
-
+namespace coverage {
+bool StartCoverageCollection(Environment* env);
+}
} // namespace node
#endif // defined(NODE_WANT_INTERNALS) && NODE_WANT_INTERNALS