On 06/20/2013 07:21 AM, Till Schneidereit wrote:
All!

We still don't have a clear line on how to name handles, both in- and
outside of the engine. Or, if we do, it's pretty unevenly distributed.

The current policy is HandleT inside spidermonkey and xpconnect, JS::Handle<T*> outside.

Seeing as how everyone in the world just loves a good discussion about
naming (and how we should probably get to something resembling consistency
before handles are used outside the engine too much), let's get this thing
going, shall we?

I would be happy for this perennial topic to die. Having a discussion here seems like a plausible way to make it die. So I am fully in support of this plan. :-)

Here's my opening gambit, in IRC-based collaboration with @ted and @jonco,
and opposition from @evilpie:

Options:
1. don't use any typedefs at all, so always use (js:: and JS::)Handle<Foo*>
2. change the template to the form Handle<Foo>, roughly matching what v8
does
3. use typedefs everywhere, so always use HandleFoo

Personally, I favor the last of these options, because:
1. it is the cleanest, least cluttery one
2. v8 seems to get by just fine with option 2, somewhat countering the
argument for option 1 that everything else hides the fact that you're
dealing with heap values
3. Handle<T> isn't a general container people can use with their own Ts, so
the fact that it's a template in the first place is an implementation
detail that shouldn't be exposed
3. it scales linearly with the number of JSObject subclasses, so isn't
really going to be a burden going forward

That's all I've got, I think.

I support option #1.

Assuming #2 means using Handle<JSObject> instead of Handle<JSObject*>, I'm against. First, because of Handle<Value>, which is inconsistent with Handle<JSObject>. Second, because Handles are mysterious and feel heavyweight until you realize they're just a double pointer (ok, pointer to encoded pointer in the case of Value).

Which itself makes sense: I have a pointer to something that may move, so the pointer value will need to change. How can I avoid changing all consumers' pointers? By adding a level of indirection: store a pointer to a movable pointer instead. It's very clear what you're giving up (an extra dereference on use) and what you're gaining (pointers can now move).

As for #3, this morning on IRC, bz pointed out that he is utilizing the templateyness *outside* of spidermonkey in the DOM bindings. I think that's a strong argument for keeping the template exposed.

Expanding on that, if we exposed HandleObject, HandleString, HandleValue, etc., then I kind of starting thinking: Hey, these things are all closely related. Wouldn't it be nice if we could use the C++ type system to express that commonality? I know, I'll make my own header that does

  template<typename T>
  class MyHandle {
    public:
      typedef T InnerType;
  };

  template<>
  class MyHandle<JSObject*> {
    public:
      typedef HandleObject Handle;
  };

  template<>
  class MyHandle<JSStringt*> {
    public:
      typedef HandleString Handle;
  };

   .
   .
   .

there! Now I can use MyHandle<T>::Handle for everything!

  template<typename T>
  void LogPointer(const MyHandle<T>::Handle& h)
  {
     printf("rooted %p\n", h.get());
  }
  ...overload for MyHandle<Value>::Handle if needed...
  ...overload for other pointers that print out a different string...

I'm half kidding, but seriously, if there's *any* reason why somebody might want to implement something generically against Handles, then we should expose the commonality via the C++ type system, not conceal it. And bz has an existence proof in hand. (If our silly compilers just supported the syntax |friend developer bz;|, then I might change my mind.)

The main counterargument I see to this is if we have such a small set of externally exposed gcptr types that the commonality doesn't help. In a quick glace at jspubtd.h, I see:

  class                                       JSFlatString;
  class                                       JSFunction;
  class                                       JSObject;
  class                                       JSScript;
  class                                       JSStableString;
  class                                       JSString;

which is more than enough for me. I also like the idea of being able to expose new garbage-collectible things in the future. (I'm not thinking of any of the ones we now have, more about new things.) Also, note that within spidermonkey there are a lot more types, so the argument for Handle<T> is stronger.

So put me down for #1. I like exposing Handle<T>, and I'd like to use it internally in Spidermonkey. I've heard the extra finger typing argument, but these just show up in parameter lists. Anyway, we have a long history of lengthening names for precision and documentation. Get friendly with your < and > keys.

I would also support renaming it everywhere to Local<T>, to better pair with HeapPtr<T> and stop people from thinking that you should be able to get a Handle out of a HeapPtr. (Which you can't, because HeapPtr is using static typing to call the right barriers when you modify it, and if you lose the static heap-vs-stack distinction casting both to a Handle, then you'd have to do barriers on both things. Or at least, dynamically check which one you're holding.) But given that we're currently exporting Handle<T>, we can make those decisions independently.

I think I had one more point to make, but wracking my memory right now, I find myself to be pointless. I guess I'd better shut up, then.

_______________________________________________
dev-tech-js-engine-internals mailing list
[email protected]
https://lists.mozilla.org/listinfo/dev-tech-js-engine-internals

Reply via email to