-
Notifications
You must be signed in to change notification settings - Fork 107
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
rework cppgc for prototype chain #1047
base: main
Are you sure you want to change the base?
Conversation
f319d33
to
2d67870
Compare
|
||
/// A good enough number for the maximum prototype chain depth based on the | ||
/// usage. | ||
const MAX_PROTO_CHAIN: usize = 3; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Are you sure we're not gonna hit this limit immediately in Deno?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Nope, this is only for native object proto chain. The actual JS proto chain isn't restricted.
@@ -58,6 +132,78 @@ pub fn make_cppgc_object<'a, T: GarbageCollected + 'static>( | |||
wrap_object(scope, obj, t) | |||
} | |||
|
|||
pub fn make_cppgc_object2< |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Maybe change a name to something more descriptive to suggest that it uses the second argument as a prototype
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It's named because its easier for the macro to do: format!("make_cppgc_object{}", chain.len())
. These aren't supposed to be publicly used. I've added #[doc(hidden)]
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think cppgc_template_constructor
should throw a TypeError
.
/// ErasedPtr is a wrapper around a `v8::cppgc::Ptr` that allows downcasting | ||
/// to a specific type. Safety is guaranteed by the `tag` field in the | ||
/// `CppGcObject` struct. | ||
struct ErasedPtr { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actually this abstraction is much nicer than what we had previously. With this it is impossible to accidentially use T
without checking ptr.tag
anymore. Great!
fn trace(&self, visitor: &v8::cppgc::Visitor) { | ||
// Trace all the objects top-down the prototype chain. | ||
for ptr in self.0.iter().flatten() { | ||
ptr.ptr.trace(visitor); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Does this dispatch correctly? We don't want to call EreasedPtr
's T here - I assume this all works out, but can you add some comments?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Added
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@devsnek PTAL also
tag: TypeId::of::<T>(), | ||
member: t, | ||
}, | ||
PrototypeChainStore([ |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
do normal objects need this? its unfortunate to have double the allocations. could we instead have two tags, one for plain objects and one for prototype backed objects? plain objects can continue to use wrap/unwrap, and prototype backed objects can use wrap2/unwrap2.
} | ||
} | ||
|
||
struct PrototypeChainStore([Option<ErasedPtr>; MAX_PROTO_CHAIN]); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
maybe crazy but could this be an interior linked list of ErasedPtr stored on each object? not sure if saving the memory is worth the slight overhead of traversing when unwrapping, perhaps worth testing?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Tried it out:
#[repr(C)]
struct CppGcObject<T: GarbageCollected> {
tag: TypeId,
next: Option<ErasedPtr>,
member: T,
}
./dcore_proto_linked_list test.mjs # linked list
🛑 deno_core binary is meant for development and testing purposes.
Run test.mjs
1e8x new DOMPoint(): 10290ms
1e8x point.x: 2985ms
./dcore_proto_array test.mjs # array
🛑 deno_core binary is meant for development and testing purposes.
Run test.mjs
1e8x new DOMPoint(): 10544ms
1e8x point.x: 2785ms
Maybe it makes sense to use linked list when we increase depth further than 3?
Implement prototype inheritance into cppgc object wraps.