Author Archives: Mike Conley

The Joy of Coding (Ep. 18): New Theme Song!

In this episode, I debuted The Joy of Coding’s new theme song, lovingly crafted by my good friend Barn Costello!1

Then I dove into fixing a new bug that allows e10s to continue running if the user is in safe mode. After that, we dove into an investigation on why click-to-play wasn’t working for a particular site.

Episode agenda.

References


  1. Shameless plug – Barn and I are in a band together. Here are some of our music videos

Things I’ve Learned This Week (June 1 – June 5, 2015)

How to get an nsIGlobalObject* from a JSContext*

I’m working on a patch for bug 1116188 to make gathering profiles from subprocesses asynchronous. In order to do that, I’m exposing a new method on nsIProfiler called getProfileDataAsync that is returning a DOM Promise. What’s interesting about this is that I’m returning a DOM Promise from C++! 1

In order to construct a DOM Promise in C++, I need to hand it something that implements nsIGlobalObject. I suspect that this helps the Promise determine which memory region that it belongs to.

My new method gets a JSContext* because I’ve got the [implicit_jscontext] bit about the method definition in the nsIProfiler.idl file… so how do I go about turning that into an nsIGlobalObject?

Here’s the maneuver:

// Where aCX is your JSContext*:
nsIGlobalObject* go = xpc::NativeGlobal(JS::CurrentGlobalOrNull(aCx));

That will, as the name suggests, return either an nsIGlobalObject*, or a nullptr.

Resolving a DOM Promise from C++ with a JS Object

For my patch for bug 1116188, it’s all well and good to create a DOM Promise, but you have to resolve or reject that Promise for it to have any real value.

In my case, I wanted to take a string, parse it into a JS Object, and resolve with that.

Resolving or rejecting a DOM Promise in Javascript is pretty straight-forward – you’re given back resolve / reject function, and you just need to call those with your results and you’re done.

In C++, things get a little hairier. As I discovered in my most recent episode of The Joy of Coding, conditions need to be right in order for this to work out.

Here’s what I ended up doing (I’ve simplified the method somewhat to remove noise):

void
ProfileGatherer::Finish()
{
  AutoJSAPI jsapi;
  jsapi.Init();
  JSContext* cx = jsapi.cx();
  JSAutoCompartment ac(cx, mPromise->GlobalJSObject());

  // Now parse the JSON so that we resolve with a JS Object.
  JS::RootedValue val(cx);
  {
    UniquePtr<char[]> buf = mWriter.WriteFunc()->CopyData();
    NS_ConvertUTF8toUTF16 js_string(nsDependentCString(buf.get()));
    MOZ_ALWAYS_TRUE(JS_ParseJSON(cx, static_cast<const char16_t*>(js_string.get()),
                                 js_string.Length(), &val));
  }
  mPromise->MaybeResolve(val);
}

The key parts here are getting the AutoJSAPI on the stack, initting it, gettings its JSContext, and then putting the JSAutoCompartment on the stack. Note that I had to pass not only the JSContext, but the global JS Object for the Promise as well – I suspect that’s, again, to ensure that the right compartment is being entered. Otherwise, I start failing assertions like crazy.

Note that the code above is by no means perfect – I’m missing error handling functions for when the JSON parsing goes wrong. In that case, I should probably reject the Promise instead. bz pointed me to a good example of that going on here in Fetch.cpp:

      if (!JS_ParseJSON(cx, decoded.get(), decoded.Length(), &json)) {
        if (!JS_IsExceptionPending(cx)) {
          localPromise->MaybeReject(NS_ERROR_DOM_UNKNOWN_ERR);
          return;
        }

        JS::Rooted<JS::Value> exn(cx);
        DebugOnly<bool> gotException = JS_GetPendingException(cx, &exn);
        MOZ_ASSERT(gotException);

        JS_ClearPendingException(cx);
        localPromise->MaybeReject(cx, exn);
        return;
      }

      localPromise->MaybeResolve(cx, json);
      return;

I’ll probably end up doing something similar in the next iteration of my patch.


  1. I learned how to do that a few weeks back

The Joy of Coding (Ep. 17): Frustrations in the Key of C++

In this episode, I gave a quick update on the OS X printing bug we’d been working on a for a few weeks (Spoiler alert – the patch got reviewed and landed!), and then dove into my new problem: getting performance profiles from subprocesses asynchronously.

And, I won’t lie to you, this is probably the most frustrating episode in the series so far. I really didn’t make much headway.

The way I want to solve this problem involves passing a DOM Promise back to the Javascript caller that resolves when all of the profiles have been gathered asynchronously.

If I were writing this in Javascript, it’d be a cinch. Creating, passing around, and resolving Promises is pretty straight-forward in that world.

But the Gecko profiler backend is written entirely in C++, and so that’s where I’d have to create the Promise.

A few weeks back, I posted a “Things I’ve learned this week” about how to create DOM Promises in C++. That’s all well and good, but creating the Promise is only half of the job. You have to resolve (or reject) the Promise in order for it to be useful at all.

The way I wanted to resolve the Promise involved parsing a JSON string and resolving with the resulting object.

That turned out to be a lot harder than I thought it’d be. Watch the video to see why. Suffice it to say, I spend a lot of it asking for help in IRC. It’s a 100% accurate demonstration of what I do when I’m lost, or can’t figure something out, and I need help.

Since I recorded this episode, I’ve figured out what I needed to do – I’ve posted a “Things I’ve learned this week” containing that information. Hopefully that’ll help somebody else in the future!

Oh – also, this episode has sound effects, courtesy of Wacky Morning DJ (which I demonstrated in last week’s episode).

Episode agenda.

References

Bug 1116188 – [e10s] Stop using sync messages for Gecko profilerNotes

Things I’ve Learned This Week (May 25 – May 29, 2015)

MozReview will now create individual attachments for child commits

Up until recently, anytime you pushed a patch series to MozReview, a single attachment would be created on the bug associated with the push.

That single attachment would link to the “parent” or “root” review request, which contains the folded diff of all commits.

We noticed a lot of MozReview users were (rightfully) confused about this mapping from Bugzilla to MozReview. It was not at all obvious that Ship It on the parent review request would cause the attachment on Bugzilla to be r+’d. Consequently, reviewers used a number of workarounds, including, but not limited to:

  1. Manually setting the r+ or r- flags in Bugzilla for the MozReview attachments
  2. Marking Ship It on the child review requests, and letting the reviewee take care of setting the reviewer flags in the commit message
  3. Just writing “r+” in a MozReview comment

Anyhow, this model wasn’t great, and caused a lot of confusion.

So it’s changed! Now, when you push to MozReview, there’s one attachment created for every commit in the push. That means that when different reviewers are set for different commits, that’s reflected in the Bugzilla attachments, and when those reviewers mark “Ship It” on a child commit, that’s also reflected in an r+ on the associated Bugzilla attachment!

I think this makes quite a bit more sense. Hopefully you do too!

See gps’s blog post for the nitty gritty details, and some other cool MozReview announcements!

The Joy of Coding (Ep. 16): Wacky Morning DJ

I’m on vacation this week, but the show must go on! So I pre-recorded a shorter episode of The Joy of Coding last Friday.

In this episode1, I focused on a tool I wrote that I alluded to in the last episode, which is a soundboard to use during Joy of Coding episodes.

I demo the tool, and then I explain how it works. After I finished the episode, I pushed to repository to GitHub, and you can check that out right here.

So I’ll see you next week with a full length episode! Take care!


  1. Which, several times, I mistakenly refer to as the 15th episode, and not the 16th. Whoops.