@@ -25,7 +25,23 @@ namespace workerd::jsg {
2525template <typename T, bool = isGcVisitable<T>()>
2626struct OpaqueWrappable ;
2727
28+ // Unique type tag for each type T. Used to implement fast type checking in OpaqueWrappable
29+ // without relying on dynamic_cast/RTTI. Each instantiation of this template variable has a
30+ // unique address that serves as a type identifier.
31+ template <typename T>
32+ inline const char opaqueTypeTag = 0 ;
33+
34+ template <typename T>
35+ inline const void * getOpaqueTypeTag () {
36+ return &opaqueTypeTag<T>;
37+ }
38+
2839struct OpaqueWrappableBase : public Wrappable {
40+ // Type tag for fast type checking. Set by OpaqueWrappable<T> constructor.
41+ const void * const typeTag;
42+
43+ explicit OpaqueWrappableBase (const void * tag): typeTag(tag) {}
44+
2945 kj::StringPtr jsgGetMemoryName () const override final {
3046 return " OpaqueWrappable" _kjc;
3147 }
@@ -38,7 +54,7 @@ template <typename T>
3854struct OpaqueWrappable <T, false >: public OpaqueWrappableBase {
3955 // Used to implement wrapOpaque().
4056
41- OpaqueWrappable (T&& value): value(kj::mv(value)) {}
57+ OpaqueWrappable (T&& value): OpaqueWrappableBase(getOpaqueTypeTag<T>()), value(kj::mv(value)) {}
4258
4359 T value;
4460 bool movedAway = false ;
@@ -95,8 +111,9 @@ T unwrapOpaque(v8::Isolate* isolate, v8::Local<v8::Value> handle) {
95111 static_assert (!isV8Local<T>(), " can't opaque-wrap non-persistent handles" );
96112
97113 Wrappable& wrappable = KJ_ASSERT_NONNULL (Wrappable::tryUnwrapOpaque (isolate, handle));
98- OpaqueWrappable<T>* holder = dynamic_cast <OpaqueWrappable<T>*>(&wrappable);
99- KJ_ASSERT (holder != nullptr );
114+ auto * base = static_cast <OpaqueWrappableBase*>(&wrappable);
115+ KJ_ASSERT (base->typeTag == getOpaqueTypeTag<T>());
116+ auto * holder = static_cast <OpaqueWrappable<T>*>(base);
100117 KJ_ASSERT (!holder->movedAway );
101118 holder->movedAway = true ;
102119 return kj::mv (holder->value );
@@ -111,8 +128,9 @@ T& unwrapOpaqueRef(v8::Isolate* isolate, v8::Local<v8::Value> handle) {
111128 static_assert (!isV8Local<T>(), " can't opaque-wrap non-persistent handles" );
112129
113130 Wrappable& wrappable = KJ_ASSERT_NONNULL (Wrappable::tryUnwrapOpaque (isolate, handle));
114- OpaqueWrappable<T>* holder = dynamic_cast <OpaqueWrappable<T>*>(&wrappable);
115- KJ_ASSERT (holder != nullptr );
131+ auto * base = static_cast <OpaqueWrappableBase*>(&wrappable);
132+ KJ_ASSERT (base->typeTag == getOpaqueTypeTag<T>());
133+ auto * holder = static_cast <OpaqueWrappable<T>*>(base);
116134 KJ_ASSERT (!holder->movedAway );
117135 return holder->value ;
118136}
@@ -126,8 +144,9 @@ void dropOpaque(v8::Isolate* isolate, v8::Local<v8::Value> handle) {
126144 static_assert (!isV8Ref<T>());
127145
128146 KJ_IF_SOME (wrappable, Wrappable::tryUnwrapOpaque (isolate, handle)) {
129- OpaqueWrappable<T>* holder = dynamic_cast <OpaqueWrappable<T>*>(&wrappable);
130- if (holder != nullptr ) {
147+ auto * base = static_cast <OpaqueWrappableBase*>(&wrappable);
148+ if (base->typeTag == getOpaqueTypeTag<T>()) {
149+ auto * holder = static_cast <OpaqueWrappable<T>*>(base);
131150 holder->movedAway = true ;
132151 auto drop KJ_UNUSED = kj::mv (holder->value );
133152 }
0 commit comments