#include "vtune/VTuneWrapper.h"
#include "mozilla/Sprintf.h"
#include "threading/LockGuard.h"
#include "threading/Mutex.h"
#include "vm/JSContext.h"
#include "vm/MutexIDs.h"
#include "vm/Realm.h"
#include "vm/Shape.h"
#ifdef MOZ_VTUNE
namespace js {
namespace vtune {
static Mutex* VTuneMutex = nullptr;
static bool VTuneLoaded(false);
bool Initialize() {
VTuneMutex = js_new<Mutex>(mutexid::VTuneLock);
if (!VTuneMutex) return false;
int loaded = loadiJIT_Funcs();
if (loaded == 1) VTuneLoaded = true;
return true;
}
void Shutdown() {
js_delete(VTuneMutex);
VTuneMutex = nullptr;
}
bool IsProfilingActive() {
return VTuneLoaded && iJIT_IsProfilingActive() == iJIT_SAMPLING_ON;
}
uint32_t GenerateUniqueMethodID() {
MOZ_ASSERT(VTuneMutex);
LockGuard<Mutex> guard(*VTuneMutex);
return (uint32_t)iJIT_GetNewMethodID();
}
static int SafeNotifyEvent(iJIT_JVM_EVENT event_type, void* data) {
MOZ_ASSERT(VTuneMutex);
LockGuard<Mutex> guard(*VTuneMutex);
return iJIT_NotifyEvent(event_type, data);
}
void MarkStub(const js::jit::JitCode* code, const char* name) {
if (!IsProfilingActive()) return;
iJIT_Method_Load_V2 method = {0};
method.method_id = GenerateUniqueMethodID();
method.method_name = const_cast<char*>(name);
method.method_load_address = code->raw();
method.method_size = code->instructionsSize();
method.module_name = const_cast<char*>("jitstubs");
int ok =
SafeNotifyEvent(iJVM_EVENT_TYPE_METHOD_LOAD_FINISHED_V2, (void*)&method);
if (ok != 1) printf("[!] VTune Integration: Failed to load method.\n");
}
void MarkRegExp(const js::jit::JitCode* code, bool match_only) {
if (!IsProfilingActive()) return;
iJIT_Method_Load_V2 method = {0};
method.method_id = GenerateUniqueMethodID();
method.method_load_address = code->raw();
method.method_size = code->instructionsSize();
if (match_only)
method.method_name = const_cast<char*>("regexp (match-only)");
else
method.method_name = const_cast<char*>("regexp (normal)");
method.module_name = const_cast<char*>("irregexp");
int ok =
SafeNotifyEvent(iJVM_EVENT_TYPE_METHOD_LOAD_FINISHED_V2, (void*)&method);
if (ok != 1) printf("[!] VTune Integration: Failed to load method.\n");
}
void MarkScript(const js::jit::JitCode* code, JSScript* script,
const char* module) {
if (!IsProfilingActive()) return;
iJIT_Method_Load_V2 method = {0};
method.method_id = script->vtuneMethodID();
method.method_load_address = code->raw();
method.method_size = code->instructionsSize();
method.module_name = const_cast<char*>(module);
char namebuf[512];
SprintfLiteral(namebuf, "%s:%u:%u", script->filename(), script->lineno(),
script->column() + 1);
method.method_name = &namebuf[0];
int ok =
SafeNotifyEvent(iJVM_EVENT_TYPE_METHOD_LOAD_FINISHED_V2, (void*)&method);
if (ok != 1) printf("[!] VTune Integration: Failed to load method.\n");
}
void MarkWasm(unsigned methodId, const char* name, void* start,
uintptr_t size) {
if (!IsProfilingActive()) return;
iJIT_Method_Load_V2 method = {0};
method.method_id = methodId;
method.method_name = const_cast<char*>(name);
method.method_load_address = start;
method.method_size = (unsigned)size;
method.module_name = const_cast<char*>("wasm");
int ok =
SafeNotifyEvent(iJVM_EVENT_TYPE_METHOD_LOAD_FINISHED_V2, (void*)&method);
if (ok != 1) printf("[!] VTune Integration: Failed to load method.\n");
}
void UnmarkCode(const js::jit::JitCode* code) {
UnmarkBytes(code->raw(), (unsigned)code->instructionsSize());
}
void UnmarkBytes(void* bytes, unsigned size) {
if (!IsProfilingActive()) return;
iJIT_Method_Load method = {0};
method.method_load_address = bytes;
method.method_size = size;
int ok = SafeNotifyEvent(iJVM_EVENT_TYPE_METHOD_UNLOAD_START, (void*)&method);
if (ok != 1) printf("[!] VTune Integration: Failed to unload method.\n");
}
} }
#endif