@ 261105.16
current
#include "node_debug.h"

#ifdef DEBUG
#include "node_binding.h"

#include "env-inl.h"
#include "util.h"
#include "v8-fast-api-calls.h"
#include "v8.h"

#include <string>
#include <string_view>
#include <unordered_map>
#endif  // DEBUG

namespace node::debug {

#ifdef DEBUG
using v8::Context;
using v8::FastApiCallbackOptions;
using v8::FunctionCallbackInfo;
using v8::Local;
using v8::Number;
using v8::Object;
using v8::Value;

// NOLINTNEXTLINE(runtime/thread_local)
thread_local std::unordered_map<FastStringKey, int, FastStringKey::Hash>
    generic_usage_counters;
// NOLINTNEXTLINE(runtime/thread_local)
thread_local std::unordered_map<FastStringKey, int, FastStringKey::Hash>
    v8_fast_api_call_counts;

void CountGenericUsage(FastStringKey counter_name) {
  generic_usage_counters[counter_name]++;
}

int GetGenericUsageCount(FastStringKey counter_name) {
  return generic_usage_counters[counter_name];
}

void TrackV8FastApiCall(FastStringKey key) {
  v8_fast_api_call_counts[key]++;
}

int GetV8FastApiCallCount(FastStringKey key) {
  return v8_fast_api_call_counts[key];
}

void GetGenericUsageCount(const FunctionCallbackInfo<Value>& args) {
  Environment* env = Environment::GetCurrent(args);
  if (!args[0]->IsString()) {
    env->ThrowError("getGenericUsageCount must be called with a string");
    return;
  }
  Utf8Value utf8_key(env->isolate(), args[0]);
  args.GetReturnValue().Set(GetGenericUsageCount(
      FastStringKey::AllowDynamic(utf8_key.ToStringView())));
}

void GetV8FastApiCallCount(const FunctionCallbackInfo<Value>& args) {
  Environment* env = Environment::GetCurrent(args);
  if (!args[0]->IsString()) {
    env->ThrowError("getV8FastApiCallCount must be called with a string");
    return;
  }
  Utf8Value utf8_key(env->isolate(), args[0]);
  args.GetReturnValue().Set(GetV8FastApiCallCount(
      FastStringKey::AllowDynamic(utf8_key.ToStringView())));
}

void SlowIsEven(const FunctionCallbackInfo<Value>& args) {
  Environment* env = Environment::GetCurrent(args);
  if (!args[0]->IsNumber()) {
    env->ThrowError("isEven must be called with a number");
    return;
  }
  int64_t value = args[0].As<Number>()->Value();
  args.GetReturnValue().Set(value % 2 == 0);
}

bool FastIsEven(Local<Value> receiver,
                const int64_t value,
                // NOLINTNEXTLINE(runtime/references)
                FastApiCallbackOptions& options) {
  TRACK_V8_FAST_API_CALL("debug.isEven");
  return value % 2 == 0;
}

void SlowIsOdd(const FunctionCallbackInfo<Value>& args) {
  Environment* env = Environment::GetCurrent(args);
  if (!args[0]->IsNumber()) {
    env->ThrowError("isOdd must be called with a number");
    return;
  }
  int64_t value = args[0].As<Number>()->Value();
  args.GetReturnValue().Set(value % 2 != 0);
}

bool FastIsOdd(Local<Value> receiver,
               const int64_t value,
               // NOLINTNEXTLINE(runtime/references)
               FastApiCallbackOptions& options) {
  TRACK_V8_FAST_API_CALL("debug.isOdd");
  return value % 2 != 0;
}

static v8::CFunction fast_is_even(v8::CFunction::Make(FastIsEven));
static v8::CFunction fast_is_odd(v8::CFunction::Make(FastIsOdd));

void Initialize(Local<Object> target,
                Local<Value> unused,
                Local<Context> context,
                void* priv) {
  SetMethod(context, target, "getV8FastApiCallCount", GetV8FastApiCallCount);
  SetMethod(context, target, "getGenericUsageCount", GetGenericUsageCount);
  SetFastMethod(context, target, "isEven", SlowIsEven, &fast_is_even);
  SetFastMethod(context, target, "isOdd", SlowIsOdd, &fast_is_odd);
}
#endif  // DEBUG

}  // namespace node::debug

#ifdef DEBUG
NODE_BINDING_CONTEXT_AWARE_INTERNAL(debug, node::debug::Initialize)
#endif  // DEBUG