Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
46 changes: 35 additions & 11 deletions bindings/otel-thread-ctx.cc
Original file line number Diff line number Diff line change
Expand Up @@ -679,6 +679,28 @@ constexpr int WRAPPED_OBJECT_OFFSET = 0;
#endif
constexpr int TAGGED_SIZE = v8::internal::kApiTaggedSize;

// sizeof(node::ObjectWrap). Given a pointer to a CtxWrap — or any other
// ObjectWrap-derived C++ object attached to a JSObject via the V8
// wrapped-object slot — add this offset to reach the derived class's own
// fields. For CtxWrap, that's `record_` (see the static_assert on its
// offset above).
constexpr int NATIVE_WRAP_FIELDS_OFFSET =
static_cast<int>(sizeof(node::ObjectWrap));

// V8 JSMap layout: kTableOffset within the JSMap object holds a tagged
// pointer to the backing OrderedHashMap table. Not exposed in V8's
// public headers; kept in sync with
// deps/v8/src/objects/js-collection.h (JSCollection::kTableOffset)
// and the torque-generated JSCollection layout.
constexpr int JS_MAP_TABLE_OFFSET = 0x18;

// V8 OrderedHashMap layout: the on-heap table starts with a 16-byte
// header before the element_count / deleted_element_count /
// number_of_buckets fields. Not exposed in V8's public headers; kept in
// sync with deps/v8/src/objects/ordered-hash-table.h
// (OrderedHashTable base layout).
constexpr int ORDERED_HASH_MAP_HEADER_SIZE = 0x10;

} // namespace

void OtelThreadCtx::Init(Local<Object> exports) {
Expand All @@ -688,17 +710,19 @@ void OtelThreadCtx::Init(Local<Object> exports) {

Isolate* isolate = Isolate::GetCurrent();
Local<Context> ctx = isolate->GetCurrentContext();
exports
->Set(ctx,
String::NewFromUtf8Literal(isolate,
"otelThreadCtxWrappedObjectOffset"),
Integer::New(isolate, WRAPPED_OBJECT_OFFSET))
.FromJust();
exports
->Set(ctx,
String::NewFromUtf8Literal(isolate, "otelThreadCtxTaggedSize"),
Integer::New(isolate, TAGGED_SIZE))
.FromJust();
auto publish_int = [&](const char* name, int value) {
exports
->Set(ctx,
String::NewFromUtf8(isolate, name).ToLocalChecked(),
Integer::New(isolate, value))
.FromJust();
};
publish_int("otelThreadCtxJsMapTableOffset", JS_MAP_TABLE_OFFSET);
publish_int("otelThreadCtxNativeWrapFieldsOffset", NATIVE_WRAP_FIELDS_OFFSET);
publish_int("otelThreadCtxOrderedHashMapHeaderSize",
ORDERED_HASH_MAP_HEADER_SIZE);
publish_int("otelThreadCtxTaggedSize", TAGGED_SIZE);
publish_int("otelThreadCtxWrappedObjectOffset", WRAPPED_OBJECT_OFFSET);
}

} // namespace dd
15 changes: 15 additions & 0 deletions ts/src/otel-thread-ctx.ts
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,9 @@ export interface ProcessContextAttributes {
readonly 'threadlocal.attribute_key_map': readonly string[];
readonly 'threadlocal.wrapped_object_offset': number;
readonly 'threadlocal.tagged_size': number;
readonly 'threadlocal.native_wrap_fields_offset': number;
readonly 'threadlocal.js_map_table_offset': number;
readonly 'threadlocal.ordered_hash_map_header_size': number;
}

/**
Expand Down Expand Up @@ -103,6 +106,9 @@ interface Addon {
otelThreadCtxGetStoredAlsHash(): number;
otelThreadCtxWrappedObjectOffset: number;
otelThreadCtxTaggedSize: number;
otelThreadCtxNativeWrapFieldsOffset: number;
otelThreadCtxJsMapTableOffset: number;
otelThreadCtxOrderedHashMapHeaderSize: number;
}

const SCHEMA_VERSION = 'nodejs_v1_dev';
Expand All @@ -114,6 +120,9 @@ const SCHEMA_VERSION = 'nodejs_v1_dev';
// consistent in shape.
let WRAPPED_OBJECT_OFFSET = 24;
let TAGGED_SIZE = 8;
let NATIVE_WRAP_FIELDS_OFFSET = 24;
let JS_MAP_TABLE_OFFSET = 0x18;
let ORDERED_HASH_MAP_HEADER_SIZE = 0x10;

/** {@inheritDoc ThreadContextCtor} */
export let ThreadContext: ThreadContextCtor;
Expand All @@ -140,6 +149,9 @@ if (process.platform === 'linux') {
const addon: Addon = findBinding(join(__dirname, '..', '..'));
WRAPPED_OBJECT_OFFSET = addon.otelThreadCtxWrappedObjectOffset;
TAGGED_SIZE = addon.otelThreadCtxTaggedSize;
NATIVE_WRAP_FIELDS_OFFSET = addon.otelThreadCtxNativeWrapFieldsOffset;
JS_MAP_TABLE_OFFSET = addon.otelThreadCtxJsMapTableOffset;
ORDERED_HASH_MAP_HEADER_SIZE = addon.otelThreadCtxOrderedHashMapHeaderSize;

ThreadContext = addon.threadContext;

Expand Down Expand Up @@ -266,5 +278,8 @@ export function getProcessContextAttributes(
'threadlocal.attribute_key_map': Object.freeze(keys.slice()),
'threadlocal.wrapped_object_offset': WRAPPED_OBJECT_OFFSET,
'threadlocal.tagged_size': TAGGED_SIZE,
'threadlocal.native_wrap_fields_offset': NATIVE_WRAP_FIELDS_OFFSET,
'threadlocal.js_map_table_offset': JS_MAP_TABLE_OFFSET,
'threadlocal.ordered_hash_map_header_size': ORDERED_HASH_MAP_HEADER_SIZE,
}) as ProcessContextAttributes;
}
9 changes: 9 additions & 0 deletions ts/test/test-otel-thread-ctx.ts
Original file line number Diff line number Diff line change
Expand Up @@ -733,8 +733,17 @@ function captureBytes(opts: {
strictAssert.deepEqual(pca['threadlocal.attribute_key_map'], keys);
strictAssert.equal(pca['threadlocal.wrapped_object_offset'], 24);
strictAssert.equal(pca['threadlocal.tagged_size'], 8);
strictAssert.equal(pca['threadlocal.native_wrap_fields_offset'], 24);
strictAssert.equal(pca['threadlocal.js_map_table_offset'], 0x18);
strictAssert.equal(
pca['threadlocal.ordered_hash_map_header_size'],
0x10,
);
strictAssert.deepEqual(Object.keys(pca).sort(), [
'threadlocal.attribute_key_map',
'threadlocal.js_map_table_offset',
'threadlocal.native_wrap_fields_offset',
'threadlocal.ordered_hash_map_header_size',
'threadlocal.schema_version',
'threadlocal.tagged_size',
'threadlocal.wrapped_object_offset',
Expand Down
Loading