Closed Bug 812314 Opened 7 years ago Closed 7 years ago

Don't put definitions in `namespace js { ... }` blocks in .cpp files

Categories

(Core :: JavaScript Engine, defect)

Other Branch
defect
Not set

Tracking

()

RESOLVED FIXED
mozilla20

People

(Reporter: jorendorff, Assigned: jorendorff)

Details

Attachments

(2 files, 1 obsolete file)

So, apparently it's slightly preferred to do a qualified definition:

    void
    frontend::Foo()
    {
    }

rather than wrap the whole .cpp file in namespace blocks:

    namespace js {
    namespace frontend {

    void Foo()
    {
    }

    } // namespace frontend
    } // namespace js

This was a reversal of what we previously did, though, so we're pretty inconsistent about it. Here's a patch that fixes up a bunch of places to do the former rather than the latter -- not all of them but most of them.

It moves a bunch of static (file-scope) helper functions out of namespaces and into the global namespace, which I'm going to call a feature.
Attached patch part 1 - v1 (obsolete) — Splinter Review
Oh. In a handful of places, we're using a trick where you sort of declare a function without exposing the declaration it, like this:

    namespace js {

    inline void GoNuts(Squirrel *sq) {
        extern GoNutsSlow(Squirrel *);
        if (!sq->rabid())
            GoNutsSlow(sq);
    }

    }

I get it, but I think we're better off with one less clever thing in the codebase. The patch removes it in favor of actually declaring the Slow version in the header, which was already the more common practice.
Assignee: general → jorendorff
Attached patch part 1 - v2Splinter Review
Sorry this is huge. :-\ Very mechanical though.
Attachment #682144 - Attachment is obsolete: true
Attachment #682446 - Flags: review?(luke)
gc directory. There is some moderately weird stuff going on in Marking.cpp, so a few namespace-blocks remain there.
Attachment #682447 - Flags: review?(terrence)
Comment on attachment 682446 [details] [diff] [review]
part 1 - v2

Nicely done sir!  This has bugged me for a long time.  (I think I started the trend the wrong way by wrapping jstracer.cpp in namespace js { ... } before I saw why explicit qualification is better.)  lol @ make_unicode.py
Attachment #682446 - Flags: review?(luke) → review+
Comment on attachment 682447 [details] [diff] [review]
Part 2 - gc directory, v2

Review of attachment 682447 [details] [diff] [review]:
-----------------------------------------------------------------

\o/  This is very nice.  Thanks for flagging me for review: I learned a bunch.  Questions below are mostly for my own edjikashun, feel free to land after fixing the minor nits I found.

::: js/src/gc/Marking.cpp
@@ +24,1 @@
>  using mozilla::DebugOnly;

Linebreak between these sections, see vm/Stack.cpp for an example.

@@ +118,5 @@
>                   thing->compartment() == rt->atomsCompartment);
>  }
>  
>  template<typename T>
> +static void

Oh, nice catch!

@@ +158,5 @@
>      MarkInternal(trc, thingp);
>  }
>  
> +namespace js {
> +namespace gc {

Why is this required here?  Not saying it's not, I'm just surprised since you didn't need one for MarkRoot and it should have exactly the same sematics and usage.

@@ +238,5 @@
>  {                                                                                                 \
>      MarkUnbarriered<type>(trc, thingp, name);                                                     \
>  }                                                                                                 \
>                                                                                                    \
> +void                                                                                              \

Doh!  I totally missed that.  My brain must have wanted fewer lines to \s*\\.

@@ +936,5 @@
>          PushMarkStack(gcmarker, type->interpretedFunction);
>  }
>  
>  static void
> +gc::MarkChildren(JSTracer *trc, types::TypeObject *type)

This is static.  Why does it (and the following handful) need to be in gc:: whereas the other static functions don't?

::: js/src/gc/Memory.cpp
@@ +13,1 @@
>  #include "mozilla/Assertions.h"

I thought our normal include ordering put mozilla/ at the top?

::: js/src/gc/StoreBuffer.cpp
@@ +18,5 @@
>  /*** MonoTypeBuffer ***/
>  
>  template <typename T>
>  bool
>  StoreBuffer::MonoTypeBuffer<T>::enable(uint8_t *region, size_t len)

Huh, why does leaving off the gc:: work here when it doesn't in the other files?
Attachment #682447 - Flags: review?(terrence) → review+
evilpies pointed out that I didn't run make_unicode.py and check in the modified Unicode.cpp file. Will fix for checkin.

(In reply to Terrence Cole [:terrence] from comment #7)
> >  using mozilla::DebugOnly;
> Linebreak between these sections, see vm/Stack.cpp for an example.

Thanks.

> > +namespace js {
> > +namespace gc {
> 
> Why is this required here?  Not saying it's not, I'm just surprised since
> you didn't need one for MarkRoot and it should have exactly the same
> sematics and usage.

This is really hard to explain, bear with me...

These namespace blocks contain only the template js::gc::Mark<T>(JSTracer *trc, EncapsulatedPtr<T> *thing, const char *name). You can move this template out of the namespace and it'll parse just fine, but a bit later, the macro generates code like this:

// in namespace js::gc, generated by DeclMarkerImpl(BaseShape, BaseShape)
void
MarkBaseShape(JSTracer *trc, EncapsulatedPtr<BaseShape> *thing, const char *name)
{
    Mark<BaseShape>(trc, thing, name);
}

This fails to compile, because the lookup for 'Mark' finds the functions js::gc::Mark declared in Marking.h. It does not find the global template, because of course a hit in an inner namespace shadows a hit in an outer namespace.

(Extra credit: Furthermore the error message we get will be really baffling, because those none of those js::gc::Mark signatures in Marking.h are templates, so the angle brackets in "Mark<BaseShape>(trc, thing, name)" are parsed as less-than and greater-than operators, and then C++ goes quietly to pieces from there.)

We want the C++ compiler to consider all the Mark signatures at each call site, so we need to put them all in the same namespace.

> @@ +936,5 @@
> >  static void
> > +gc::MarkChildren(JSTracer *trc, types::TypeObject *type)
> 
> This is static.  Why does it (and the following handful) need to be in gc::
> whereas the other static functions don't?

The rule is just that for a top-level definition to match up with a previous declaration in a namespace, the definition has to be qualified. Otherwise the definition would be a new global.

So it doesn't really have anything to do with static, except that normally our static declarations are global. MarkChildren is special because, again, there's a js::gc::MarkChildren signature declared in Marking.h.

This particular case is a little sad because exposing js::gc::MarkChildren in the header is a hack. I'd prefer to change the hack to use a different function name, and make all the MarkChildren signatures global and static.

> >  #include "mozilla/Assertions.h"
> I thought our normal include ordering put mozilla/ at the top?

Er, quite. Thanks. Fixed.
Oh dear, that /is/ extremely sad-making. Thank you for the explanation!  :-)
> So, apparently it's slightly preferred to do a qualified definition
> rather than wrap the whole .cpp file in namespace blocks

Can someone explain why?  If you don't wrap the whole .cpp file then all the local definitions (e.g. classes) will be in the global namespace rather than the |js| namespace.  This probably doesn't matter in practice, but it seems a bit inconsistent.
https://hg.mozilla.org/mozilla-central/rev/7600a1ab2d7c
https://hg.mozilla.org/mozilla-central/rev/d19500da9c16
Status: NEW → RESOLVED
Closed: 7 years ago
Resolution: --- → FIXED
Target Milestone: --- → mozilla20
You need to log in before you can comment on or make changes to this bug.