Closed Bug 1185106 Opened 9 years ago Closed 8 years ago

Implement async functions (ES 2017 proposal)

Categories

(Core :: JavaScript Engine, defect)

defect
Not set
normal

Tracking

()

RESOLVED FIXED
mozilla52
Tracking Status
relnote-firefox --- 52+
firefox52 --- fixed

People

(Reporter: mkierski, Assigned: mkierski, Mentored)

References

(Blocks 1 open bug)

Details

(Keywords: dev-doc-complete, Whiteboard: [DocArea=JS])

Attachments

(35 files, 145 obsolete files)

58 bytes, text/x-review-board-request
till
: review+
h4writer
: review+
Details
58 bytes, text/x-review-board-request
till
: review+
Details
58 bytes, text/x-review-board-request
till
: review+
Details
58 bytes, text/x-review-board-request
till
: review+
Details
58 bytes, text/x-review-board-request
till
: review+
Details
58 bytes, text/x-review-board-request
till
: review+
Details
58 bytes, text/x-review-board-request
till
: review+
Details
58 bytes, text/x-review-board-request
till
: review+
Details
58 bytes, text/x-review-board-request
till
: review+
Details
58 bytes, text/x-review-board-request
till
: review+
Details
58 bytes, text/x-review-board-request
till
: review+
Details
58 bytes, text/x-review-board-request
till
: review+
Details
58 bytes, text/x-review-board-request
till
: review+
Details
58 bytes, text/x-review-board-request
till
: review+
Details
58 bytes, text/x-review-board-request
till
: review+
Details
58 bytes, text/x-review-board-request
till
: review+
Details
58 bytes, text/x-review-board-request
till
: review+
Details
58 bytes, text/x-review-board-request
till
: review+
Details
58 bytes, text/x-review-board-request
till
: review+
Details
58 bytes, text/x-review-board-request
till
: review+
Details
58 bytes, text/x-review-board-request
till
: review+
Details
58 bytes, text/x-review-board-request
till
: review+
Details
58 bytes, text/x-review-board-request
till
: review+
Details
58 bytes, text/x-review-board-request
till
: review+
Details
58 bytes, text/x-review-board-request
till
: review+
Details
58 bytes, text/x-review-board-request
till
: review+
Details
58 bytes, text/x-review-board-request
till
: review+
Details
58 bytes, text/x-review-board-request
Details
58 bytes, text/x-review-board-request
till
: review+
Details
58 bytes, text/x-review-board-request
till
: review+
Details
58 bytes, text/x-review-board-request
till
: review+
Details
58 bytes, text/x-review-board-request
till
: review+
Details
58 bytes, text/x-review-board-request
till
: review+
Details
1.98 KB, patch
till
: review+
Details | Diff | Splinter Review
2.95 KB, patch
till
: review+
Details | Diff | Splinter Review
ni? for myself because I promised to provide a bare-bones self-hosted constructor for Promise, to be used as the implementation vehicle here.
Flags: needinfo?(till)
Keywords: dev-doc-needed
Whiteboard: [DocArea=JS]
This implements the Promise object as an empty stub. It also has stubs for all the (static) methods, but doesn't store the callbacks anywhere. I guess converting it to an extended function and using the reserved slots might just work.
Flags: needinfo?(till)
Attached patch Basic implementation of promises (obsolete) — Splinter Review
Attachment #8635822 - Attachment is obsolete: true
Attachment #8636818 - Flags: review?(efaustbmo)
Assignee: nobody → mkierski
Attachment #8636818 - Attachment description: newpatch3 → Basic implementation of promises
Comment on attachment 8636818 [details] [diff] [review]
Basic implementation of promises

Punting to till, the selfhosting guru.
Attachment #8636818 - Flags: review?(efaustbmo) → review?(till)
Comment on attachment 8636818 [details] [diff] [review]
Basic implementation of promises

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

For future reference, it's best to keep changes in separate patches, at least while reviewing. Much easier to separate out what you changed on top of my changes. As it is now, I'm effectively reviewing my own changes, too.

Please make sure that all indentation is using spaces, not tabs. Promise.js contains a mix of both.

I added lots of additional comments below that need to be addressed. In general, you should read the self-hosting documentation once again to see what the restrictions are compared to normal JS code. I didn't note all issues in Promise.js because most are repeats of the same issues already mentioned.

Also, the implementation isn't spec-compliant in various ways. I don't know how important that is for your project, you should discuss that with efaust. At the very least, I'd like to see comments about deviations from the spec, so we're aware of them.

::: js/src/builtin/Promise.cpp
@@ +20,5 @@
> +static const JSFunctionSpec promise_static_methods[] = {
> +    JS_SELF_HOSTED_FN("all", "Promise_all", 1, 0),
> +    JS_SELF_HOSTED_FN("race", "Promise_race", 1, 0),
> +    JS_SELF_HOSTED_FN("reject", "Promise_reject", 1, 0),
> +    JS_SELF_HOSTED_FN("init", "Promise_init", 2, 0),

You only need to install functions on an object if they're exposed to content and should be called on that object. That's not the case for Promise_init: it's neither supposed to be exposed to content (but is, by this line), nor should you ever call it via Promise.init. (But see below for more issues with this function.)

@@ +34,5 @@
> +    HandleValue fn = args.get(0);
> +
> +    if (!IsCallable(fn)) {
> +        JS_ReportErrorNumber(cx, GetErrorMessage, nullptr, JSMSG_NOT_FUNCTION,
> +                             "Promise constructor argument");

Please test which errors the current implementation in Gecko throws here and match those. (Hint, test for too few arguments in addition to IsCallable, and fix the error message.)

@@ +43,5 @@
> +    JSObject* obj = NewBuiltinClassInstance(cx, &PromiseObject::class_);
> +    if (!obj)
> +        return false;
> +
> +    Rooted<JSObject*> rt(cx, obj);

This can be RootedObject. Also, you can get rid of the JSObject* above and just use
RootedObject obj(cx, NewBuiltinClassInstance(cx, &PromiseObject::class_));
if (!obj)
    return false;

(and change all usages of rt to obj below.)

@@ +45,5 @@
> +        return false;
> +
> +    Rooted<JSObject*> rt(cx, obj);
> +    JSObject* promiseConstructor = JS_GetConstructor(cx, rt);
> +    Rooted<JSObject*> rtPromiseConstructor(cx, promiseConstructor);

Same here: RootedObject, and no intermediary JSObject*.

@@ +56,5 @@
> +    JS::AutoValueVector argValues(cx);
> +    argValues.append(promise);
> +    argValues.append(fn);
> +    HandleValueArray arr(argValues);
> +    JS_CallFunctionName(cx, rtPromiseConstructor, "init",

There are some problems with this: the most important one is that content could just change the way promises are initialized by doing `Promise.init = myEvilFunction`. However, it's also quite a bit slower than it'd need to be.

Instead, the instance should be fully initialized in C++ code. The way things are set up right now, that'd be quite annoying: defining properties on JSObjects from C++ sucks a bit. However, we shouldn't do that anyway: right now, the internal state of a promise could just be changed by content code by doing assigning to the _state, _value, or _deferreds properties. (Or changing their internal values.)

So how should we do this instead, you ask. By using reserved slots. A good example for how to use those and initialize instances with enough of them is the ArrayIterator in builtin/Array.js. Take a look at CreateArrayIteratorAt in that file: it calls the intrinsic NewArrayIterator (defined and installed in SelfHosting.cpp). That returns an object with 3 reserved slots. Check ArrayIteratorObject::class_ in jsiter.cpp for how that works. Then observe how the UnsafeSetReservedSlot intrinsic is used to set the slots. Reserved slots can also be set from C++, which is what you want to do in the constructor. Try to understand how the ArrayIterator implementation works: it'll help you understand how to use the reserved slots from both C++ and self-hosted JS code.

::: js/src/builtin/Promise.js
@@ +2,5 @@
> + * License, v. 2.0. If a copy of the MPL was not distributed with this
> + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
> +
> +function Promise_all(promises) {
> +		return new Promise(function (resolve, reject) {

As described above, this needs to use an intrinsic function for calling the C++-implemented constructor, similar to how things are done for ArrayIterator.

@@ +5,5 @@
> +function Promise_all(promises) {
> +		return new Promise(function (resolve, reject) {
> +			if (promises.length === 0) return resolve([]);
> +			var remaining = promises.length;
> +			function res(i, val) {

Please give all functions and variables speaking names. If they're a bit longer, that's ok.

@@ +7,5 @@
> +			if (promises.length === 0) return resolve([]);
> +			var remaining = promises.length;
> +			function res(i, val) {
> +				try {
> +					if (val && (typeof val === 'object' || typeof val === 'function')) {

There's an `IsCallable` intrinsic which should be used here. Somewhat irritatingly, not all callables are functions.

@@ +10,5 @@
> +				try {
> +					if (val && (typeof val === 'object' || typeof val === 'function')) {
> +						var then = val.then;
> +						if (typeof then === 'function') {
> +							then.call(val, function (val) { res(i, val) }, reject);

In self-hosted code, using .call and .apply (and pretty much all other method calls) is forbidden in 99.9% of all cases. This code would break if content code overrode Function.prototype.call. Use `callFunction` instead.

@@ +23,5 @@
> +					reject(ex);
> +				}
> +			}
> +			for (var i = 0; i < promises.length; i++) {
> +				res(i, promises[i]);

Can't you just inline the contents of `res` into this loop?

@@ +28,5 @@
> +			}
> +		});
> +}
> +
> +function Promise_race(values) {

This doesn't really implement Promise.prototype.race, right? It's somewhat ok if the implementation is just enough to get async/await working, but if so, please add a comment explaining why it's done this way. If race isn't needed to implement async/await at all, I'd much rather see this replaced with a stub that just throws an exception saying that it's not really implemented.

@@ +31,5 @@
> +
> +function Promise_race(values) {
> +    return new Promise(function (resolve, reject) {
> +        for (var i = 0, len = values.length; i < len; i++) {
> +            values[i].then(resolve, reject);

Same here: no method calls without callFunction.

@@ +43,5 @@
> +    });
> +}
> +
> +function Promise_resolve(value) {
> +    if (value && typeof value === 'object' && value.constructor === Promise) {

`value.constructor === Promise` probably isn't the right check: it can be fooled by changing value.__proto__, Promise.prototype.constructor, or value.constructor. Check the specification for how this check is supposed to work.

@@ +57,5 @@
> +  return this.then(null, onRejected);
> +}
> +
> +function asap(cb) {
> +  cb();

This implementation of asap will definitely not be sufficient for your needs. It's going to be very important to delay running `cb` until the next turn of the event loop. That's probably the most annoying part of doing all this in SpiderMonkey. (Though it might also be easier than I think.) Talk to efaust or Waldo about how to approach this.

@@ +93,5 @@
> +
> +MakeConstructible(Promise, {
> +  then: Promise_then,
> +  catch: Promise_catch
> +});

As explained above, you can't use this constructor but have to use an intrinsic as is done for ArrayIterator.

There's another reason for this that I didn't explain before: a promise created this way, using `new Promise` in self-hosted code will not have the same constructor as one created using `new Promise` in content code. That's because the `Promise` constructor available to content code isn't the one you have here. Instead it's the one created from PromiseObject::class_. One consequence here is that the `constructor` properties would be different, als would be __proto__.

::: js/src/gc/StoreBuffer.cpp
@@ +105,5 @@
>  
> +// template struct StoreBuffer::MonoTypeBuffer<StoreBuffer::ValueEdge>;
> +// template struct StoreBuffer::MonoTypeBuffer<StoreBuffer::CellPtrEdge>;
> +// template struct StoreBuffer::MonoTypeBuffer<StoreBuffer::SlotsEdge>;
> +// template struct StoreBuffer::MonoTypeBuffer<StoreBuffer::WholeCellEdges>;

This needs review from someone else. I commented out these lines to get things to compile, but really, that's not the right solution. My guess is that adding a new source file changed which cpp files get compiled together, causing issues here. Talk to efaust or waldo about how best to deal with this.
Attachment #8636818 - Flags: review?(till)
Attached patch fix_unified_bustage-v0.diff (obsolete) — Splinter Review
This patch fixes the unified bustage.

The issue here is that we may or may not need the template instantiations depending one what code the compiler sees in the translation unit containing the instantiations.
Comment on attachment 8640005 [details] [diff] [review]
fix_unified_bustage-v0.diff

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

Seems like it should fix the problem. There's no way commenting out those specializations can be correct, so I'm willing to believe this should be the way forward.
Attachment #8640005 - Flags: review+
Attachment #8636818 - Attachment is obsolete: true
Attachment #8640005 - Attachment is obsolete: true
Attachment #8640126 - Flags: review?(till)
Attachment #8640126 - Flags: review?(efaustbmo)
Comment on attachment 8640126 [details] [diff] [review]
Implemented a polyfill for promises

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

::: js/src/moz.build
@@ +343,4 @@
>  SOURCES += [
>      'builtin/RegExp.cpp',
>      'frontend/Parser.cpp',
> +    'gc/StoreBuffer.cpp',

At the very least, the patch that terrence wrote should land seperately. This fix has nothing to do with the patch for the polyfill.
Note: It is dependent on terrence's patch (does not include it)
Attachment #8640212 - Flags: review?(till)
Attachment #8640212 - Flags: review?(efaustbmo)
Comment on attachment 8640212 [details] [diff] [review]
Fixed (rebased) implementation of promises

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

I've been thinking about this some more and would really prefer for this to not include my original patch, either. The reason is that I'm deeply uncomfortable with reviewing my own code.

The way this works is that you first apply terrence's patch, then mine, then yours. Change the descriptions to "Bug 1185106 - Part N: description". That way, it's clear which order they have to be applied in without additional comments.

Clearing review for now, please re-request for the new patch.
Attachment #8640212 - Flags: review?(till)
Attachment #8640126 - Attachment is obsolete: true
Attachment #8640212 - Attachment is obsolete: true
Attachment #8640126 - Flags: review?(till)
Attachment #8640126 - Flags: review?(efaustbmo)
Attachment #8640212 - Flags: review?(efaustbmo)
Attachment #8640668 - Flags: review+
Attachment #8640670 - Flags: review?(efaustbmo)
Attached patch Part 3: Promises implementation (obsolete) — Splinter Review
Attachment #8640672 - Flags: review?(till)
Attachment #8640670 - Attachment is patch: true
Attachment #8640670 - Attachment mime type: text/x-patch → text/plain
Comment on attachment 8640670 [details] [diff] [review]
Part 2: (till) Promises boilerplate

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

I believe this.

::: js/src/gc/StoreBuffer.cpp
@@ +105,5 @@
>  
> +// template struct StoreBuffer::MonoTypeBuffer<StoreBuffer::ValueEdge>;
> +// template struct StoreBuffer::MonoTypeBuffer<StoreBuffer::CellPtrEdge>;
> +// template struct StoreBuffer::MonoTypeBuffer<StoreBuffer::SlotsEdge>;
> +// template struct StoreBuffer::MonoTypeBuffer<StoreBuffer::WholeCellEdges>;

We should not still do this. We even have a patch in this series so that it's not necessary.
Attachment #8640670 - Flags: review?(efaustbmo) → review+
Fixed up the patch format for part 1 and landed:
remote:   https://hg.mozilla.org/integration/mozilla-inbound/rev/48a35f84fb9d
Attachment #8640668 - Attachment is obsolete: true
Attachment #8640988 - Flags: review+
Removed the StoreBuffer.cpp changes from part 2, carrying review.

I didn't land this because it doesn't make any sense whatsoever. We might fold it in with part 3 in the end, not sure yet.
Attachment #8640670 - Attachment is obsolete: true
Attachment #8640998 - Flags: review+
Comment on attachment 8640672 [details] [diff] [review]
Part 3: Promises implementation

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

Thanks for the new patch. This is getting closer, but still has quite a few issues. Please read through the comments carefully and try to address them all. I'm still particularly concerned with the asap stuff and don't fully understand how it works. For the parts of the code that aren't straight-forward, comments would be really important.

::: js/src/builtin/Promise.cpp
@@ +7,5 @@
>  #include "builtin/Promise.h"
>  
>  #include "jscntxt.h"
>  
> +#define PROMISE_STATE_SLOT 0

You can add these defines to builtin/SelfHostingDefines.h, include that in this cpp file, and remove them from here and from Promise.js. That way they're not duplicated and can't accidentally change in only one place.

@@ +33,5 @@
>  PromiseConstructor(JSContext* cx, unsigned argc, Value* vp)
>  {
>      CallArgs args = CallArgsFromVp(argc, vp);
>  
> +    HandleValue fn = args.get(0);

Move this to below the args length check.

@@ +37,5 @@
> +    HandleValue fn = args.get(0);
> +
> +    if (args.length() == 0) {
> +      JS_ReportErrorNumber(cx, GetErrorMessage, nullptr, JSMSG_MORE_ARGS_NEEDED,
> +          "Promise.constructor", "0", "s");

Nit: check the indentations and general formatting in this file, too.

@@ +53,5 @@
>          return false;
> +
> +    RootedObject promiseConstructor(cx, JS_GetConstructor(cx, promise));
> +
> +    JS_SetReservedSlot(promise, PROMISE_STATE_SLOT, NullValue()); // state

See the comment for reject in Promise.js.

@@ +55,5 @@
> +    RootedObject promiseConstructor(cx, JS_GetConstructor(cx, promise));
> +
> +    JS_SetReservedSlot(promise, PROMISE_STATE_SLOT, NullValue()); // state
> +    JS_SetReservedSlot(promise, PROMISE_VALUE_SLOT, NullValue()); // value
> +    JS_SetReservedSlot(promise, PROMISE_DEFERREDS_SLOT, ObjectValue(*JS_NewArrayObject(cx, 0))); // deferreds

The result of calling JS_NewArrayObject needs to be checked: it could fail, just as NewBuiltinClassInstance above could.

However, we really don't want to call JS_NewArrayObject here: it creates an array in the content compartment, with the behavior

@@ +56,5 @@
> +
> +    JS_SetReservedSlot(promise, PROMISE_STATE_SLOT, NullValue()); // state
> +    JS_SetReservedSlot(promise, PROMISE_VALUE_SLOT, NullValue()); // value
> +    JS_SetReservedSlot(promise, PROMISE_DEFERREDS_SLOT, ObjectValue(*JS_NewArrayObject(cx, 0))); // deferreds
> +    JS_SetReservedSlot(promise, PROMISE_CONSTRUCTOR_SLOT, ObjectValue(*promiseConstructor)); // constructor

As explained in Promise.js, I don't think you need this slot. If that's correct, please remove it and change the slot count to 3.

@@ +64,5 @@
> +    argValues.append(ObjectValue(*promise));
> +    argValues.append(fn);
> +    HandleValueArray arr(argValues);
> +
> +    RootedPropertyName name(cx, JS_AtomizeAndPinString(cx, "Promise_init")->asAtom().asPropertyName());

Use Atomize(cx, "Promise_init", 12) here. You also need to check the result because the allocation might fail.

@@ +70,5 @@
> +
> +    if (!GlobalObject::getIntrinsicValue(cx, cx->global(), name, &selfHostedFun))
> +        return false;
> +
> +    JS_CallFunctionValue(cx, promise, selfHostedFun, arr, &initRval);

I *think* this should check for the result of calling the function and return false without setting the return value. Then you can also just return true in the last line.

::: js/src/builtin/Promise.h
@@ +23,5 @@
>  
>  } // namespace js
>  
> +bool
> +PromiseConstructor(JSContext* cx, unsigned argc, Value* vp);

Move this into the js namespace.

::: js/src/builtin/Promise.js
@@ +1,2 @@
>  /* This Source Code Form is subject to the terms of the Mozilla Public
> +* License, v. 2.0. If a copy of the MPL was not distributed with this

Nit: undo this change.

@@ +8,2 @@
>  
> +/* This implementation is by no means complete and is using a polyfill.

Nit: please change the comment format to the following:
/**
 * Text
 * more text
 */

@@ +24,3 @@
>  }
>  
> +MakeConstructible(Handler, {});

Use std_Object_create(null) instead of {} here.

@@ +24,5 @@
>  }
>  
> +MakeConstructible(Handler, {});
> +
> +function Promise_setState(state) {

For all these internal utility functions (the Promise_getFoo, etc ones), I think it'd be much better to explicitly pass in the promise and then just call them: `Promise_getState(promise)`

Also, this "state" is whether the promise was resolved or not, right? In that case, change it to "Promise_setIsResolved", and the getter to "Promise_getIsResolved". (Note: I think I misunderstood this, so the name is probably ok as-is. See the comment for Promise_reject below.)

@@ +30,4 @@
>  }
>  
> +function Promise_getState() {
> +  return UnsafeGetReservedSlot(this, PROMISE_STATE_SLOT);

Use UnsafeGetObjectFromReservedSlot for all object slots and UnsafeGetBooleanFromReservedSlot for bools.

@@ +53,5 @@
> +  return UnsafeGetReservedSlot(this, PROMISE_CONSTRUCTOR_SLOT);
> +}
> +
> +function Promise_init(promise, fn) {
> +  doResolve(fn, resolve.bind(promise), reject.bind(promise));

I don't think using "bind" is ok here. If content changes Function.prototype.bind, that'll change what happens here. Wrap the functions into closures instead: `function() {callFunction(resolve, promise}`. That's better for performance, too.

@@ +56,5 @@
> +function Promise_init(promise, fn) {
> +  doResolve(fn, resolve.bind(promise), reject.bind(promise));
> +}
> +
> +function Promise_all(promises) {

This is supposed to take an iterable, not just arrays. I think it's ok for now to only deal with arrays (and array-likes), but please add a comment mentioning this.

@@ +57,5 @@
> +  doResolve(fn, resolve.bind(promise), reject.bind(promise));
> +}
> +
> +function Promise_all(promises) {
> +  var results = [];

This code is unsafe: it creates an Array with the __proto__ being the content compartment's Array.prototype. If there's a setter defined for an index, that will be called instead of the value being stored in the index.

Also, I think it's best to only call promises.length once, so use something like
var length = promises.length;
var results = NewDenseArray(length);

And change all usages of promises.length below to use length.

@@ +60,5 @@
> +function Promise_all(promises) {
> +  var results = [];
> +  return NewPromise(function (resolve, reject) {
> +    if (promises.length === 0)
> +			return resolve([]);

Change the indentation to spaces, here and everywhere else. In general, check the formatting of all code once again: there are various alignment issues, which I didn't explicitly call out below.

@@ +68,5 @@
> +        if (valueOrPromise && (typeof valueOrPromise === 'object' || IsCallable(valueOrPromise))) {
> +        	var then = valueOrPromise.then;
> +          if (IsCallable(then)) {
> +            callFunction(then, valueOrPromise,
> +              function (valueOrPromise) { resolveChain(index, valueOrPromise); }, reject);

Nit: horizontally align this argument with the beginning of the first argument.

@@ +72,5 @@
> +              function (valueOrPromise) { resolveChain(index, valueOrPromise); }, reject);
> +            return;
> +          }
> +        }
> +        results[index] = valueOrPromise;

Is it ok to not store the result if an exception was thrown? It probably is because it looks like we're not doing anything with the results in that case, but I'm not sure.

@@ +73,5 @@
> +            return;
> +          }
> +        }
> +        results[index] = valueOrPromise;
> +        if (--remaining === 0) {

Can't you just use `index === length - 1` here and get rid of `remaining`?

@@ +80,5 @@
> +      } catch (ex) {
> +        reject(ex);
> +      }
> +    }
> +    for (var i = 0; i < promises.length; i) {

Nit: no braces needed for single-line bodies.

@@ +87,5 @@
> +  });
> +}
> +
> +function Promise_race(values) {
> +  throw new Error("Promise.race is not implemented");

I'm pretty sure this doesn't actually work: the "Error" constructor almost certainly isn't available. Use ThrowTypeError for now, I would say.

@@ +100,5 @@
> +function Promise_resolve(value) {
> +  if (value && typeof value === 'object' &&
> +    callFunction(Promise_getConstructor, value) === this) {
> +    return value;
> +  }

This doesn't do what (IIUC) it should be doing: Promise_getConstructor would only work on actual instances of Promise. For everything else, it would either crash if no reserved slot with that index exists, or return some bogus value. Both are bad.

Also, if you do something like `MyObject.resolve = Promise.resolve` and then call `MyObject.resolve(someValue)`, you're checking if the result of `Promise_getConstructor(someValue)` equals `MyObject`.

I think it'd be best to implement the IsPromise spec function as an intrinsic. The IsTypedArray intrinsic is a good example for how that'd work. Check the definition of that in SelfHosting.cpp and usages in builtin/TypedArray.js.

We don't currently support subclassing of builtins (but efaust is on the case!), so it's probably ok to just return the value of the IsPromise check returns true.

@@ +109,4 @@
>  }
>  
>  function Promise_catch(onRejected) {
> +  return this.then(null, onRejected);

Per spec, this should use `undefined`, not `null`.

@@ +112,5 @@
> +  return this.then(null, onRejected);
> +}
> +
> +function asap(cb) {
> +  cb();

I still don't understand how this works and actually defers execution. Can you add an explanation? Also, it still executes in the same event loop turn instead of in the next one, right? If that's the case, it definitely needs to change, otherwise the semantics of async/await won't be what we want them to be at all.

@@ +116,5 @@
> +  cb();
> +}
> +
> +function handle(deferred) {
> +  var me = this;

Change this to `promise`, and use it everywhere below instead of `this`.

@@ +117,5 @@
> +}
> +
> +function handle(deferred) {
> +  var me = this;
> +  if (callFunction(Promise_getState, this) === null) {

This check will never succeed because the state is always a boolean. Change `null` to `false`.

@@ +140,5 @@
> +    deferred.resolve(returnValue);
> +  });
> +}
> +
> +function doResolve(fn, onFulfilled, onRejected) {

It's not ideal that we have Promise_resolve, doResolve, and resolve. I don't have good suggestions, but names that make it more clear what each of these does would be good. If that turns out to be hard, at the very least we need comments explaining their roles.

@@ +172,5 @@
> +        return;
> +      }
> +    }
> +    callFunction(Promise_setState, this, true);
> +    callFunction(Promise_setValue, this, newValue);

Can't these two calls be moved into "finale", with the values passed in?

@@ +179,5 @@
> +		callFunction(reject, this, ex);
> +	}
> +}
> +
> +function reject(newValue) {

Same issue was with resolve: multiple functions with very similar names. Please either change the names or add comments.

@@ +180,5 @@
> +	}
> +}
> +
> +function reject(newValue) {
> +  callFunction(Promise_setState, this, false);

Hmm, maybe I'm misunderstanding what the state stores. It looks like it starts out with `null`, indicating that it's unresolved, and can change to `true` for resolved and `false` for rejected? If that's the case, please change it to use enum values. Well, the poor-man's version of them, because we don't have enums in JS. Define values in SelfHostingDefines.h like this and use them here and in Promise.cpp:
#define PROMISE_STATE_UNRESOLVED 0
#define PROMISE_STATE_RESOLVED   1
#define PROMISE_STATE_REJECTED   2

@@ +185,5 @@
> +  callFunction(Promise_setValue, this, newValue);
> +  callFunction(finale, this);
> +}
> +
> +function finale() {

I'm not sure I understand what "finale" means. Perhaps "finalize"? That would still not be an ideal name, as it sounds like some destructor thing, which it isn't, really. I don't have a good suggestion, but this name certainly isn't right.

@@ +187,5 @@
> +}
> +
> +function finale() {
> +  var deferreds = callFunction(Promise_getDeferreds, this);
> +  for (var i = 0, len = deferreds.length; i < len; i) {

Nit: no braces needed.

@@ +188,5 @@
> +
> +function finale() {
> +  var deferreds = callFunction(Promise_getDeferreds, this);
> +  for (var i = 0, len = deferreds.length; i < len; i) {
> +    callFunction(handle, this, deferreds[i]);

Is this guaranteed to not throw? I think so, but am not sure. If it is, add a comment noting that so readers can immediately tell that nothing bad can happen here.

@@ +195,4 @@
>  }
>  
>  function Promise_then(onFulfilled, onRejected) {
> +  var me = this;

Change this to "promise".

::: js/src/vm/SelfHosting.cpp
@@ +1387,5 @@
>            CallNonGenericSelfhostedMethod<Is<LegacyGeneratorObject>>, 2, 0),
>      JS_FN("CallStarGeneratorMethodIfWrapped",
>            CallNonGenericSelfhostedMethod<Is<StarGeneratorObject>>, 2, 0),
>  
>      JS_FN("IsWeakSet",               intrinsic_IsWeakSet,               1,0),

Nit: undo this change.

@@ +1392,2 @@
>      JS_FN("NewDenseArray",           intrinsic_NewDenseArray,           1,0),
> +    JS_FN("NewPromise",              intrinsic_NewPromise, 1, 0),

Nit: please align the arguments as in the lines above.

::: js/src/vm/SelfHosting.h
@@ -17,5 @@
>   * Check whether the given JSFunction is a self-hosted function whose
>   * self-hosted name is the given name.
>   */
>  bool IsSelfHostedFunctionWithName(JSFunction* fun, JSAtom* name);
> -

Nit: undo this change.
Attachment #8640672 - Flags: review?(till)
Till, I agree with most of the comments and am about to send a new, fixed patch. I also did a few things to refactor the code. It is actually based on a polyfill taken from GitHub, and it has a few of wrong design patterns (like using null/true/false as tri-state).

I also introduced a quasi-eventloop for deferring calls to setTimeout. I will also want to make setTimeout available to the user as soon as this promise implementation gets accepted.

Moreover, I added some basic test cases for promises.

> Can't you just use `index === length - 1` here and get rid of `remaining`?

I don't think so - there is no guarantee that the promise with the last index in the array will resolve as last. Or maybe I don't understand something?

> This doesn't do what (IIUC) it should be doing: Promise_getConstructor would only work
> on actual instances of Promise. For everything else, it would either crash
> if no reserved slot with that index exists, or return some bogus value. Both are bad.

As far as I read, accessing an unregistered slot just returns an `undefined` value. My implementation of `isPromise` closely follows the one provided in the spec, and it works... are we sure we want to change this?
For now I'm leaving this one as-is.
Attached patch Part 3: Promises implementation (obsolete) — Splinter Review
This fixes all of mentioned issues, except for those which I don't understand/fully agree with. Also I did some work to make code more readable, hopefully enough :)
Attachment #8640672 - Attachment is obsolete: true
Attachment #8643323 - Flags: review?(till)
Currently only a part of async/await grammar is supported:
- Async function statements are supported.
- Await expressions are supported (as regular unary expressions).
All other parts of proposal are probably not supported.
Even the supported parts of implementation may not be 100% compliant with
the grammar. This is to be considered a proof-of-concept implementation.
Attachment #8643351 - Flags: review?(efaustbmo)
Attached patch Part 3: Promises implementation (obsolete) — Splinter Review
I found a bug, fixed that and added a test case.
Attachment #8643323 - Attachment is obsolete: true
Attachment #8643323 - Flags: review?(till)
Attachment #8643790 - Flags: review?(till)
Attached patch Refactor DEFFUN in jits (obsolete) — Splinter Review
Comment on attachment 8640988 [details] [diff] [review]
Part 1: Exclude StoreBuffer.cpp from unified build to prevent build bustage

Already landed separately.
Attachment #8640988 - Attachment is obsolete: true
Attached patch Refactor DEFFUN in jits (obsolete) — Splinter Review
This should fix the baseline stack problems.
Attachment #8650150 - Attachment is obsolete: true
Attached patch Part 4: Parser grammar rules (obsolete) — Splinter Review
Attachment #8643351 - Attachment is obsolete: true
Attachment #8643351 - Flags: review?(efaustbmo)
Attachment #8651233 - Flags: review?(efaustbmo)
Attachment #8651235 - Flags: review?(efaustbmo)
Attachment #8651161 - Attachment is obsolete: true
Attachment #8651237 - Flags: review+
Comment on attachment 8651237 [details] [diff] [review]
Part 6: Refactored JIT DEFFUN (by efaust)

This is not yet r+, if it needs review, we should get it from Jan.
Attachment #8651237 - Flags: review+
Comment on attachment 8651235 [details] [diff] [review]
Part 5: Bytecode and self-hosted wrapper code

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

Cancelling review for now. This patch needs to get the right hunks into the right other patches where it should live. Please repost when that happens.

The parser stuff should go to the parser. The promise stuff should go to the promise patch. Please make a new patch for the DEFFUN refactor, as well.

The emitter sections, however, look pretty good! The self-hosted stuff also seems fine. So the async/await parts of this look fine, but it is parts of several patches sewn together.

::: js/src/builtin/AsyncFunctions.js
@@ +3,5 @@
> + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
> +
> +function AsyncFunction_wrap(genFunction) {
> +  var fun = function() {
> +    return AsyncFunction_start(callFunction(std_Function_apply, genFunction, null, arguments));

we talked about adding the try catch here. We should do that.

::: js/src/builtin/Promise.js
@@ +135,2 @@
>      return value;
> +  } // FIXME this does not properly check if 'value' is a Promise, which it should do.

These changes should split out and go with the ones that till is supposed to review, right?

::: js/src/frontend/BytecodeEmitter.cpp
@@ -998,5 @@
>  bool
>  BytecodeEmitter::emitIndex32(JSOp op, uint32_t index)
>  {
>      MOZ_ASSERT(checkStrictOrSloppy(op));
> -

This blank line and the one above where there intentionally. Let's leave them.

@@ +5887,5 @@
>  bool
> +BytecodeEmitter::emitAsyncWrapper(unsigned index) {
> +    JSAtom* atom = Atomize(cx, "AsyncFunction_wrap", 18);
> +    return (atom != nullptr &&
> +        emitAtomOp(atom, JSOP_GETINTRINSIC) &&

This formatting can't stand. We want more whitespace.

if (!atom)
    return false;

return emitAtomOp(...) &&
       ...;

@@ -7995,5 @@
> -      // so currently we just return "true" as a placeholder.
> -      case PNK_AWAIT:
> -        if(!emit1(JSOP_TRUE))
> -            return false;
> -        break;

This seems like it should not have been in a previous patch, but it's fine.

::: js/src/frontend/Parser.cpp
@@ +2290,5 @@
>  {
>      MOZ_ASSERT_IF(kind == Statement, funName);
>  
> +    if (asyncKind == AsyncFunction)
> +      generatorKind = StarGenerator;

4 spaces indenture, please.

@@ +2785,5 @@
>          !report(ParseStrictError, pc->sc->strict(), null(), JSMSG_STRICT_FUNCTION_STATEMENT))
>          return null();
>  
> +    if (asyncKind == AsyncFunction)
> +      generatorKind = StarGenerator;

and here.

@@ +6308,5 @@
>        case TOK_NAME: {
>          TokenKind next;
> +        TokenKind nextSameLine;
> +
> +        #ifdef NIGHTLY_BUILD

These changes should be in the parser patch, and are stale, right?

::: js/src/vm/Interpreter.cpp
@@ +3493,5 @@
>          goto error;
>  }
>  END_CASE(JSOP_DEFVAR)
>  
> +CASE(JSOP_DEFFUN) {

Please leave this on the next line, like it is everywhere else in this file.
Attachment #8651235 - Flags: review?(efaustbmo)
Attachment #8651235 - Flags: feedback+
Comment on attachment 8651233 [details] [diff] [review]
Part 4: Parser grammar rules

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

Cancelling review in the face of having to rewrite most of this, as per our discussion. The spec changed.
Attachment #8651233 - Flags: review?(efaustbmo)
Attachment #8640998 - Attachment is obsolete: true
Attachment #8656853 - Flags: review+
Attached patch Part 3: Promises implementation (obsolete) — Splinter Review
Attachment #8643790 - Attachment is obsolete: true
Attachment #8643790 - Flags: review?(till)
Attachment #8656862 - Flags: review?(till)
Attached patch Part 4: Parser grammar rules (obsolete) — Splinter Review
Attachment #8651233 - Attachment is obsolete: true
Attachment #8656864 - Flags: review?(efaustbmo)
Attachment #8651235 - Attachment is obsolete: true
Attachment #8656865 - Flags: review?(efaustbmo)
Attachment #8651237 - Attachment is obsolete: true
Attachment #8656862 - Attachment is patch: true
Attachment #8656862 - Attachment mime type: text/x-patch → text/plain
Comment on attachment 8656864 [details] [diff] [review]
Part 4: Parser grammar rules

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

OK, a lot of things went right here:

1) The tests look phenomenal. Very careful, with good coverage.
2) Much of the parsing is good and robust.
3) It all mostly does what it claims to do

But a few things went very wrong.

1) There are tons of little stylistic things. The patch needs some more polish before it can go in. I have tried to note as many as I saw below.
2) There are a few small refactoring things that need to be taken care of (the default await throwing case, removing asyncKind from FunctionBox)
3) We cannot increase the size of JSFunction by a word. We have got to find a way to pack the FunctionAsyncKind.
4) I am dubious that we cannot lazily parse an async function, and I'm not seeing a place where we stash that information in the lazyScript, so I suspect we are getting this wrong.

Because of 3 and 4, I have to cancel review for now. We can talk about how to fix these things on Tuesday, when I'm back in the office. Until then, 1 and 2 seem fairly tractable, if somewhat boring, to churn through and fix.

A more complete review follows.

::: js/src/builtin/ReflectParse.cpp
@@ +1798,5 @@
>                     "defaults", defarray,
>                     "body", body,
>                     "rest", rest,
>                     "generator", isGeneratorVal,
> +                   "async", isAsyncVal,

this will do for now. We may well have to revisit this when esprima writes a spec for async/await support. It is likely to look a lot like this, though, so this should be good.

::: js/src/frontend/BytecodeCompiler.cpp
@@ +312,5 @@
>      RootedFunction fun(cx, evalCaller->functionOrCallerFunction());
>      MOZ_ASSERT_IF(fun->strict(), options.strictOption);
>      Directives directives(/* strict = */ options.strictOption);
>      ObjectBox* funbox = parser->newFunctionBox(/* fn = */ nullptr, fun, &parseContext,
> +                                              directives, fun->generatorKind(), fun->asyncKind());

pre-existing nit: directives should be aligned  with the /*, not the (

@@ +863,5 @@
>          return false;
>  
>      Rooted<JSFunction*> fun(cx, lazy->functionNonDelazifying());
>      MOZ_ASSERT(!lazy->isLegacyGenerator());
> +    ParseNode* pn = parser.standaloneLazyFunction(fun, lazy->strict(), lazy->generatorKind(), SyncFunction);

It's not at all clear to me that this is right. What keeps us from lazily compiling an async function?

::: js/src/frontend/BytecodeEmitter.cpp
@@ +8089,5 @@
>              return false;
>          break;
>  
> +      // PNK_AWAIT handling is not yet implemented,
> +      // so currently we just return "true" as a placeholder.

This is replaced later in this stack. OK.

::: js/src/frontend/FoldConstants.cpp
@@ +1738,5 @@
>          MOZ_ASSERT(!pn->pn_kid->maybeExpr());
>          return true;
>  
> +      case PNK_AWAIT:
> +        return true;

We can do better than this. At least we can Fold() the expression, right?

::: js/src/frontend/FullParseHandler.h
@@ +435,2 @@
>          TokenPos pos(begin, value ? value->pn_pos.end : begin + 1);
> +        return new_<BinaryNode>(isAwait ? PNK_AWAIT : PNK_YIELD, op, pos, value, gen);

Why not just add a new one, newAwaitExpression()? Maybe I will understand why below.

::: js/src/frontend/Parser.cpp
@@ +824,5 @@
>      if (!pc->sc->needStrictChecks())
>          return true;
>  
> +    if (name == context->names().eval || name == context->names().arguments ||
> +      (IsKeyword(name) && name != context->names().await)) {

nit: align (IsKeyword( with name above, and move opening brace to next line.

@@ +860,2 @@
>      ParseNode* pn = statements(YieldIsKeyword);
> +    tokenStream.setAwaitIsKeyword(awaitIsKeyword);

Man, this would have been ugly, otherwise, huh?

@@ +1451,5 @@
>          return nullptr;
>      if (options().selfHostingMode)
>          fun->setIsSelfHostedBuiltin();
> +
> +    fun->setAsyncKind(asyncKind);

If the function holds the asyncKind, then the FunctionBox needn't do so. We can just access it though funbox->function()->asyncKind().

@@ +2411,5 @@
>  {
>      MOZ_ASSERT_IF(kind == Statement, funName);
>  
> +    if (asyncKind == AsyncFunction)
> +        generatorKind = StarGenerator;

Shouldn't this be an assertion instead? functionDef has very specific callers, looks like.

@@ +2453,5 @@
>      tokenStream.tell(&start);
>  
>      while (true) {
> +        if (functionArgsAndBody(inHandling, pn, fun, kind, generatorKind, asyncKind,
> +           directives, &newDirectives))

nit: alignment

@@ +2698,5 @@
>  template <>
>  ParseNode*
>  Parser<FullParseHandler>::standaloneLazyFunction(HandleFunction fun, bool strict,
> +                                                 GeneratorKind generatorKind,
> +                                                 FunctionAsyncKind asyncKind)

but isn't this always SyncFunction, above? I don't get it.

@@ +2819,5 @@
>  #endif
>      }
>  
> +    bool beforeAwaitIsKeyword = tokenStream.getAwaitIsKeyword();
> +    tokenStream.setAwaitIsKeyword(fun->isAsync());

This approach is a little kludgey, but nowhere near as bad as what we do for yield. Nice design.

@@ +2869,5 @@
>  }
>  
>  template <typename ParseHandler>
>  typename ParseHandler::Node
> +Parser<ParseHandler>::functionStmt(YieldHandling yieldHandling, DefaultHandling defaultHandling, FunctionAsyncKind asyncKind)

nit: suspected line length. Ensure that it's <100 characters

@@ +2910,5 @@
>          !report(ParseStrictError, pc->sc->strict(), null(), JSMSG_STRICT_FUNCTION_STATEMENT))
>          return null();
>  
> +    if (asyncKind == AsyncFunction)
> +      generatorKind = StarGenerator;

Right, this supports the assertion claims above.

@@ +5806,5 @@
>      if (!noteNameUse(context->names().dotGenerator, generator))
>          return null();
>      if (isYieldStar)
>          return handler.newYieldStarExpression(begin, expr, generator);
> +    return handler.newYieldExpression(begin, expr, generator, JSOP_YIELD, isAwait);

yeah, this is a mistake. we should instead

if (isAwait)
    return handler.newAwaitExpression(...);
return handler.newYieldExpression(...);

@@ +6426,5 @@
>                  report(ParseError, false, propName, JSMSG_BAD_METHOD_DEF);
>                  return null();
>              }
> +            if (propType == PropertyType::AsyncMethod) {
> +                report(ParseError, false, null(), JSMSG_ASYNC_CONSTRUCTOR);

Uhm...Surely the error above will always be thrown if propType == PropertyType::AsyncMethod, so this code is dead.

@@ +6711,5 @@
>  typename ParseHandler::Node
>  Parser<ParseHandler>::expr(InHandling inHandling, YieldHandling yieldHandling,
>                             InvokedPrediction invoked)
>  {
> +    Node pn = assignExpr(inHandling, yieldHandling, true, invoked);

this |true| needs a /* foo = */ for readability.

@@ +6983,5 @@
>      if (tt == TOK_NAME) {
> +        TokenKind nextSameLine;
> +
> +        #ifdef NIGHTLY_BUILD
> +        if (tokenStream.currentName() == context->names().async &&

nit: alignment of if clauses.

@@ +6997,5 @@
>          if (endsExpr)
>              return identifierName(yieldHandling);
>      }
>  
> +    if (tt == TOK_AWAIT && !awaitAllowed) {

This feels out of place here. It should find a way to live in assignExprWithoutYieldOrAwait, or functionArguments().

@@ +7306,5 @@
>          return handler.newDelete(begin, expr);
>        }
>  
> +      case TOK_AWAIT:
> +          TokenKind nextSameLine;

Does this declaration not warn? Normally, you need a new block. See the default block below.

@@ +7315,5 @@
> +              if (nextSameLine != TOK_EOL) {
> +                 Node kid = unaryExpr(yieldHandling);
> +                  if (!kid)
> +                      return null();
> +                  return newYieldExpression(begin, kid, false, true);

These too need /* isYieldStar = */ and so on.

@@ +8241,3 @@
>      if (res && pc->lastYieldOffset != startYieldOffset) {
>          reportWithOffset(ParseError, false, pc->lastYieldOffset,
>                           msg, js_yield_str);

maybe change that to res->isKind(PNK_AWAIT) ? awaitMsg : yieldMsg, or something? Here is infinitely better than inside assignExpression for the await in default message

@@ +8844,5 @@
>          TokenKind tt;
>          if (!tokenStream.getToken(&tt, TokenStream::KeywordIsName))
>              return null();
> +
> +        if (isAsync && (tt == TOK_NAME || tt == TOK_STRING || tt == TOK_NUMBER || tt == TOK_LB)) {

We can do it cleaner than this. Not looking for accessor syntax on async is enough, right?

Then

async get name() { }

is still a syntax error? It looks like it should be.

@@ +8852,3 @@
>          if (tt == TOK_NAME) {
>              propAtom.set(tokenStream.currentName());
> +

nit: This new line is probably not needed.

@@ +8875,3 @@
>              return newNumber(tokenStream.currentToken());
>          }
> +        if (tt == TOK_LB) {

nit: Please remove the braces. Single line ifs do not need them. The blank line is also unnecessary.

@@ +8932,5 @@
>      }
>  
>      if (tt == TOK_LP) {
>          tokenStream.ungetToken();
> +        *propType = isGenerator ? PropertyType::GeneratorMethod : (

nit: indenting here, with ( on end of previous line is really ugly. Indent it one indenture past the start of isGenerator with the entire last ternary parenthesized.

@@ +9185,2 @@
>          return identifierName(yieldHandling);
> +      }

nit: no need for these braces.

::: js/src/frontend/Parser.h
@@ +127,5 @@
>      bool isGenerator() const { return generatorKind() != NotGenerator; }
>      bool isLegacyGenerator() const { return generatorKind() == LegacyGenerator; }
>      bool isStarGenerator() const { return generatorKind() == StarGenerator; }
>  
> +    bool isAsync() const { return sc->isFunctionBox() && sc->asFunctionBox()->function()->isAsync(); }

This confirms that we can not store the async kind in the function box, as we are already not consulting it.

@@ +519,5 @@
>      }
>  
>      // Use when the funbox should be linked to the outerpc's innermost scope.
>      FunctionBox* newFunctionBox(Node fn, HandleFunction fun, ParseContext<ParseHandler>* outerpc,
> +                                Directives directives, GeneratorKind generatorKind, FunctionAsyncKind asyncKind = SyncFunction)

The last parameter should flow to a third line.

@@ +650,5 @@
>       * Some parsers have two versions:  an always-inlined version (with an 'i'
>       * suffix) and a never-inlined version (with an 'n' suffix).
>       */
> +    Node functionStmt(YieldHandling yieldHandling,
> +      DefaultHandling defaultHandling, FunctionAsyncKind asyncKind);

Please align params after the (

::: js/src/frontend/SharedContext.h
@@ +298,5 @@
>      bool            usesApply:1;      /* contains an f.apply() call */
>      bool            usesThis:1;       /* contains 'this' */
>  
>      FunctionContextFlags funCxFlags;
> +    FunctionAsyncKind asyncKind_;

Unnecessary as discussed.

@@ +335,5 @@
> +    }
> +
> +    bool isAsync() {
> +      return asyncKind() == AsyncFunction;
> +    }

These seem dead. Are they? If so, please remove.

::: js/src/js.msg
@@ +513,5 @@
>  MSG_DEF(JSMSG_CANT_DELETE_SUPER, 0, JSEXN_REFERENCEERR, "invalid delete involving 'super'")
> +
> +// Promise
> +MSG_DEF(JSMSG_PROMISE_RESOLVED_WITH_ITSELF, 0, JSEXN_TYPEERR, "A promise cannot be resolved with itself")
> +MSG_DEF(JSMSG_SETTIMEOUT_INTERVAL_NONZERO, 0, JSEXN_TYPEERR, "Intervals other than 0 are not supported")

These don't belong in this patch, still, probably.

::: js/src/jsfun.h
@@ +139,5 @@
>          } i;
>          void*           nativeOrScript;
>      } u;
>      js::HeapPtrAtom  atom_;       /* name for diagnostics and decompiling */
> +    js::FunctionAsyncKind   asyncKind_;

OK, there's no way we can afford to do this. There are /way/ too many functions in the world to make them all a word larger. It's one bit. We need to find a way to fit it into the union above.

::: js/src/tests/ecma_7/AsyncFunctions/syntax.js
@@ +5,5 @@
> +/**
> + * Currently only a part of async/await grammar is supported:
> + * - Async function statements are supported.
> + * - Await expressions are supported (as regular unary expressions).
> + * All other parts of proposal are probably not supported.

This isn't even true! :)

@@ +53,5 @@
> +assertThrows(() => Reflect.parse("async function a() { return await; }"), SyntaxError);
> +
> +// Yield is not allowed in an async function / treated as identifier
> +assertThrows(() => Reflect.parse("async function a() { yield 3; }"), SyntaxError);
> +assertThrows(() => Reflect.parse("async function a() { return yield 3; }"), SyntaxError);

also throw in a test for var yield = 5, just for completeness

@@ +62,5 @@
> +
> +// Await is treated differently depending on context. Various cases.
> +Reflect.parse("var await = 3; async function a() { await 4; }");
> +Reflect.parse("async function a() { await 4; } var await = 5");
> +Reflect.parse("async function a() { function b() { return await; } }");

I can't believe this nonsense is specced to work. Blech. Nice test.

::: js/src/vm/Xdr.h
@@ +32,5 @@
>  static const uint32_t XDR_BYTECODE_VERSION_SUBTRAHEND = 306;
>  static const uint32_t XDR_BYTECODE_VERSION =
>      uint32_t(0xb973c0de - XDR_BYTECODE_VERSION_SUBTRAHEND);
>  
> +static_assert(JSErr_Limit == 416,

When this goes up, the subtrahend must also. Please increment the number above.
Attachment #8656864 - Flags: review?(efaustbmo)
Comment on attachment 8656865 [details] [diff] [review]
Part 5: Bytecode and self-hosted wrapper code

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

Looks good! r=me with questions below answered, and tests guarded.

::: js/src/Makefile.in
@@ +285,5 @@
>  
>  selfhosting_srcs := \
>    $(srcdir)/builtin/Utilities.js \
>    $(srcdir)/builtin/Array.js \
> +	$(srcdir)/builtin/AsyncFunctions.js \

nit: alignment.

::: js/src/builtin/AsyncFunctions.js
@@ +3,5 @@
> + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
> +
> +function AsyncFunction_wrap(genFunction) {
> +  var fun = function() {
> +    try {

Please add a comment here that the try/catch is for function defaults throwing.

@@ +24,5 @@
> +function AsyncFunction_resume(gen, v, method) {
> +    let result;
> +    try {
> +      result = callFunction(method, gen, v);
> +      // get back into async function, run to next await point

nit: This should move to above the line of code it describes.

::: js/src/frontend/BytecodeEmitter.cpp
@@ +2002,5 @@
>          return true;
>  
>        case PNK_YIELD_STAR:
>        case PNK_YIELD:
> +      case PNK_AWAIT:

Oooops. Yes. Should this go in the previous patch?

@@ +5970,5 @@
> +BytecodeEmitter::emitAsyncWrapper(unsigned index, bool needsHomeObject) {
> +    JSAtom* atom = Atomize(cx, "AsyncFunction_wrap", 18);
> +    if (!atom)
> +        return false;
> +    if (needsHomeObject && !emitIndex32(JSOP_LAMBDA, index))

Please add a comment here describing the handshake with propertyList() and why we are doing it in that order.

@@ +7176,5 @@
>              propdef->pn_right->pn_funbox->needsHomeObject())
>          {
>              MOZ_ASSERT(propdef->pn_right->pn_funbox->function()->allowSuperProperty());
> +            bool isAsync = propdef->pn_right->pn_funbox->function()->isAsync();
> +            if (isAsync && !emit1(JSOP_SWAP))

Maybe the comment should actually live here, and above should be "see comment in propertyList()", or visa versa. Either way.

::: js/src/shell/js.cpp
@@ +1582,5 @@
> +        return false;
> +
> +    args.rval().set(rval);
> +    return true;
> +}

Are these impls not mandatory to getting the promise code working? Maybe just testing functions?

::: js/src/tests/ecma_7/AsyncFunctions/1.1.1.js
@@ +12,5 @@
> +assertThrowsSE("async function a() { super.prop(); }");
> +assertThrowsSE("async function a() { super(); }");
> +
> +// FIXME this should work
> +// assertThrowsSE("async function a(k = await 3) {}");

Why doesn't this work? Does it work now?

::: js/src/tests/ecma_7/AsyncFunctions/1.1.2.js
@@ +6,5 @@
> +
> +var anon = async function() { }
> +
> +assertEq(test.name, "test");
> +assertEq(anon.name, "");

Nice test.

::: js/src/tests/ecma_7/AsyncFunctions/methods.js
@@ +46,5 @@
> +  assertEventuallyEq(y.getBaseClassName(), 'X'),
> +]).then(() => {
> +  if (typeof reportCompare === "function")
> +      reportCompare(true, true);
> +});

All these tests need some kind of mechanism guarding them against failure when the code is no longer on nightly. When the nightly branch merges to Aurora (dev edition), these will start to fail, because neither classes nor async functions will parse.

::: js/src/tests/ecma_7/AsyncFunctions/semantics.js
@@ +91,5 @@
> +  return n !== 0 && await isEven(n - 1);
> +}
> +
> +// recursion, take three!
> +// FIXME this example doesn't work...

I thought you had showed me this working? It's certainly not commented out, so...

::: js/src/vm/GeneratorObject.cpp
@@ +61,5 @@
>  bool
>  GeneratorObject::suspend(JSContext* cx, HandleObject obj, AbstractFramePtr frame, jsbytecode* pc,
>                           Value* vp, unsigned nvalues)
>  {
> +    MOZ_ASSERT(*pc == JSOP_INITIALYIELD || *pc == JSOP_YIELD || *pc == JSOP_GENERATOR);

How can /that/ happen? Can it?

::: js/src/vm/ScopeObject.cpp
@@ +237,5 @@
>       */
>      if (callee->isNamedLambda()) {
> +        if (callee->isAsync()) {
> +            RootedFunction fun(cx, &callee->getExtendedSlot(1).toObject().as<JSFunction>());
> +            scopeChain = DeclEnvObject::create(cx, scopeChain, fun);

A beautiful hack :P
Attachment #8656865 - Flags: review?(efaustbmo) → review+
Comment on attachment 8656866 [details] [diff] [review]
Part 6: Refactored JIT DEFFUN (by efaust)

This is really part of part 5, but I wrote it, so I can't review it.

The purpose is to make JSOP_DEFFUN take the function value from the stack, instead of from the bytecode stream.
Attachment #8656866 - Flags: review?(jdemooij)
Comment on attachment 8656866 [details] [diff] [review]
Part 6: Refactored JIT DEFFUN (by efaust)

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

::: js/src/jit/BaselineCompiler.cpp
@@ +2473,5 @@
>  
>  bool
>  BaselineCompiler::emit_JSOP_DEFFUN()
>  {
> +

Uber nit: remove this empty line.
Attachment #8656866 - Flags: review?(jdemooij) → review+
Attachment #8656853 - Attachment is obsolete: true
Attached patch Part 3: Promises implementation (obsolete) — Splinter Review
Attachment #8662651 - Flags: review?(till)
Attached patch Part 4: Parser grammar rules (obsolete) — Splinter Review
Attachment #8656864 - Attachment is obsolete: true
Attachment #8662652 - Flags: review?(efaustbmo)
Attachment #8656865 - Attachment is obsolete: true
Attachment #8662653 - Flags: review?(efaustbmo)
Attachment #8656866 - Attachment is obsolete: true
Attachment #8662654 - Flags: review?(efaustbmo)
Attachment #8656862 - Attachment is obsolete: true
Attachment #8656862 - Flags: review?(till)
Comment on attachment 8662651 [details] [diff] [review]
Part 3: Promises implementation

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

My deepest apologies for sitting on this for so long! Given that you're leaving, please do the barest minimum of what I'm asking below, and I'll pick it up from there.

The most important part is documentation of how things work. Mostly, that means explanations of the roles of the SLOTs on Promise instances: what do they do, how are they used? Also, much of the code isn't exactly self-explanatory, and it would be a great help to have some targeted comments in there.

Next is making this all tamper-proof. Right now, content code can change Promises' behavior by changing methods on Array instances. It's very important to ensure that whatever content code does, the behavior of builtins stays as it is intended to be.

I didn't look at the patches that actually introduce async/await, so ignore this if it doesn't apply, but: if the async/await implementation retrieves the Promise constructor from the current global and uses its methods, then it isn't tamper-proof in the same way. The best thing to do there would be to somehow stash the original value somewhere (for both the constructor and the set of methods used, which then should be invoked using callFunction), or use an internal version of promises that isn't affected by things being done to window.Promise.

Finally, I think it'd make sense to only expose this with an environment var set or something like that. Unconditionally landing it even in Nightly seems a bit risky, given that it's not tamper-proof right now. But again, I'm willing to pick it up and drive it in.

::: js/src/builtin/Promise.cpp
@@ +6,5 @@
>  
>  #include "builtin/Promise.h"
>  
>  #include "jscntxt.h"
> +#include "SelfHostingDefines.h"

This needs to be "builtin/SelfHostingDefines.h", and be moved up to below the Promise.h include.

::: js/src/builtin/Promise.js
@@ +20,5 @@
> + * this setTimeout implementation must be manually triggered by calling
> + * runEvents().
> + */
> +
> +var eventQueue = [];

Use `new List()` here. That way, the queue's behavior can't be changed by modifying Array.prototype. With the current implementation, content code could derail the Promise implementation by changing Array.prototype.push/pop.

@@ +24,5 @@
> +var eventQueue = [];
> +
> +function runEvents() {
> +  while (eventQueue.length > 0) {
> +    //var evt = eventQueue.pop();

Remove this line. (And the empty one below it.)

@@ +100,5 @@
> +}
> +
> +function Promise_all(promises) {
> +  var length = promises.length;
> +  var results = NewDenseArray(length);

This should just use `[]` instead of NewDenseArray. Below, the `results[index] = ..` should be replaced with `_DefineDataProperty(results, index, valueOrPromise)`. Then just remove the `NewDenseArray` function.

Right now, changing Array.prototype.push would again break Promise's behavior.

@@ +135,5 @@
> +    reject(value);
> +  });
> +}
> +
> +function Promise_resolve(value) {

What happens if you do this?

function Foo() {}
Foo.prototype.resolve = Promise.prototype.resolve;
var foo = new Foo();
foo.resolve();

I *think* it should assert in a debug build.
Attachment #8662651 - Flags: review?(till)
> Foo.prototype.resolve = Promise.prototype.resolve;
It's a static function Promise.resolve - not Promise.prototype.resolve. You can change it but it's all right, isn't it?

I addressed all of your comments and you're right - it's possible to break the implementation of async functions by tampering with Promise prototype. Fortunately it looks like it's easy to fix.
Comment on attachment 8662652 [details] [diff] [review]
Part 4: Parser grammar rules

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

Much better, just a few little nits.

::: js/src/builtin/ReflectParse.cpp
@@ +3113,5 @@
>        case PNK_INSTANCEOF:
>          return leftAssociate(pn, dst);
>  
>        case PNK_POW:
> +	      return rightAssociate(pn, dst);

nit: remove bogus indent

::: js/src/frontend/BytecodeCompiler.cpp
@@ +312,5 @@
>      RootedFunction fun(cx, evalCaller->functionOrCallerFunction());
>      MOZ_ASSERT_IF(fun->strict(), options.strictOption);
>      Directives directives(/* strict = */ options.strictOption);
>      ObjectBox* funbox = parser->newFunctionBox(/* fn = */ nullptr, fun, &parseContext,
> +                                              directives, fun->generatorKind(), fun->asyncKind());

nit: 'd' under '/', please

@@ +863,5 @@
>          return false;
>  
>      Rooted<JSFunction*> fun(cx, lazy->functionNonDelazifying());
>      MOZ_ASSERT(!lazy->isLegacyGenerator());
> +    ParseNode* pn = parser.standaloneLazyFunction(fun, lazy->strict(), lazy->generatorKind(), SyncFunction);

This is still wrong, right? this should be lazy->asyncKind()

::: js/src/frontend/Parser.cpp
@@ +1456,5 @@
>                   : JSFunction::INTERPRETED_GENERATOR);
>      }
>  
> +    if (asyncKind == AsyncFunction) {
> +        allocKind = gc::AllocKind::FUNCTION_EXTENDED;

A comment here being like

// We store the async wrapper in a slot for later access

would be nice

@@ -2654,5 @@
>          return false;
>  
>      if (!leaveFunction(pn, outerpc, kind))
>          return false;
> -

nit: please don't remove this line

@@ +2927,5 @@
>          !report(ParseStrictError, pc->sc->strict(), null(), JSMSG_STRICT_FUNCTION_STATEMENT))
>          return null();
>  
> +    if (asyncKind == AsyncFunction)
> +      generatorKind = StarGenerator;

nit: 4 space indent

@@ +7542,5 @@
> +      case TOK_AWAIT:
> +      {
> +          TokenKind nextSameLine;
> +
> +          #ifdef NIGHTLY_BUILD

nit: #ifdef always fully unindented to the far left

@@ +7550,5 @@
> +                 Node kid = unaryExpr(yieldHandling);
> +                  if (!kid)
> +                      return null();
> +                  return newYieldExpression(begin, kid, /* isYieldStar = */ false, /* isAwait = */ true);
> +            } else {

nit: indenture here makes little sense.

@@ +8475,5 @@
> +    if (!tokenStream.peekToken(&tt, TokenStream::Operand))
> +        return null();
> +
> +    if (tt == TOK_AWAIT) {
> +        report(ParseError, false, null(), JSMSG_AWAIT_IN_DEFAULT);

Yeah. This is much better. Thanks :)

::: js/src/frontend/Parser.h
@@ +657,5 @@
>       */
> +    Node functionStmt(YieldHandling yieldHandling,
> +      DefaultHandling defaultHandling, FunctionAsyncKind asyncKind);
> +    Node functionExpr(InvokedPrediction invoked = PredictUninvoked,
> +      FunctionAsyncKind asyncKind = SyncFunction);

Indenture here still wrong

::: js/src/frontend/SyntaxParseHandler.h
@@ +282,5 @@
>      bool addPropertyDefinition(Node literal, Node name, Node expr) { return true; }
>      bool addShorthand(Node literal, Node name, Node expr) { return true; }
>      bool addObjectMethodDefinition(Node literal, Node name, Node fn, JSOp op) { return true; }
>      bool addClassMethodDefinition(Node literal, Node name, Node fn, JSOp op, bool isStatic) { return true; }
> +    Node newYieldExpression(uint32_t begin, Node value, Node gen, JSOp op) { return NodeUnparenthesizedYieldExpr; }

why did this grow a JSOp?

::: js/src/jsfun.h
@@ +285,5 @@
>          flags_ |= RESOLVED_NAME;
>      }
>  
> +    void setAsyncKind(js::FunctionAsyncKind asyncKind) {
> +        if (isInterpretedLazy())

We talked about your fix here. That's fine.
Attachment #8662652 - Flags: review?(efaustbmo) → review+
Comment on attachment 8662653 [details] [diff] [review]
Part 5: Bytecode and self-hosted wrapper code

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

Looks good to me. Going to ask Till to look over AsyncFunctions.js, just to be sure his fears from his last review are assuaged.

::: js/src/frontend/BytecodeCompiler.cpp
@@ +863,5 @@
>          return false;
>  
>      Rooted<JSFunction*> fun(cx, lazy->functionNonDelazifying());
>      MOZ_ASSERT(!lazy->isLegacyGenerator());
> +    ParseNode* pn = parser.standaloneLazyFunction(fun, lazy->strict(), lazy->generatorKind(), lazy->asyncKind());

Ah, this fix is here! OK. That's fine, then.

::: js/src/frontend/Parser.cpp
@@ +2639,5 @@
>          return false;
>  
>      if (!functionArgsAndBodyGeneric(inHandling, yieldHandling, pn, fun, kind))
>          return false;
> +    

nit: whitespace on empty line

::: js/src/shell/js.cpp
@@ +998,5 @@
>  static bool
>  CacheEntry_setBytecode(JSContext* cx, HandleObject cache, uint8_t* buffer, uint32_t length)
>  {
>      MOZ_ASSERT(CacheEntry_isCacheEntry(cache));
> +  

nit: whitespace on empty line
Attachment #8662653 - Flags: review?(efaustbmo)
Attachment #8662653 - Flags: review+
Attachment #8662653 - Flags: feedback?(till)
Comment on attachment 8662654 [details] [diff] [review]
Part 6: Refactored JIT DEFFUN (by efaust)

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

Carrying Jandem's review. I cannot review this, as I wrote it.
Attachment #8662654 - Flags: review?(efaustbmo) → review+
(In reply to mkierski from comment #49)
> > Foo.prototype.resolve = Promise.prototype.resolve;
> It's a static function Promise.resolve - not Promise.prototype.resolve. You
> can change it but it's all right, isn't it?

Oh, right. In that case: what happens if you pass in an arbitrary object, like {}? Normal objects shouldn't have 4 reserved slots, so this should assert.

> I addressed all of your comments and you're right - it's possible to break
> the implementation of async functions by tampering with Promise prototype.
> Fortunately it looks like it's easy to fix.

Excellent. Self-hosted JS is simple on the surface, and quite finicky in the details, unfortunately.
Comment on attachment 8662653 [details] [diff] [review]
Part 5: Bytecode and self-hosted wrapper code

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

Looks good except for the comments below. Plus: this now always uses the self-hosted implementation of Promises. That's fine, as long as that doesn't interfere with the browser's implementation. What's more problematic is that even the SpiderMonkey-implementation relies on a browser-provided builtin: setTimeout. That can again be changed by content, wreaking havoc on async/await, IINM. To verify: what happens if you do `window.setTimeout = function() {throw "bazinga"}` and then use async/await in that window? If that works fine, great. If not, we need to somehow store the original value of `setTimeout` - or use the same fake implementation as in the shell. In the latter case, move it from a shell builtin to a self-hosting intrinsic and just use it like Promise_foo. That means async/await don't work any better in the browser than in the shell, but at least it should work exactly the same.

f+ with this feedback addressed.

::: js/src/builtin/AsyncFunctions.js
@@ +36,5 @@
> +      return Promise_resolve(result.value);
> +    }
> +
> +    // If we get here, `await` occurred. `gen` is paused at a yield point.
> +    return Promise_resolve(result.value).then(

This still isn't right: Promise.prototype.then can be change by content, changing the behavior here. `return callFunction(Promise_then, Promise_resolve(result.value), ...)` should fix that.

Note that I'm not well-versed enough in the details of promises to know whether the `result.value` and similar things are ok. It seems so, but I'm not sure.

::: js/src/vm/SelfHosting.cpp
@@ +1239,5 @@
> +intrinsic_SetFunctionExtendedSlot(JSContext* cx, unsigned argc, Value* vp)
> +{
> +    CallArgs args = CallArgsFromVp(argc, vp);
> +    MOZ_ASSERT(args.length() == 3);
> +    MOZ_ASSERT(args[0].isObject());

Uber-nit: this assert isn't required, because it's contained in `toObject` in the line below. Feel free to ignore.
Attachment #8662653 - Flags: feedback?(till) → feedback+
Attached patch Rolled up testing patch (obsolete) — Splinter Review
STR

open dev console

async function() a { }
run |a().then(console.log)| until assertion failure
(In reply to mkierski from comment #55)
> Created attachment 8665172 [details] [diff] [review]
> Rolled up testing patch
> 
> STR
> 
> open dev console
> 
> async function() a { }
> run |a().then(console.log)| until assertion failure

I pared this down to |a()| until failure, just to simplify.

The problem is that the clone of AsyncFunction_Wrap in the content compartment is relazified, despite having an internal function, which escapes.

I have the following evidence for this:

Program received signal SIGSEGV, Segmentation fault.
0x00007fffe7d7ef1e in JSFunction::needsCallObject (this=0x7fffb130ebf0) at /home/efaust/m-classes/js/src/jsfun.h:148
148	        MOZ_ASSERT(!isInterpretedLazy());
(gdb) where
#0  0x00007fffe7d7ef1e in JSFunction::needsCallObject() const (this=0x7fffb130ebf0) at /home/efaust/m-classes/js/src/jsfun.h:148
#1  0x00007fffe7d91c01 in js::StaticScopeIter<(js::AllowGC)0>::hasSyntacticDynamicScopeObject() const (this=0x7fffffff18b0) at /home/efaust/m-classes/js/src/vm/ScopeObject-inl.h:107
#2  0x00007fffe7f052a5 in AssertDynamicScopeMatchesStaticScope(JSContext*, JSScript*, JSObject*) (cx=0x7fffd7e44500, script=0x7fffc16af8b0, scope=0x7fffb1306600) at /home/efaust/m-classes/js/src/vm/Stack.cpp:150
#3  0x00007fffe7f058bb in js::InterpreterFrame::prologue(JSContext*) (this=0x7fffd486e4e8, cx=0x7fffd7e44500) at /home/efaust/m-classes/js/src/vm/Stack.cpp:218
#4  0x00007fffe7e5352b in Interpret(JSContext*, js::RunState&) (cx=0x7fffd7e44500, state=...) at /home/efaust/m-classes/js/src/vm/Interpreter.cpp:1952
#5  0x00007fffe7e4f282 in js::RunScript(JSContext*, js::RunState&) (cx=0x7fffd7e44500, state=...) at /home/efaust/m-classes/js/src/vm/Interpreter.cpp:709
#6  0x00007fffe7e4f733 in js::Invoke(JSContext*, JS::CallArgs const&, js::MaybeConstruct) (cx=0x7fffd7e44500, args=..., construct=js::NO_CONSTRUCT) at /home/efaust/m-classes/js/src/vm/Interpreter.cpp:786
BACKTRACE CONTINUES

(gdb) up
#2  0x00007fffe7f052a5 in AssertDynamicScopeMatchesStaticScope (cx=0x7fffd7e44500, script=0x7fffc16af8b0, scope=0x7fffb1306600) at /home/efaust/m-classes/js/src/vm/Stack.cpp:150
150	        } else if (i.hasSyntacticDynamicScopeObject()) {
(gdb) p enclosingScope.get()->as<JSFunction>().isInterpretedLazy()
$13 = true
(gdb) p enclosingScope.get()
$14 = (JSObject * const&) @0x7fffffff18d0: 0x7fffb130ebf0
(gdb) p i.obj()
Invalid data type for function to be called.
(gdb) p i.obj
$15 = {<js::RootedBase<JSObject*>> = {<No data fields>}, ptr = 0x7fffb130ebf0}
(gdb) p i.obj.get()
$16 = (JSObject * const&) @0x7fffffff18b0: 0x7fffb130ebf0

|enclosingScope| here is args.callee()->nonLazyScript()->enclosingStaticScope(), in terms of the Invoke call.

So it's the immediately enclosing function to the one being called that got delazified, which is AsyncFunction_Wrap in this case.

One fix, which Mariusz found, was to make a function CreateAsyncWrapper() that's called by AsyncFunction_Wrap(). This will ensure that the version in the selfhosted compartment is always delazified and avoid this bug, but it seems bad to evade it.

All told, it seems way more likely that we want to do some checks and respect the doNotRelazify_ flag here in some way, but it's late and I'm not going to find the exact right spot.

ni? till as he said he would take up the torch tomorrow to fix the rest of this. It should be fairly easy for someone familiar with the code, I would think.
Flags: needinfo?(till)
Shell test case:

var g = newGlobal();
g.eval("async function a(){ }");
gc();
g.a();
Depends on: 1208067
Tested, this one works.
Attachment #8662650 - Attachment is obsolete: true
Attachment #8665559 - Flags: review+
Attachment #8665559 - Attachment is obsolete: true
Attachment #8665561 - Flags: review?(till)
Attached patch Part 2: Promises implementation (obsolete) — Splinter Review
Attachment #8662651 - Attachment is obsolete: true
Attachment #8665562 - Flags: review?(till)
Attached patch Part 3: Parser grammar rules (obsolete) — Splinter Review
Attachment #8662652 - Attachment is obsolete: true
Attachment #8665572 - Flags: review?(efaustbmo)
Attachment #8662653 - Attachment is obsolete: true
Attachment #8665574 - Flags: review?(efaustbmo)
Attachment #8662654 - Attachment is obsolete: true
Comment on attachment 8665561 [details] [diff] [review]
Part 1: (till) Promises boilerplate

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

I think we can just carry efaust's r+ here, as it's just a straight rename. Please fix the author information and append r=efaust to the description before landing.
Attachment #8665561 - Flags: review?(till) → review+
Comment on attachment 8665562 [details] [diff] [review]
Part 2: Promises implementation

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

Looks good by and large. r=me with the feedback addressed.

The {Set,Get}FunName intrinsics introduced here (and presumably used in the next patches) shouldn't be required: _DefineDataProperty(myFunction, "name", "myName") *should* work. And just using `var name = myFunction.name` for getting the name should, too.

::: js/src/builtin/Promise.cpp
@@ +33,5 @@
>      CallArgs args = CallArgsFromVp(argc, vp);
>  
>      JSObject* obj = NewBuiltinClassInstance(cx, &ShellPromiseObject::class_);
>      if (!obj)
>          return false;

These three lines snuck back in: the last version of the patch correctly removed them.

@@ +55,5 @@
> +        return false;
> +
> +    JSObject* deferredsArray = JS_NewArrayObject(cx, 0);
> +    if (!deferredsArray)
> +        return false;

Oh, I didn't see that this was wrong in the last version, good catch.

@@ +57,5 @@
> +    JSObject* deferredsArray = JS_NewArrayObject(cx, 0);
> +    if (!deferredsArray)
> +        return false;
> +
> +    JS_SetReservedSlot(promise, PROMISE_STATE_SLOT, NumberValue(PROMISE_STATE_PENDING)); // state

The comments for these three lines should be dropped: they just repeat what the code says.

@@ +59,5 @@
> +        return false;
> +
> +    JS_SetReservedSlot(promise, PROMISE_STATE_SLOT, NumberValue(PROMISE_STATE_PENDING)); // state
> +    JS_SetReservedSlot(promise, PROMISE_VALUE_SLOT, NullValue()); // value
> +    JS_SetReservedSlot(promise, PROMISE_DEFERREDS_SLOT, ObjectValue(*deferredsArray)); // deferreds

I just realize that this slot is set in the self-hosted Promise_init, too. Given that, just replace this with `NullValue()` (and the creation of `deferredsArray` above). We could do it in either place, except the self-hosted version can use the internal `List` class which content can't modify.

@@ +94,5 @@
>      return cx->global()->createBlankPrototype(cx, &ShellPromiseObject::protoClass_);
>  }
>  
>  const Class ShellPromiseObject::class_ = {
> +   "ShellPromise",

Nit: revert this change.

@@ +108,5 @@
>      nullptr, /* finalize */
>      nullptr, /* call */
>      nullptr, /* hasInstance */
>      nullptr, /* construct */
> +    nullptr, /* trace  */

Nit: revert this change.

::: js/src/builtin/Promise.h
@@ +17,5 @@
>  {
>    public:
> +     static const unsigned RESERVED_SLOTS = 3;
> +     static const Class class_;
> +     static const Class protoClass_;

These three lines were somehow indented one space further. Please revert.

::: js/src/builtin/Promise.js
@@ +24,5 @@
> +var eventQueue = new List();
> +
> +function runEvents() {
> +  while (eventQueue.length > 0) {
> +    var evt = callFunction(std_Array_pop, eventQueue);

With `eventQueue` being a list now, .pop can just be called normally. However, it's probably clearer to still use callFunction, so leave this as-is.

@@ +71,5 @@
> +  return UnsafeGetReservedSlot(promise, PROMISE_VALUE_SLOT);
> +}
> +
> +function Promise_init(promise, fn) {
> +  Promise_setDeferreds(promise, []);

Use `new List()` here instead of [].

@@ +125,5 @@
> +}
> +
> +function Promise_resolve(value) {
> +  if (value && typeof value === 'object' &&
> +    IsPromise(value)) {

This should all fit into one line. Then, the braces can be left off.

::: js/src/vm/SelfHosting.cpp
@@ +1241,5 @@
>      return true;
>  }
>  
> +bool
> +intrinsic_SetFunctionExtendedSlot(JSContext* cx, unsigned argc, Value* vp)

This intrinsic isn't used in the patch. Is it used in a consecutive patch? If so, it's ok to keep, but if not, please remove.
Attachment #8665562 - Flags: review?(till) → review+
Oh, one thing I forgot: I still would really like to see documentation of how all this works. Either in one big block comment in Promise.js, or spread out over various comments in the complicated places.
Flags: needinfo?(till)
Attached patch Part 2: Promises implementation (obsolete) — Splinter Review
Attachment #8665562 - Attachment is obsolete: true
Comment on attachment 8665575 [details] [diff] [review]
Part 5: Refactored JIT DEFFUN (by efaust)

Carrying jandem's r+
Attachment #8665575 - Flags: review+
Comment on attachment 8665678 [details] [diff] [review]
Part 2: Promises implementation

Carrying till's r+
Attachment #8665678 - Flags: review+
Comment on attachment 8665572 [details] [diff] [review]
Part 3: Parser grammar rules

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

Carrying. This did not require additional review.
Attachment #8665572 - Flags: review?(efaustbmo) → review+
Comment on attachment 8665574 [details] [diff] [review]
Part 4: Bytecode and self-hosted wrapper code

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

Carrying. This did not require additional review.
Attachment #8665574 - Flags: review?(efaustbmo) → review+
Lots of context, by request
Attachment #8668698 - Flags: review?(jwalden+bmo)
Comment on attachment 8668698 [details] [diff] [review]
Part 6: Clean up the NIGHTLY_ONLY guards for the feature, and allow tests to uplift cleanly

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

I'd prefer putting JS_HAS_ASYNC_FUNCS directly into code as a condition, so that async-handling code always builds and can't be accidentally broken for an uplift where it gets turned off again, but this is somewhat of a nit.

::: js/src/tests/ecma_7/AsyncFunctions/methods.js
@@ +59,5 @@
> +
> +`;
> +
> +if (classesEnabled() && asyncFunctionsEnabled())
> +    eval(test);

inb4philor

::: js/src/tests/ecma_7/AsyncFunctions/shell.js
@@ +30,5 @@
> +    try {
> +        eval("async function f()  { }");
> +        return true;
> +    } catch (e if e instanceof SyntaxError) {
> +        return false;

Use

  if (e instanceof SyntaxError)
    return false;
  throw e;

to avoid non-standard syntax

::: js/src/tests/shell.js
@@ +871,5 @@
>      fullmsg += " - " + msg;
>    throw new Error(fullmsg);
>  };
>  
> +function classesEnabled(testCode = "class Foo { constructor() {} }") {

Hmm, doesn't this want to be removed from ecma_6/shell.js or wherever it is?
Attachment #8668698 - Flags: review?(jwalden+bmo) → review+
Flags: needinfo?(efaustbmo)
Attachment #8671058 - Flags: review?(ehsan)
Attachment #8671058 - Flags: review?(ehsan) → review+
Depends on: 1212656
What's the status of this project now? It seems Blink started working on this now: https://groups.google.com/a/chromium.org/d/msg/blink-dev/jlSoAmWa1i4/7xowBIOSBAAJ
These patches are waiting on the spidermonkey promises work that till is doing. There is a lot of interest in getting it finished an in, and that will happen as soon as we can.
will take this over :)
now rebasing and testing
looks like some parts of the spec are not implemented or doesn't match.
  * async arrow functions
  * export default async function

I guess the spec had been updated since then.
now fixing those parts
efaust, do you know the purpose of the following Early Error rule?

https://tc39.github.io/ecmascript-asyncawait/#async-decls-exprs-static-semantics-early-errors
> * It is a Syntax Error if ContainsUseStrict of AsyncFunctionBody is true and IsSimpleParameterList of FormalParameters is false.

IIUC, it means the following code throws SyntaxError, but I'm not sure why it should.

  async function f(a = 1) { `use strict`; }

as following doesn't throw SyntaxError:

  `use strict`; async function f(a = 1) {}
Flags: needinfo?(efaustbmo)
(In reply to Tooru Fujisawa [:arai] from comment #90)
> efaust, do you know the purpose of the following Early Error rule?
> 
> https://tc39.github.io/ecmascript-asyncawait/#async-decls-exprs-static-
> semantics-early-errors
> > * It is a Syntax Error if ContainsUseStrict of AsyncFunctionBody is true and IsSimpleParameterList of FormalParameters is false.
> 
> IIUC, it means the following code throws SyntaxError, but I'm not sure why
> it should.
> 
>   async function f(a = 1) { `use strict`; }
> 
> as following doesn't throw SyntaxError:
> 
>   `use strict`; async function f(a = 1) {}

Sorry, just noticed that it's just same as sync function's case, and SpiderMonkey haven't yet implemented it.
https://tc39.github.io/ecma262/#sec-function-definitions-static-semantics-early-errors
Flags: needinfo?(efaustbmo)
See Also: → 1272784
Attached patch Part 1: Refactor JSOP_DEFFUN. (obsolete) — Splinter Review
Separated JSOP_DEFFUN refactoring from previous Part 3, and merged with Part 5.
Attachment #8665172 - Attachment is obsolete: true
Attachment #8665561 - Attachment is obsolete: true
Attachment #8665575 - Attachment is obsolete: true
Attachment #8665678 - Attachment is obsolete: true
Attachment #8671058 - Attachment is obsolete: true
Attachment #8753179 - Flags: review+
Rebased previous Part 3, and merged parser part of previous Part 6.
JS_HAS_ASYNC_FUNCS is defined only if SPIDERMONKEY_PROMISE is defined.

> +#ifdef SPIDERMONKEY_PROMISE
> +/* Support for ES7 Async Functions. */
> +#define JS_HAS_ASYNC_FUNCS 1
> +#endif // SPIDERMONKEY_PROMISE
Attachment #8665572 - Attachment is obsolete: true
Attachment #8753180 - Flags: review+
Comment on attachment 8753181 [details] [diff] [review]
Part 4: Fix function name for export default async function.

oops, this was wrong one.
Attachment #8753181 - Attachment is obsolete: true
Rebased previous Part 4, and merged remaining part of previous Part 6, and also merged sel-hosting intrinsic from previous Part 2 (SetFunctionExtendedSlot, SetFunName, GetFunName).
Attachment #8753182 - Flags: review+
`export default async function() {}` should be named '*default*', and it needs separated handling than other expression after `export default`.

https://tc39.github.io/ecmascript-asyncawait/#async-decls-exprs-static-semantics-BoundNames
Attachment #8753184 - Flags: review?(efaustbmo)
`yield` is always an identifier in async function parameters and body. (but not function name).

https://tc39.github.io/ecmascript-asyncawait/#async-function-definitions

Removed JSMSG_YIELD_IN_ASYNC, as it's not valid error.
Attachment #8753185 - Flags: review?(efaustbmo)
Added async arrow support.

Async arrow function with expression body |async () => 1| is converted into STATEMENTLIST body, to insert initial yield, and converted back to expression body in Reflect.parse.

then, in ecma_7/AsyncFunctions/arrow.js, there are some disabled tests for `yield` and `await` binding in strict mode.  is there any bug already filed for the `yield` binding issue?  (if so, I'll add the bug number there.  if not, I'll file it)


Also, added comment about the stack convention in emitAsyncWrapper.
Attachment #8753190 - Flags: review?(efaustbmo)
Added parser test for modifier and error handling.
Attachment #8753191 - Flags: review?(efaustbmo)
Added Reflect.parse test.

failure cases are already tested in Part 2, so this tests whole structure for successful cases.
Attachment #8753193 - Flags: review?(efaustbmo)
Attachment #8753184 - Flags: review?(efaustbmo) → review+
Comment on attachment 8753185 [details] [diff] [review]
Part 5: Treat yield as an identifier in async function parameters and body.

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

Nice. A few nits below.

::: js/src/frontend/Parser.cpp
@@ +2827,5 @@
>  }
>  
>  template <typename ParseHandler>
>  typename ParseHandler::Node
> +Parser<ParseHandler>::functionDef(InHandling inHandling,

oh, oops. Nice catch that this was dead.

@@ +3162,5 @@
>      else if (fun->isGetter())
>          syntaxKind = Getter;
>      else if (fun->isSetter())
>          syntaxKind = Setter;
> +    YieldHandling yieldHandling = GetYieldHandling(generatorKind, asyncKind);

nit: please insert blank line above this.

@@ +3290,5 @@
>  template <typename ParseHandler>
>  bool
>  Parser<ParseHandler>::checkYieldNameValidity()
>  {
> +    if (pc->isAsync())

Add comment being like "async functions are implemented as star generators, but not syntactically. Allow yield" or something.

@@ +3296,1 @@
>      // In star generators and in JS >= 1.7, yield is a keyword.  Otherwise in

nit: blank line before comment

@@ +8037,5 @@
>          if (endsExpr)
>              return stringLiteral();
>      }
>  
>      if (tt == TOK_YIELD && yieldExpressionsSupported()) {

nit: can remove braces from single line if.
Attachment #8753185 - Flags: review?(efaustbmo) → review+
Comment on attachment 8753190 [details] [diff] [review]
Part 6: Support async arrow function.

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

This is good, but we also need tests for async() being a function call. As I understand things, this should be the case with no backtracking. Is that true?

::: js/src/builtin/ReflectParse.cpp
@@ +3497,1 @@
>          builder.function(type, &pn->pn_pos, id, args, defaults, body,

can we align the builder. with the functionArgs above?

::: js/src/frontend/BytecodeEmitter.cpp
@@ +6478,5 @@
>      /* Non-hoisted functions simply emit their respective op. */
>      if (!pn->functionIsHoisted()) {
>          /* JSOP_LAMBDA_ARROW is always preceded by a new.target */
>          MOZ_ASSERT(fun->isArrow() == (pn->getOp() == JSOP_LAMBDA_ARROW));
> +        if (needsProto) {

Does this case really need to move? It's only for class constructors, right?

@@ +6564,5 @@
>                     bi->kind() == Binding::ARGUMENT);
>          MOZ_ASSERT(bi.argOrLocalIndex() < JS_BIT(20));
>  #endif
>          if (funbox->isAsync()) {
> +            if (!emitAsyncWrapper(index, false, false))

please comment these bools with argument names, for future readers

::: js/src/frontend/Parser.cpp
@@ +1389,5 @@
>              return null();
>      } else {
>          MOZ_ASSERT(type == ExpressionBody);
>  
> +        Node stmtList = null();

A comment here about star generators being assumed to be statement lists would be nice.
Attachment #8753190 - Flags: review?(efaustbmo) → review+
Attachment #8753191 - Flags: review?(efaustbmo) → review+
Comment on attachment 8753193 [details] [diff] [review]
Part 8: Add Reflect.parse test for async/await.

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

Good.

::: js/src/builtin/ReflectParse.cpp
@@ +3529,5 @@
>          if (pnstart && pnstart->isKind(PNK_YIELD)) {
>              MOZ_ASSERT(pnstart->getOp() == JSOP_INITIALYIELD);
>              pnstart = pnstart->pn_next;
>          }
> +        // Async arrow with expression body is converted into STATEMENTLIST

nit: blank line before comment
Attachment #8753193 - Flags: review?(efaustbmo) → review+
Thank you for reviewing :)

I found that the yield binding issue in strict mode is just a bug in my patch, will fix it.
Attachment #8753190 - Attachment is obsolete: true
Attachment #8755148 - Flags: review+
yield handling in async arrow is inherited from enclosing script, so, `GetYieldHandling` needs some more information:
  * YieldHandling of encloding script
  * FunctionSyntaxKind for the function (whether it's arrow or not)
  * YieldHandldingContext (whether current context is arguments or body)

Also, added YieldIsNotInherited to YieldHandling, to clarify that the parameter has no meaning, in the case yield handling is not inherited.

also, yieldHandling differs for arguments and body, so moved GetYieldHandling call into functionArgsAndBodyGeneric, and call it for functionArguments and functionBody.
Attachment #8755149 - Flags: review?(efaustbmo)
await should be set to keyword for whole function parameter, and also name of function expression.

destructuring parameter's default value can also contain await, and default parameter can be complex expression that contains await.
So, we should check the existence of await expression just like yield, in destructuring parameter and default parameter, by lastAwaitOffset.


Also added AutoAwaitIsKeyword, to automatically reset TokenStream's awaitIsKeyword to previous value, when leaving the scope.
Attachment #8755150 - Flags: review?(efaustbmo)
Attachment #8753191 - Attachment is obsolete: true
Attachment #8755151 - Flags: review+
Attachment #8753193 - Attachment is obsolete: true
Attachment #8755152 - Flags: review+
so far, here are things to fix:
  * AsyncFunction constructor and prototype
  * length of the async function
  * toString
  * syntax priority for async function expression

may be some more.
some are already fixed locally.
(In reply to Tooru Fujisawa [:arai] from comment #113)
> so far, here are things to fix:

I'm not following this closely enough to know if this is sane, but is there any possibility of hiding the feature behind a nightly-only pref and having followup bugs that block it riding the trains?
(In reply to Mark Hammond [:markh] from comment #114)
> (In reply to Tooru Fujisawa [:arai] from comment #113)
> > so far, here are things to fix:
> 
> I'm not following this closely enough to know if this is sane, but is there
> any possibility of hiding the feature behind a nightly-only pref and having
> followup bugs that block it riding the trains?

don't worry :)
No patches have been landed, and I won't land these patches until those issues are fixed.
also, async/await is behind two switches, NIGHTLY_BUILD and SPIDERMONKEY_PROMISE, that means even if I land them, it won't be available in Nightly.
(In reply to Tooru Fujisawa [:arai] from comment #115)
> don't worry :)
> No patches have been landed, and I won't land these patches until those
> issues are fixed.

I worry they *will not* land ASAP - I want to play with them!

> also, async/await is behind two switches, NIGHTLY_BUILD and
> SPIDERMONKEY_PROMISE

Right - that sounds great! I'm wondering if we can land that way before those other problems are fixed, and only remove those switches once those other issues are fixed?

> that means even if I land them, it won't be available
> in Nightly.

Oh - it looks like SPIDERMONKEY_PROMISE isn't enabled anywhere by default? I must have mis-guessed what that means...
ah, I see.
Will try fixing remaining things shortly, now toString is the only remaining not-yet-fixed-locally issue :)
(In reply to Mark Hammond [:markh] from comment #116)
> Oh - it looks like SPIDERMONKEY_PROMISE isn't enabled anywhere by default? I
> must have mis-guessed what that means...

It means I have to get this green: https://treeherder.mozilla.org/#/jobs?repo=try&revision=ce5f80201fe1
async function expression was parsed as assignment expression, but should be primary expression

https://tc39.github.io/ecmascript-asyncawait/#PrimaryExpression
Attachment #8755552 - Flags: review?(efaustbmo)
Added AsyncFunction constructor, and AsyncFunctionPrototype.

wrapper's prototype is dynamically changed to AsyncFunctionPrototype in AsyncFunction_wrap.

AsyncFunction constructor and prototype are created just like GeneratorFunction constructor and prototype.

AsyncFunctionConstructor is the implementation of AsyncFunction constructor.
there is one tricky thing.  function created in FunctionConstructor is unwrapped function, so it uses GeneratorFunction as its prototype.
then, it's wrapped in AsyncFunctionConstructor, just like we do in bytecode.

Also, modified intrinsic_GetBuiltinConstructor to return AsyncFunction constructor, that has no JSProtoKey.
Attachment #8755554 - Flags: review?(efaustbmo)
Also, length of async function was not set to unwrapped function's one.
so, changed to define it inside AsyncFunction_wrap
Attachment #8755555 - Flags: review?(efaustbmo)
to support toString, we need to do following steps:
  1. check if given function is wrapper
  2. extract unwrapped function from wrapper
  3. apply toString on unwrapped function


for 1, stored "AsyncWrapper" string to wrapper's first reserved slot.
as, self-hosted function's first reserved slot is mostly used to store original function name, but it's not used for inner function.
it would be better to store name there for this case too, as we can use IsSelfHostedFunctionWithName to check it.

for 2, stored unwrapped function into wrapper's second reserved slot.


Then, just as a cleanup, moved slot handling done in CallObject::createForFunction into GetAsyncFunctionWrapper,
and added GetUnwrappedAsyncFunction for other way.
Attachment #8755557 - Flags: review?(efaustbmo)
Comment on attachment 8755554 [details] [diff] [review]
Part 10: Add AsyncFunction constructor and prototype.

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

::: js/src/builtin/AsyncFunctions.js
@@ +11,5 @@
>              var promiseCtor = GetBuiltinConstructor('Promise');
>              return callFunction(Promise_static_reject, promiseCtor, e);
>          }
>      };
> +    std_Object_setPrototypeOf(wrapper, GetBuiltinPrototype("AsyncFunction"));

It'd be great if we could somehow avoid this, because it costs us in terms of optimization potential. Specifically, every typeset the async function becomes part of will be made fully generic.

For a first implementation, that's probably fine, but we should ideally fix this before shipping.
With all those patches applied, following tests still fails in async/await test262 ( https://github.com/tc39/test262/pull/479 ), but all of them are not async/await specific issue.


implement toStringTag (bug 1114580)
  * built-ins/AsyncFunction/AsyncFunctionPrototype-to-string.js


toString should reflect the comment inside arguments (bug 755821)
  * built-ins/Function/prototype/toString/AsyncFunction.js
  * built-ins/Function/prototype/toString/async-function-declaration.js
  * built-ins/Function/prototype/toString/async-function-expression.js
  * built-ins/Function/prototype/toString/async-method.js


"use strict" in body with default/destructuring should throw (bug 1272784)
  * language/expressions/async-arrow-function/early-errors-arrow-NSPL-with-USD.js
  * language/expressions/async-function/early-errors-expression-NSPL-with-USD.js
  * language/expressions/object/method-definition/early-errors-object-method-NSPL-with-USD.js
  * language/statements/async-function/early-errors-declaration-NSPL-with-USD.js
  * language/statements/class/definition/early-errors-class-method-NSPL-with-USD.js


redeclaration should be SyntaxError, but we're using TypeError (no bug)
  * language/expressions/async-arrow-function/early-errors-arrow-formals-body-duplicate.js
  * language/expressions/async-function/early-errors-expression-formals-body-duplicate.js
  * language/statements/async-function/early-errors-declaration-formals-body-duplicate
(In reply to Till Schneidereit [:till] from comment #123)
> Comment on attachment 8755554 [details] [diff] [review]
> Part 10: Add AsyncFunction constructor and prototype.
> 
> Review of attachment 8755554 [details] [diff] [review]:
> -----------------------------------------------------------------
> 
> ::: js/src/builtin/AsyncFunctions.js
> @@ +11,5 @@
> >              var promiseCtor = GetBuiltinConstructor('Promise');
> >              return callFunction(Promise_static_reject, promiseCtor, e);
> >          }
> >      };
> > +    std_Object_setPrototypeOf(wrapper, GetBuiltinPrototype("AsyncFunction"));
> 
> It'd be great if we could somehow avoid this, because it costs us in terms
> of optimization potential. Specifically, every typeset the async function
> becomes part of will be made fully generic.
> 
> For a first implementation, that's probably fine, but we should ideally fix
> this before shipping.

Thank you for pointing that out :)
okay, will try finding a better solution.
Comment on attachment 8755554 [details] [diff] [review]
Part 10: Add AsyncFunction constructor and prototype.

Okay, I got another solution without setPrototypeOf.
will post it after some more test.
Attachment #8755554 - Flags: review?(efaustbmo)
Comment on attachment 8755555 [details] [diff] [review]
Part 11: Set length of async function.

This should be fixed at once
Attachment #8755555 - Flags: review?(efaustbmo)
Comment on attachment 8755557 [details] [diff] [review]
Part 12: Support async function in Function.prototype.toString.

This will also be affected by the change.
Attachment #8755557 - Flags: review?(efaustbmo)
Moved everything into CreateAsyncFunction intrinsic.
There a new function is created with %AsyncFunctionPrototype%,
reusing the script and the environment of `wrapper` function,
and the name and the length of `unwrapped` function.

For now, I'm using 3 names for each function:
  * wrapper   -- a function defined inside AsyncFunction_wrap
  * unwrapped -- a function created by compiling actual async function
  * wrapped   -- a function created by CreateAsyncFunction
                 its script and environment are `wrapper`'s,
                 and name and length are `unwrapped`'s.

  wrapper
     |
     | script, environment
     |
     |   unwrapped
     |       |
     |       | name, length
     |       |
     v       v
CreateAsyncFunction
     |
     v
  wrapped
Attachment #8755554 - Attachment is obsolete: true
Attachment #8755555 - Attachment is obsolete: true
Attachment #8755753 - Flags: review?(efaustbmo)
Moved most part to Part 10.
Attachment #8755557 - Attachment is obsolete: true
Attachment #8755754 - Flags: review?(efaustbmo)
just as a note, |(async function f(){}).isGenerator()| returns false.
not sure how people expects the value to be tho.
(related to bug 1119777)
Filed bug 1275240 for redeclaration of formal parameter
rebasing on bug 911216, and some trivial fix on some parts.
Attachment #8753179 - Attachment is obsolete: true
Attachment #8771755 - Flags: review+
Attachment #8753182 - Attachment is obsolete: true
Attachment #8771757 - Flags: review+
Attachment #8755148 - Attachment is obsolete: true
Attachment #8771760 - Flags: review+
details in comment #109
Attachment #8755149 - Attachment is obsolete: true
Attachment #8755149 - Flags: review?(efaustbmo)
Attachment #8771761 - Flags: review?(efaustbmo)
details in comment #110
Attachment #8755150 - Attachment is obsolete: true
Attachment #8755150 - Flags: review?(efaustbmo)
Attachment #8771762 - Flags: review?(efaustbmo)
Attachment #8755151 - Attachment is obsolete: true
Attachment #8771763 - Flags: review+
Attachment #8755152 - Attachment is obsolete: true
Attachment #8771764 - Flags: review+
details in comment #119
Attachment #8755552 - Attachment is obsolete: true
Attachment #8755552 - Flags: review?(efaustbmo)
Attachment #8771765 - Flags: review?(efaustbmo)
details in comment #129
Attachment #8755753 - Attachment is obsolete: true
Attachment #8755753 - Flags: review?(efaustbmo)
Attachment #8771766 - Flags: review?(efaustbmo)
details in comment #122 and comment #130
Attachment #8755754 - Attachment is obsolete: true
Attachment #8755754 - Flags: review?(efaustbmo)
Attachment #8771767 - Flags: review?(efaustbmo)
Comment on attachment 8771761 [details] [diff] [review]
Part 6.1: Fix yield handling in async function.

will rebase all these patches and cleanup the patch order/granularity.
Attachment #8771761 - Flags: review?(efaustbmo)
Attachment #8771762 - Flags: review?(efaustbmo)
Attachment #8771765 - Flags: review?(efaustbmo)
Attachment #8771766 - Flags: review?(efaustbmo)
Attachment #8771767 - Flags: review?(efaustbmo)
with new EnvironmentObject, there seems to need some more tricks to mix wrapper/unwrapped functions.
will try finding a solution.
The issue is that, we need pseudo NamedLambdaObject for named async function expression,
that points wrapped function, instead of unwrapped function.

  var wrapped = async function func() {
    return func;
  };
  var resolved;
  wrapped().then(r=>resolved=r);
  drainJobQueue();
  assertEq(resolved, wrapped);
just rebased.
no change
Attachment #8771755 - Attachment is obsolete: true
Attachment #8785838 - Flags: review+
Later in the patch series, we'll need to calculate YieldHandling for function arguments and body separately.
As a preparation, changed Parser::functionFormalParametersAndBody to receive GeneratorKind instead of YieldHandling, and calculate YieldHandling inside it.
Attachment #8785840 - Flags: review?(efaustbmo)
Also, later in the patch, we need to check yield name validity depends on current yield handling.
As a preparation, changed the signature of Parser::checkYieldNameValidity to receive YieldHandling.
Attachment #8785841 - Flags: review?(efaustbmo)
One more preparation.
Parser::functionFormalParametersAndBody was changed to receive GeneratorKind instead of YieldHandling, but actually we need another YieldHandling parameter, that is the YieldHandling for outside of the function (instead of inside the function, that was previous one), that affects the YieldHandling of async arrow arguments.

YieldHandling enum is extended to 3 states YieldIsName, YieldIsKeyword, and YieldIsNotInherited.
YieldIsNotInherited explicitly represents yield handling is not inherited for the context, like non-arrow.
Attachment #8785842 - Flags: review?(efaustbmo)
Separated the change for FunctionBox, JSScript, and LazyScript.
no changes except minor styling.
Attachment #8785843 - Flags: review+
For most cases, we need FunctionAsyncKind parameter where the Parser methods receives GeneratorKind.
Separated the change for it.
no changes except rebase on different new methods from frontend rewrite.
Attachment #8785844 - Flags: review+
Separated the change for TokenStream, for TOK_AWAIT.
Removed unused TOK_ASYNC.
No other changes except moving awaitIsKeyword to private.
Attachment #8785845 - Flags: review+
Previously we were directly modifying awaitIsKeyword property, but it should be better the property is changed back to original state automatically when leaving the context.
So added AutoAwaitIsKeyword class that sets and resets awaitIsKeyword.
Attachment #8785846 - Flags: review?(efaustbmo)
Separated async function declaration part.
no changes.
Attachment #8771756 - Attachment is obsolete: true
Attachment #8785847 - Flags: review+
Also separated async function declaration part of Reflect.parse.
no changes.
Attachment #8785848 - Flags: review+
Await handling was changed in previous not-yet-reviewed patch.
Separated that part.

  * Added ParseHandler::newAwaitExpression, instead of reusing newYieldExpression.
  * Throw error when destructuring parameter contains await,
    just in the same way as yield
Attachment #8771761 - Attachment is obsolete: true
Attachment #8785851 - Flags: review?(efaustbmo)
Separated await part of Reflect.parse.
no changes.
Attachment #8785852 - Flags: review+
Separated basic parser test for async function declaration.
no changes except BUGNUMBER and summary for each test,
and using anonymous function in shell.js.
Attachment #8785853 - Flags: review+
Test for yield handling in async function.
Attachment #8785856 - Flags: review?(efaustbmo)
Async function expression's priority was fixed in previous not-yet-reviewed patch.
separated that part.
Attachment #8785857 - Flags: review?(efaustbmo)
Separated async function expression part.
no changes.
Attachment #8785859 - Flags: review+
test for yield in async function expression.
Attachment #8785860 - Flags: review?(efaustbmo)
Separated async method handling.
no changes.
Attachment #8785861 - Flags: review+
Separated async method part.
no changes.
Attachment #8785862 - Flags: review+
test for yield in async method.
Attachment #8785864 - Flags: review?(efaustbmo)
Changed to use AutoAwaitIsKeyword in module body.
no other changes.
Attachment #8785868 - Flags: review+
Separated async function test for modules.
no changes.
Attachment #8785869 - Flags: review+
Separated async function in export default.
no changes.
Attachment #8771758 - Attachment is obsolete: true
Attachment #8785870 - Flags: review+
Separated test for async function in export default.
no changes.
Attachment #8785871 - Flags: review+
test for yield in async function in export default.
Attachment #8771759 - Attachment is obsolete: true
Attachment #8771762 - Attachment is obsolete: true
Attachment #8771763 - Attachment is obsolete: true
Attachment #8771765 - Attachment is obsolete: true
Attachment #8785872 - Flags: review?(efaustbmo)
Now YieldHandling is calculated separately for arguments and body, especially for async arrow.
Async arrow function inherits yield handling from enclosing context.

other await/yield handling is separated to Part 5.3.
Attachment #8771760 - Attachment is obsolete: true
Attachment #8785873 - Flags: review?(efaustbmo)
Separated async arrow part of Reflect.parse.
no changes.
Attachment #8785874 - Flags: review+
Separated test for async arrow.
no changes.
Attachment #8785875 - Flags: review+
Previous part 10.
No change from previous one except NamedLambdaObject.

Summary from comment 129, and some extra.

Async function instance is created by CreateAsyncFunction intrinsic, called from AsyncFunction_wrap.

There a new function is created with %AsyncFunctionPrototype%,
reusing the script and the environment of `wrapper` function,
and the name and the length of `unwrapped` function.

For now, I'm using 3 names for each function:
  * wrapper   -- a function defined inside AsyncFunction_wrap
  * unwrapped -- a function created by compiling actual async function
  * wrapped   -- a function created by CreateAsyncFunction
                 its script and environment are `wrapper`'s,
                 and name and length are `unwrapped`'s.

  wrapper
     |
     | script, environment
     |
     |   unwrapped
     |       |
     |       | name, length
     |       |
     v       v
CreateAsyncFunction
     |
     v
  wrapped


`unwrapped` function can be retrieved from `wrapped` by `GetUnwrappedAsyncFunction`,
and `wrapped` can be retrieved from `unwrapped` by `GetWrappedAsyncFunction`.
Both references are stored in 2nd extended slot.

Here, fun->isAsync() is true for `unwrapped`, not `wrapped`.
`IsWrappedAsyncFunction` can be used to detect `wrapped`, it checks self hosted name.

If unwrapped function is named lambda, NamedLambdaObject is created with wrapped function for the name binding.
NamedLambdaObject::create is modified to accept `callee` and function value separately, to support this.
Attachment #8771757 - Attachment is obsolete: true
Attachment #8771764 - Attachment is obsolete: true
Attachment #8771766 - Attachment is obsolete: true
Attachment #8785877 - Flags: review?(efaustbmo)
With previous helper functions, it's hard to see where the test fails,
so changed it to use drainJobQueue and check instantly.
So that if one test fails, we can see the stack trace.
Attachment #8785878 - Flags: review?(efaustbmo)
test for semantics, no changes except BUGNUMBER/summary headers and changes from helper functions.
Attachment #8785879 - Flags: review+
Added test for length property, as we're emulating unwrapped length in wrapped function.
Attachment #8785880 - Flags: review?(efaustbmo)
Added constructor/prototype tests.
Attachment #8785886 - Flags: review?(efaustbmo)
named lambda now uses NamedLambdaObject to store/get the binding.
added test for it.
Attachment #8785897 - Flags: review?(efaustbmo)
`arguments.callee` should return some value that makes sense.
without this patch, it returns `unwrapped` function, that is not exposed elsewhere.
changed it to return `wrapped`.

maybe we could just throw error, or return undefined, as there is no backward compat issue,
as this is implementation dependent.
Attachment #8785899 - Flags: review?(efaustbmo)
async function should return string representation of `unwrapped`, for toString call on `wrapped`,
so if it detects the `this` is async, calls FunctionToString with `unwrapped`.
Attachment #8771767 - Attachment is obsolete: true
Attachment #8785900 - Flags: review?(efaustbmo)
Comment on attachment 8785841 [details] [diff] [review]
Part 0.3: Pass YieldHandling to Parser::checkYieldNameValidity for later use. r?efaust

checkYieldNameValidity is now removed.
Attachment #8785841 - Flags: review?(efaustbmo)
Attachment #8785841 - Attachment is obsolete: true
Depends on: 1305333
rebased.

will post remaining patches with bzexport.
Attachment #8785838 - Attachment is obsolete: true
Attachment #8785840 - Attachment is obsolete: true
Attachment #8785842 - Attachment is obsolete: true
Attachment #8785843 - Attachment is obsolete: true
Attachment #8785844 - Attachment is obsolete: true
Attachment #8785845 - Attachment is obsolete: true
Attachment #8785846 - Attachment is obsolete: true
Attachment #8785847 - Attachment is obsolete: true
Attachment #8785848 - Attachment is obsolete: true
Attachment #8785851 - Attachment is obsolete: true
Attachment #8785852 - Attachment is obsolete: true
Attachment #8785853 - Attachment is obsolete: true
Attachment #8785856 - Attachment is obsolete: true
Attachment #8785857 - Attachment is obsolete: true
Attachment #8785859 - Attachment is obsolete: true
Attachment #8785860 - Attachment is obsolete: true
Attachment #8785861 - Attachment is obsolete: true
Attachment #8785862 - Attachment is obsolete: true
Attachment #8785864 - Attachment is obsolete: true
Attachment #8785868 - Attachment is obsolete: true
Attachment #8785869 - Attachment is obsolete: true
Attachment #8785870 - Attachment is obsolete: true
Attachment #8785871 - Attachment is obsolete: true
Attachment #8785872 - Attachment is obsolete: true
Attachment #8785873 - Attachment is obsolete: true
Attachment #8785874 - Attachment is obsolete: true
Attachment #8785875 - Attachment is obsolete: true
Attachment #8785877 - Attachment is obsolete: true
Attachment #8785878 - Attachment is obsolete: true
Attachment #8785879 - Attachment is obsolete: true
Attachment #8785880 - Attachment is obsolete: true
Attachment #8785886 - Attachment is obsolete: true
Attachment #8785897 - Attachment is obsolete: true
Attachment #8785899 - Attachment is obsolete: true
Attachment #8785900 - Attachment is obsolete: true
Attachment #8785840 - Flags: review?(efaustbmo)
Attachment #8785842 - Flags: review?(efaustbmo)
Attachment #8785846 - Flags: review?(efaustbmo)
Attachment #8785851 - Flags: review?(efaustbmo)
Attachment #8785856 - Flags: review?(efaustbmo)
Attachment #8785857 - Flags: review?(efaustbmo)
Attachment #8785860 - Flags: review?(efaustbmo)
Attachment #8785864 - Flags: review?(efaustbmo)
Attachment #8785872 - Flags: review?(efaustbmo)
Attachment #8785873 - Flags: review?(efaustbmo)
Attachment #8785877 - Flags: review?(efaustbmo)
Attachment #8785878 - Flags: review?(efaustbmo)
Attachment #8785880 - Flags: review?(efaustbmo)
Attachment #8785886 - Flags: review?(efaustbmo)
Attachment #8785897 - Flags: review?(efaustbmo)
Attachment #8785899 - Flags: review?(efaustbmo)
Attachment #8785900 - Flags: review?(efaustbmo)
Attachment #8795105 - Flags: review+
Assignee: mkierski → arai.unmht
Status: NEW → ASSIGNED
no... I wasn't about to steal assignee :/
Assignee: arai.unmht → mkierski
Attached patch Part 3: Add await token (obsolete) — Splinter Review
Attachment #8795114 - Flags: review?(efaustbmo)
Attachment #8795132 - Flags: review?(efaustbmo)
Comment on attachment 8795107 [details] [diff] [review]
Part 0.3: Pass YieldHandling to Parser::functionFormalParametersAndBody for later use

Removed YieldIsNotInherited, and changed to pass actual value.
  * added outerYieldHandling parameter to Parser::functionExpr, to pass to Parser::functionDelazifying
  * added LazyScript.p_.outerYieldIsKeyword to store outerYieldHandling
Depends on: 1204024
Attached file a.txt (obsolete) —
Just to obsolete all patches.
will post to mozreview, to avoid attaching these patches again :P
Attachment #8795105 - Attachment is obsolete: true
Attachment #8795106 - Attachment is obsolete: true
Attachment #8795107 - Attachment is obsolete: true
Attachment #8795108 - Attachment is obsolete: true
Attachment #8795109 - Attachment is obsolete: true
Attachment #8795110 - Attachment is obsolete: true
Attachment #8795111 - Attachment is obsolete: true
Attachment #8795112 - Attachment is obsolete: true
Attachment #8795113 - Attachment is obsolete: true
Attachment #8795114 - Attachment is obsolete: true
Attachment #8795115 - Attachment is obsolete: true
Attachment #8795116 - Attachment is obsolete: true
Attachment #8795117 - Attachment is obsolete: true
Attachment #8795118 - Attachment is obsolete: true
Attachment #8795119 - Attachment is obsolete: true
Attachment #8795120 - Attachment is obsolete: true
Attachment #8795121 - Attachment is obsolete: true
Attachment #8795122 - Attachment is obsolete: true
Attachment #8795123 - Attachment is obsolete: true
Attachment #8795124 - Attachment is obsolete: true
Attachment #8795125 - Attachment is obsolete: true
Attachment #8795126 - Attachment is obsolete: true
Attachment #8795127 - Attachment is obsolete: true
Attachment #8795128 - Attachment is obsolete: true
Attachment #8795129 - Attachment is obsolete: true
Attachment #8795130 - Attachment is obsolete: true
Attachment #8795131 - Attachment is obsolete: true
Attachment #8795132 - Attachment is obsolete: true
Attachment #8795133 - Attachment is obsolete: true
Attachment #8795134 - Attachment is obsolete: true
Attachment #8795135 - Attachment is obsolete: true
Attachment #8795136 - Attachment is obsolete: true
Attachment #8795137 - Attachment is obsolete: true
Attachment #8795138 - Attachment is obsolete: true
Attachment #8795139 - Attachment is obsolete: true
Attachment #8795106 - Flags: review?(efaustbmo)
Attachment #8795107 - Flags: review?(efaustbmo)
Attachment #8795111 - Flags: review?(efaustbmo)
Attachment #8795114 - Flags: review?(efaustbmo)
Attachment #8795117 - Flags: review?(efaustbmo)
Attachment #8795118 - Flags: review?(efaustbmo)
Attachment #8795120 - Flags: review?(efaustbmo)
Attachment #8795123 - Flags: review?(efaustbmo)
Attachment #8795128 - Flags: review?(efaustbmo)
Attachment #8795129 - Flags: review?(efaustbmo)
Attachment #8795132 - Flags: review?(efaustbmo)
Attachment #8795133 - Flags: review?(efaustbmo)
Attachment #8795135 - Flags: review?(efaustbmo)
Attachment #8795136 - Flags: review?(efaustbmo)
Attachment #8795137 - Flags: review?(efaustbmo)
Attachment #8795138 - Flags: review?(efaustbmo)
Attachment #8795139 - Flags: review?(efaustbmo)
Attachment #8799151 - Attachment is obsolete: true
This is already supported on Chrome 55 (beta).  Should a [chrome-parity] tag be added?
Attachment #8799152 - Flags: review?(efaustbmo) → review?(till)
Attachment #8799153 - Flags: review?(efaustbmo) → review?(till)
Attachment #8799154 - Flags: review?(efaustbmo) → review?(till)
Attachment #8799155 - Flags: review?(efaustbmo) → review?(till)
Attachment #8799156 - Flags: review?(efaustbmo) → review?(till)
Attachment #8799157 - Flags: review?(efaustbmo) → review?(till)
Attachment #8799158 - Flags: review?(efaustbmo) → review?(till)
Attachment #8799159 - Flags: review?(efaustbmo) → review?(till)
Attachment #8799160 - Flags: review?(efaustbmo) → review?(till)
Attachment #8799161 - Flags: review?(efaustbmo) → review?(till)
Attachment #8799162 - Flags: review?(efaustbmo) → review?(till)
Attachment #8799163 - Flags: review?(efaustbmo) → review?(till)
Attachment #8799164 - Flags: review?(efaustbmo) → review?(till)
Attachment #8799165 - Flags: review?(efaustbmo) → review?(till)
Attachment #8799166 - Flags: review?(efaustbmo) → review?(till)
Attachment #8799167 - Flags: review?(efaustbmo) → review?(till)
Attachment #8799168 - Flags: review?(efaustbmo) → review?(till)
Attachment #8799169 - Flags: review?(efaustbmo) → review?(till)
Attachment #8799170 - Flags: review?(efaustbmo) → review?(till)
Attachment #8799171 - Flags: review?(efaustbmo) → review?(till)
Attachment #8799172 - Flags: review?(efaustbmo) → review?(till)
Attachment #8799173 - Flags: review?(efaustbmo) → review?(till)
Attachment #8799174 - Flags: review?(efaustbmo) → review?(till)
Attachment #8799175 - Flags: review?(efaustbmo) → review?(till)
Attachment #8799176 - Flags: review?(efaustbmo) → review?(till)
Attachment #8799177 - Flags: review?(efaustbmo) → review?(till)
Attachment #8799178 - Flags: review?(efaustbmo) → review?(till)
Attachment #8799179 - Flags: review?(efaustbmo) → review?(till)
Attachment #8799180 - Flags: review?(efaustbmo) → review?(till)
Attachment #8799181 - Flags: review?(efaustbmo) → review?(till)
Attachment #8799182 - Flags: review?(efaustbmo) → review?(till)
Attachment #8799183 - Flags: review?(efaustbmo) → review?(till)
Attachment #8799184 - Flags: review?(efaustbmo) → review?(till)
Comment on attachment 8799152 [details]
Bug 1185106 - Part 0.1: Refactor JSOP_DEFFUN.

https://reviewboard.mozilla.org/r/84420/#review87616

Looks good, but I think it'd be good to have a JIT person take a look at this, too. I'm also just assuming that the change I commented on below is ok, but would like to have an explanation for it.

::: js/src/vm/Interpreter.cpp
(Diff revision 1)
>  bool
>  js::DefFunOperation(JSContext* cx, HandleScript script, HandleObject envChain,
> -                    HandleFunction funArg)
> +                    HandleFunction fun)
>  {
>      /*
> -     * If static link is not current scope, clone fun's object to link to the

Why isn't this needed anymore?
Attachment #8799152 - Flags: review?(till) → review+
Comment on attachment 8799152 [details]
Bug 1185106 - Part 0.1: Refactor JSOP_DEFFUN.

Hannes, can you take a look at the JIT pieces?
Attachment #8799152 - Flags: review?(hv1989)
Comment on attachment 8799153 [details]
Bug 1185106 - Part 1: Add AsyncFunction flag in FunctionBox, JSScript, and LazyScript.

https://reviewboard.mozilla.org/r/84422/#review87620

r=me with feedback addressed.

::: js/src/frontend/SharedContext.h:474
(Diff revision 1)
>      bool            usesThis:1;             /* contains 'this' */
>      bool            usesReturn:1;           /* contains a 'return' statement */
>  
>      FunctionContextFlags funCxFlags;
>  
> +    FunctionAsyncKind _asyncKind;

Can you turn this into `uint8_t asyncKindBits_` and move it to right after `generatorKindBits_`? That'd keep `FunctionBox` at its current size, which would be nice.

::: js/src/frontend/SharedContext.h:538
(Diff revision 1)
>      GeneratorKind generatorKind() const { return GeneratorKindFromBits(generatorKindBits_); }
>      bool isGenerator() const { return generatorKind() != NotGenerator; }
>      bool isLegacyGenerator() const { return generatorKind() == LegacyGenerator; }
>      bool isStarGenerator() const { return generatorKind() == StarGenerator; }
> +    bool isAsync() const { return _asyncKind == AsyncFunction; }
> +    FunctionAsyncKind asyncKind() const { return _asyncKind; }

... obviously that'd require introducing an `AsyncKindFromBits` helper and using it here. r=me on that if it's a straight duplication of `GeneratorKindFromBits`.
Attachment #8799153 - Flags: review?(till) → review+
Comment on attachment 8799154 [details]
Bug 1185106 - Part 2: Add FunctionAsyncKind parameter to Parser methods that receives GeneratorKind.

https://reviewboard.mozilla.org/r/84424/#review87624

r=me
Attachment #8799154 - Flags: review?(till) → review+
Comment on attachment 8799155 [details]
Bug 1185106 - Part 3: Add await token.

https://reviewboard.mozilla.org/r/84426/#review87628

r=me
Attachment #8799155 - Flags: review?(till) → review+
Comment on attachment 8799156 [details]
Bug 1185106 - Part 4: Add AutoAwaitIsKeyword class to set TokenStream.awaitIsKeyword.

https://reviewboard.mozilla.org/r/84428/#review87630

r=me with nit addressed.

::: js/src/frontend/TokenStream.h:1035
(Diff revision 1)
>  
> +class MOZ_STACK_CLASS AutoAwaitIsKeyword
> +{
> +private:
> +    TokenStream* ts_;
> +    bool beforeAwaitIsKeyword_;

Please rename this to `oldAwaitIsKeyword_`, which is in keeping with comparable things like `oldCompartment_` in `JSAutoCompartment`.
Attachment #8799156 - Flags: review?(till) → review+
Comment on attachment 8799157 [details]
Bug 1185106 - Part 5.1: Support async function declaration in Parser.

https://reviewboard.mozilla.org/r/84430/#review87632

r=me with nits addressed.

::: js/src/frontend/Parser.cpp:3249
(Diff revision 1)
>      if (!funpc.init())
>          return null();
>  
>      // Our tokenStream has no current token, so pn's position is garbage.
>      // Substitute the position of the first token in our source. If the function
> -    // is an arrow, use TokenStream::Operand to keep verifyConsistentModifier
> +    // is an not-async arrow, use TokenStream::Operand to keep

nit: s/is an/is a/

::: js/src/js.msg:185
(Diff revision 1)
>  MSG_DEF(JSMSG_ACCESSOR_WRONG_ARGS,     3, JSEXN_SYNTAXERR, "{0} functions must have {1} argument{2}")
>  MSG_DEF(JSMSG_ARRAY_COMP_LEFTSIDE,     0, JSEXN_SYNTAXERR, "invalid array comprehension left-hand side")
>  MSG_DEF(JSMSG_ARRAY_INIT_TOO_BIG,      0, JSEXN_INTERNALERR, "array initializer too large")
>  MSG_DEF(JSMSG_AS_AFTER_IMPORT_STAR,    0, JSEXN_SYNTAXERR, "missing keyword 'as' after import *")
>  MSG_DEF(JSMSG_AS_AFTER_RESERVED_WORD,  1, JSEXN_SYNTAXERR, "missing keyword 'as' after reserved word '{0}'")
> +MSG_DEF(JSMSG_ASYNC_GENERATOR,         0, JSEXN_SYNTAXERR, "generator function or method may not be async")

nit: please change this from "may not" to "can't".
Attachment #8799157 - Flags: review?(till) → review+
Comment on attachment 8799158 [details]
Bug 1185106 - Part 5.2: Support async function declaration in Reflect.parse.

https://reviewboard.mozilla.org/r/84432/#review87634

r=me
Attachment #8799158 - Flags: review?(till) → review+
Comment on attachment 8799159 [details]
Bug 1185106 - Part 5.3: Support await expression in Parser.

https://reviewboard.mozilla.org/r/84434/#review87636

r=me with nits addressed.

::: js/src/frontend/Parser.h:1158
(Diff revision 1)
>                      PossibleError* possibleError,
>                      InvokedPrediction invoked = PredictUninvoked);
>      Node assignExpr(InHandling inHandling, YieldHandling yieldHandling,
>                      TripledotHandling tripledotHandling,
>                      InvokedPrediction invoked = PredictUninvoked);
> -    Node assignExprWithoutYield(YieldHandling yieldHandling, unsigned err);
> +    Node assignExprWithoutYieldAndAwait(YieldHandling yieldHandling);

Please change this to "WithoutYieldOrAwait"

::: js/src/frontend/Parser.h:1223
(Diff revision 1)
>      Node generatorComprehension(uint32_t begin);
>  
>      bool argumentList(YieldHandling yieldHandling, Node listNode, bool* isSpread);
>      Node destructuringDeclaration(DeclarationKind kind, YieldHandling yieldHandling,
>                                    TokenKind tt);
> -    Node destructuringDeclarationWithoutYield(DeclarationKind kind, YieldHandling yieldHandling,
> +    Node destructuringDeclarationWithoutYieldAndAwait(DeclarationKind kind, YieldHandling yieldHandling,

Same here.

::: js/src/js.msg:186
(Diff revision 1)
>  MSG_DEF(JSMSG_ARRAY_COMP_LEFTSIDE,     0, JSEXN_SYNTAXERR, "invalid array comprehension left-hand side")
>  MSG_DEF(JSMSG_ARRAY_INIT_TOO_BIG,      0, JSEXN_INTERNALERR, "array initializer too large")
>  MSG_DEF(JSMSG_AS_AFTER_IMPORT_STAR,    0, JSEXN_SYNTAXERR, "missing keyword 'as' after import *")
>  MSG_DEF(JSMSG_AS_AFTER_RESERVED_WORD,  1, JSEXN_SYNTAXERR, "missing keyword 'as' after reserved word '{0}'")
>  MSG_DEF(JSMSG_ASYNC_GENERATOR,         0, JSEXN_SYNTAXERR, "generator function or method may not be async")
> +MSG_DEF(JSMSG_AWAIT_IN_DEFAULT,        0, JSEXN_SYNTAXERR, "await in default expression")

nit: change this to "await can't be used in default expressions"
Attachment #8799159 - Flags: review?(till) → review+
Comment on attachment 8799160 [details]
Bug 1185106 - Part 5.4: Support await expression in Reflect.parse.

https://reviewboard.mozilla.org/r/84436/#review87640

r=me
Attachment #8799160 - Flags: review?(till) → review+
Comment on attachment 8799161 [details]
Bug 1185106 - Part 5.5: Add parser test for async function declaration.

https://reviewboard.mozilla.org/r/84438/#review87642

Please remove the license headers from the new test files. Tests should be CC0 and are by default without a header. r=me with that.
Attachment #8799161 - Flags: review?(till) → review+
Comment on attachment 8799162 [details]
Bug 1185106 - Part 5.6: Add parser test for yield in async function declaration.

https://reviewboard.mozilla.org/r/84440/#review87646

r=me with nits addressed

::: js/src/tests/ecma_7/AsyncFunctions/yield.js:27
(Diff revision 1)
> +    Reflect.parse("function f() { async function yield() {} }");
> +    assertThrows(() => Reflect.parse("function* g() { async function yield() {} }"), SyntaxError);
> +    assertThrows(() => Reflect.parse("'use strict'; async function yield() {}"), SyntaxError);
> +
> +    // `yield` is treated as an identifier in an async function parameter
> +    // `yield` is not allowed as an identigier in strict code.

nit: s/identigier/identifier/

::: js/src/tests/ecma_7/AsyncFunctions/yield.js:35
(Diff revision 1)
> +    testPassArgsBody("(a = yield) {}");
> +    testErrorArgsBodyStrict("(yield 3) {}");
> +    testErrorArgsBodyStrict("(a = yield 3) {}");
> +
> +    // `yield` is treated as an identifier in an async function body
> +    // `yield` is not allowed as an identigier in strict code.

Same here.
Attachment #8799162 - Flags: review?(till) → review+
Comment on attachment 8799163 [details]
Bug 1185106 - Part 6.1: Support async function expression in Parser.

https://reviewboard.mozilla.org/r/84442/#review87648

r=me
Attachment #8799163 - Flags: review?(till) → review+
Comment on attachment 8799164 [details]
Bug 1185106 - Part 6.2: Add parser test for async function expression.

https://reviewboard.mozilla.org/r/84444/#review87652

r=me
Attachment #8799164 - Flags: review?(till) → review+
Comment on attachment 8799165 [details]
Bug 1185106 - Part 6.3: Add parser test for yield in async function expression.

https://reviewboard.mozilla.org/r/84446/#review87654

r=me with nit addressed.

::: js/src/tests/ecma_7/AsyncFunctions/yield.js:31
(Diff revision 1)
>      Reflect.parse("function f() { async function yield() {} }");
>      assertThrows(() => Reflect.parse("function* g() { async function yield() {} }"), SyntaxError);
>      assertThrows(() => Reflect.parse("'use strict'; async function yield() {}"), SyntaxError);
>  
> +    // `yield` is treated as an identifier in an async function expression name.
> +    // `yield` is not allowed as an identigier in strict code.

nit: s/identigier/identifier/ here and above.
Attachment #8799165 - Flags: review?(till) → review+
Comment on attachment 8799166 [details]
Bug 1185106 - Part 7.1: Support async method in Parser.

https://reviewboard.mozilla.org/r/84448/#review87662

r=me
Attachment #8799166 - Flags: review?(till) → review+
Comment on attachment 8799167 [details]
Bug 1185106 - Part 7.2: Add parser test for async method.

https://reviewboard.mozilla.org/r/84450/#review87664

r=me
Attachment #8799167 - Flags: review?(till) → review+
Comment on attachment 8799168 [details]
Bug 1185106 - Part 7.3: Add parser test for yield in async method.

https://reviewboard.mozilla.org/r/84452/#review87666

r=me
Attachment #8799168 - Flags: review?(till) → review+
Comment on attachment 8799169 [details]
Bug 1185106 - Part 8.1: Treat await as keyword in module.

https://reviewboard.mozilla.org/r/84454/#review87668

r=me
Attachment #8799169 - Flags: review?(till) → review+
Comment on attachment 8799170 [details]
Bug 1185106 - Part 8.2: Add parser test for await in module.

https://reviewboard.mozilla.org/r/84456/#review87670

r=me
Attachment #8799170 - Flags: review?(till) → review+
Comment on attachment 8799171 [details]
Bug 1185106 - Part 9.1: Support async function statement in export default in Parser.

https://reviewboard.mozilla.org/r/84458/#review87672

r=me
Attachment #8799171 - Flags: review?(till) → review+
Comment on attachment 8799172 [details]
Bug 1185106 - Part 9.2: Add parser test for async function statement in export default.

https://reviewboard.mozilla.org/r/84460/#review87674

r=me
Attachment #8799172 - Flags: review?(till) → review+
Comment on attachment 8799173 [details]
Bug 1185106 - Part 9.3: Add parser test for yield in async function statement in export default.

https://reviewboard.mozilla.org/r/84462/#review87676

r=me
Attachment #8799173 - Flags: review?(till) → review+
Comment on attachment 8799174 [details]
Bug 1185106 - Part 10.1: Support async arrow function in Parser.

https://reviewboard.mozilla.org/r/84464/#review87684

r=me with nit addressed.

::: js/src/frontend/Parser.cpp:7585
(Diff revision 1)
>  
> +        GeneratorKind generatorKind = NotGenerator;
> +        FunctionAsyncKind asyncKind = SyncFunction;
> +
> +#ifdef JS_HAS_ASYNC_FUNCS
> +        if (ignored == TOK_NAME) {

We're not really ignoring `ignored` anymore. Would be nice to have a better name for it.
Attachment #8799174 - Flags: review?(till) → review+
Comment on attachment 8799175 [details]
Bug 1185106 - Part 10.2: Support async arrow function in Reflect.parse.

https://reviewboard.mozilla.org/r/84466/#review87686

r=me
Attachment #8799175 - Flags: review?(till) → review+
Comment on attachment 8799176 [details]
Bug 1185106 - Part 10.3: Add parser test for async arrow function.

https://reviewboard.mozilla.org/r/84468/#review87688

r=me
Attachment #8799176 - Flags: review?(till) → review+
Comment on attachment 8799177 [details]
Bug 1185106 - Part 11.1: Implement async functions.

https://reviewboard.mozilla.org/r/84470/#review87696

This looks great!

I think you can ignore my comments about the self-hosted aspects for the most part. It'd be very nice to have a comment at the top of `AsyncFunctions.js` explaining how this all works and which code gets executed when.

r=me with feedback addressed.

::: js/src/builtin/AsyncFunctions.js:44
(Diff revision 1)
> +                        function(val) {
> +                            return AsyncFunction_resume(gen, val, gen.next);
> +                        }, function (err) {
> +                            return AsyncFunction_resume(gen, err, gen.throw);
> +                        });
> +}

I'm not convinced any of this code really should be JS. Are there any fundamental reasons why it's much simpler in JS? All functions here contain at least one C++ call, so we can't fully inline them anyway. And with the Promise code moving to C++, that's even more true.

It's fine to do this as a follow-up, but we should eventually do it because performance will be enough of a problem even without this overhead.

::: js/src/jsfun.cpp:1763
(Diff revision 1)
>       * and so would a call to f from another top-level's script or function.
>       */
>      RootedAtom anonymousAtom(cx, cx->names().anonymous);
>      RootedObject proto(cx);
>      if (isStarGenerator) {
> +        // isAsync should also use GeneratorFunction for unwrapped function.

I don't understand what this comment means. Can you expand it a bit?

::: js/src/jsfun.cpp:1888
(Diff revision 1)
>  {
> -    return FunctionConstructor(cx, argc, vp, StarGenerator);
> +    return FunctionConstructor(cx, argc, vp, StarGenerator, SyncFunction);
> +}
> +
> +bool
> +js::AsyncFunctionConstructor(JSContext* cx, unsigned argc, Value* vp)

It's pretty unfortunate that we call a JS function here that then calls another C++ function, so we're going through the JS/VM boundary twice. I wonder if it might not be possible to directly clone the inner function from `AsyncFunction_wrap` and synthesize and `environment` for it.

That'd be fine to do as a follow-up, though.

::: js/src/jsfun.cpp:1902
(Diff revision 1)
> +    if (!GlobalObject::getSelfHostedFunction(cx, cx->global(), shName, name, 1, &wrapFunc))
> +        return false;
> +
> +    RootedValue wrapped(cx);
> +    if (!Call(cx, wrapFunc, nullptr, args.rval(), &wrapped))
> +        return false;

All this could just be
```cpp
FixedInvokeArgs<1> args2(cx);
args2[0].set(args.rval());
return CallSelfHostedFunction(cx, cx->names().AsyncFunction_wrap, NullHandleValue, args2, args.rval()))
```
(Untested, so might contain slight errors, but you get the idea.)

::: js/src/vm/AsyncFunction.cpp:35
(Diff revision 1)
> +        return false;
> +    RootedObject proto(cx, &function.toObject());
> +    RootedAtom name(cx, cx->names().AsyncFunction);
> +    RootedObject asyncFunction(cx, NewFunctionWithProto(cx, AsyncFunctionConstructor, 1,
> +                                                        JSFunction::NATIVE_CTOR, nullptr, name,
> +                                                        proto));

This is needed because bug 1226261 isn't done, right? Assuming we keep all this as self-hosted code (see comment about that above), we really should land the patch for that bug and at least simplify and speed up this part of async functions.

::: js/src/vm/AsyncFunction.cpp:73
(Diff revision 1)
> +js::CreateAsyncFunction(JSContext* cx, HandleFunction wrapper, HandleFunction unwrapped,
> +                        MutableHandleFunction result)
> +{
> +    // Create a new function with AsyncFunctionPrototype, reusing the script
> +    // and the environment of `wrapper` function, and the name and the length
> +    // of `unwrapped` function.

Oh, I see. So the self-hosted code in `AsyncFunction_wrap` is only executed once. That makes it much more acceptable, and we can probably just leave it as-is.

::: js/src/vm/AsyncFunction.cpp:91
(Diff revision 1)
> +    // Link them each other to make GetWrappedAsyncFunction and
> +    // GetUnwrappedAsyncFunction work.
> +    unwrapped->setExtendedSlot(ASYNC_WRAPPED_SLOT, ObjectValue(*wrapped));
> +    wrapped->setExtendedSlot(ASYNC_UNWRAPPED_SLOT, ObjectValue(*unwrapped));
> +
> +    // The script od `wrapper` is self-hosted, so `wrapped` should also be

nit: s/od/of/
Attachment #8799177 - Flags: review?(till) → review+
Comment on attachment 8799178 [details]
Bug 1185106 - Part 11.2: Add helper functions for async/await test.

https://reviewboard.mozilla.org/r/84472/#review87714

r=me
Attachment #8799178 - Flags: review?(till) → review+
Comment on attachment 8799179 [details]
Bug 1185106 - Part 11.3: Add semantics test for async/await. .,till

https://reviewboard.mozilla.org/r/84474/#review87718

I didn't read these too closely, but they look ok at a glance. Would be nice to run the test262 tests for async/await, too.

My only request is to remove the license headers. r=me with that.
Attachment #8799179 - Flags: review?(till) → review+
Comment on attachment 8799180 [details]
Bug 1185106 - Part 11.4: Add function length test for async function.

https://reviewboard.mozilla.org/r/84476/#review87720

r=me
Attachment #8799180 - Flags: review?(till) → review+
Comment on attachment 8799181 [details]
Bug 1185106 - Part 11.5: Add async function constructor and prototype.

https://reviewboard.mozilla.org/r/84478/#review87722

r=me
Attachment #8799181 - Flags: review?(till) → review+
Comment on attachment 8799182 [details]
Bug 1185106 - Part 11.6: Add test for async function expression binding identity.

https://reviewboard.mozilla.org/r/84480/#review87724

r=me with license header removed.
Attachment #8799182 - Flags: review?(till) → review+
Comment on attachment 8799183 [details]
Bug 1185106 - Part 12: Return wrapped function for arguments.callee.

https://reviewboard.mozilla.org/r/84482/#review87738

r=me with feedback addressed and license header removed from test file.

::: js/src/js.msg:93
(Diff revision 1)
>  MSG_DEF(JSMSG_CANT_REDEFINE_PROP,      1, JSEXN_TYPEERR, "can't redefine non-configurable property {0}")
>  MSG_DEF(JSMSG_CANT_REDEFINE_ARRAY_LENGTH, 0, JSEXN_TYPEERR, "can't redefine array length")
>  MSG_DEF(JSMSG_CANT_DEFINE_PAST_ARRAY_LENGTH, 0, JSEXN_TYPEERR, "can't define array index property past the end of an array with non-writable length")
>  MSG_DEF(JSMSG_BAD_GET_SET_FIELD,       1, JSEXN_TYPEERR, "property descriptor's {0} field is neither undefined nor a function")
>  MSG_DEF(JSMSG_THROW_TYPE_ERROR,        0, JSEXN_TYPEERR, "'caller', 'callee', and 'arguments' properties may not be accessed on strict mode functions or the arguments objects for calls to them")
> +MSG_DEF(JSMSG_ASYNC_CALLEE,            0, JSEXN_TYPEERR, "'caller', 'callee', and 'arguments' properties may not be accessed on async function")

Nit: change "may not" to "can't"

But this isn't used, right? Is it a left-over from an earlier version of the spec draft that has since become redundant? If so, just remove it. If not, the tests below, and the behavior they test, are probably wrong.

(FWIW, I can't find any specific language about this in the spec, so our current behavior is probably correct.)
Attachment #8799183 - Flags: review?(till) → review+
Comment on attachment 8799184 [details]
Bug 1185106 - Part 13: Support async function in Function.prototype.toString.

https://reviewboard.mozilla.org/r/84484/#review87742

r=me
Attachment #8799184 - Flags: review?(till) → review+
Unsurprisingly, this is excellent work!

async/await just reached stage 4 at the last tc39 meeting, so we can land this and let it ride the trains without any feature flags or non-release-only restrictions.
Comment on attachment 8799152 [details]
Bug 1185106 - Part 0.1: Refactor JSOP_DEFFUN.

https://reviewboard.mozilla.org/r/84420/#review88054

LGTM
Attachment #8799152 - Flags: review?(hv1989) → review+
Comment on attachment 8799152 [details]
Bug 1185106 - Part 0.1: Refactor JSOP_DEFFUN.

https://reviewboard.mozilla.org/r/84420/#review87616

> Why isn't this needed anymore?

CloneFunctionObjectIfNotSingleton is already done in JSOP_LAMBDA, that is placed before JSOP_DEFFUN.
there is no need to do it once again.
Comment on attachment 8799177 [details]
Bug 1185106 - Part 11.1: Implement async functions.

https://reviewboard.mozilla.org/r/84470/#review87696

> I'm not convinced any of this code really should be JS. Are there any fundamental reasons why it's much simpler in JS? All functions here contain at least one C++ call, so we can't fully inline them anyway. And with the Promise code moving to C++, that's even more true.
> 
> It's fine to do this as a follow-up, but we should eventually do it because performance will be enough of a problem even without this overhead.

Currently it's so because of following reasons, and I thought self-hosted JS would be simpler.
  * to check if it's wrapper, by checking if it's self-hosted function (js::IsWrappedAsyncFunction)
  * to close `unwrapped` variable in `wrapper` function
I guess, they could be simply solved in different way in native function tho...

will file another bug for it after landing this and promise in c++.

> I don't understand what this comment means. Can you expand it a bit?

I meant, unwrapped function should be a generator while wrapped function (actual async function) isn't generator.
fixed the comment to say:
        // Unwrapped function of async function should use GeneratorFunction,
        // while wrapped function isn't generator.

> It's pretty unfortunate that we call a JS function here that then calls another C++ function, so we're going through the JS/VM boundary twice. I wonder if it might not be possible to directly clone the inner function from `AsyncFunction_wrap` and synthesize and `environment` for it.
> 
> That'd be fine to do as a follow-up, though.

this will also be addressed in the new bug above.

> This is needed because bug 1226261 isn't done, right? Assuming we keep all this as self-hosted code (see comment about that above), we really should land the patch for that bug and at least simplify and speed up this part of async functions.

It's just doing the same thing as other Function/GeneratorFunction ctors,
I don't see any relation between bug 1226261.

> Oh, I see. So the self-hosted code in `AsyncFunction_wrap` is only executed once. That makes it much more acceptable, and we can probably just leave it as-is.

Yes, it's executed once per single async function instance.
Comment on attachment 8799183 [details]
Bug 1185106 - Part 12: Return wrapped function for arguments.callee.

https://reviewboard.mozilla.org/r/84482/#review87738

> Nit: change "may not" to "can't"
> 
> But this isn't used, right? Is it a left-over from an earlier version of the spec draft that has since become redundant? If so, just remove it. If not, the tests below, and the behavior they test, are probably wrong.
> 
> (FWIW, I can't find any specific language about this in the spec, so our current behavior is probably correct.)

oops, it's from earlier version of the patch, that I was about to prohibit it (because `arguments.callee` is implementation defined thing, not specced).  but it turned out that it's easy to support, so I removed the code that throws, but forgot to remove the message :P
sorry, please ignore those additional requests :/
I was about to just update with correct reviewers list, but looks like mozreview asks extra review
Attachment #8799152 - Flags: review?(jdemooij)
Attachment #8799152 - Flags: review?(efaustbmo)
Attachment #8799153 - Flags: review?(efaustbmo)
Attachment #8799154 - Flags: review?(efaustbmo)
Attachment #8799155 - Flags: review?(efaustbmo)
Attachment #8799157 - Flags: review?(efaustbmo)
Attachment #8799158 - Flags: review?(efaustbmo)
Attachment #8799160 - Flags: review?(efaustbmo)
Attachment #8799161 - Flags: review?(efaustbmo)
Attachment #8799164 - Flags: review?(efaustbmo)
Attachment #8799166 - Flags: review?(efaustbmo)
Attachment #8799167 - Flags: review?(efaustbmo)
Attachment #8799169 - Flags: review?(efaustbmo)
Attachment #8799170 - Flags: review?(efaustbmo)
Attachment #8799171 - Flags: review?(efaustbmo)
Attachment #8799172 - Flags: review?(efaustbmo)
Attachment #8799175 - Flags: review?(efaustbmo)
Attachment #8799176 - Flags: review?(efaustbmo)
Attachment #8799179 - Flags: review?(efaustbmo)
Comment on attachment 8805536 [details] [diff] [review]
Part 14: Add AsyncFunction.prototype[@@toStringTag].

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

r=me
Attachment #8805536 - Flags: review?(till) → review+
forgot to handle object shorthand and object destructuring, when parsing property name.
property name can end with "=" and "}".

added TOK_RC and TOK_ASSIGN to tokens to stop parsing async method.
and added tests for object and destructuring with "async" names.

also added method testcases for numeric property and computed property.
Attachment #8805628 - Flags: review?(till)
Comment on attachment 8805628 [details] [diff] [review]
Part 7.4: Fix property name parsing with async name.

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

Great catch!
Attachment #8805628 - Flags: review?(till) → review+
Depends on: 1313764
https://hg.mozilla.org/integration/mozilla-inbound/rev/bc85cad3e93b19ea9a09c49d93b6010711f06fff
Bug 1185106 - Part 0.1: Refactor JSOP_DEFFUN. r=efaust,jandem,till,h4writer

https://hg.mozilla.org/integration/mozilla-inbound/rev/9a91fa1603c46e8ddeef15acc45887d74f39be21
Bug 1185106 - Part 1: Add AsyncFunction flag in FunctionBox, JSScript, and LazyScript. r=efaust,till

https://hg.mozilla.org/integration/mozilla-inbound/rev/be97b8687b6a0faf23743f7d8ce44c8cd4c08050
Bug 1185106 - Part 2: Add FunctionAsyncKind parameter to Parser methods that receives GeneratorKind. r=efaust,till

https://hg.mozilla.org/integration/mozilla-inbound/rev/86663fbc0899abb7782e39266df269df45eb0a21
Bug 1185106 - Part 3: Add await token. r=efaust,till

https://hg.mozilla.org/integration/mozilla-inbound/rev/549055084ab012587dafa202e07888074071ce6b
Bug 1185106 - Part 4: Add AutoAwaitIsKeyword class to set TokenStream.awaitIsKeyword. r=till

https://hg.mozilla.org/integration/mozilla-inbound/rev/1557532c15d1d8642115d3f1c2ac1c4685c3a48f
Bug 1185106 - Part 5.1: Support async function declaration in Parser. r=efaust,jwalden,till

https://hg.mozilla.org/integration/mozilla-inbound/rev/0572beaf72429bbffaeede34b8ce40829e62715b
Bug 1185106 - Part 5.2: Support async function declaration in Reflect.parse. r=efaust,till

https://hg.mozilla.org/integration/mozilla-inbound/rev/2465f743fb4f2b36e0a92a44a02f93472a1ad63e
Bug 1185106 - Part 5.3: Support await expression in Parser. r=till

https://hg.mozilla.org/integration/mozilla-inbound/rev/7dd9e2d62584ccfa708d322c55980015cea6df76
Bug 1185106 - Part 5.4: Support await expression in Reflect.parse. r=efaust,till

https://hg.mozilla.org/integration/mozilla-inbound/rev/a467817a09def09b9b9ed5fd88f905122af0d2ff
Bug 1185106 - Part 5.5: Add parser test for async function declaration. r=efaust,till

https://hg.mozilla.org/integration/mozilla-inbound/rev/ce9efeed3b8718a6a48c0d9f94b591343d5179af
Bug 1185106 - Part 5.6: Add parser test for yield in async function declaration. r=till

https://hg.mozilla.org/integration/mozilla-inbound/rev/eb5f24802ccbb0e44cf0448c9351755b93a15943
Bug 1185106 - Part 6.1: Support async function expression in Parser. r=till

https://hg.mozilla.org/integration/mozilla-inbound/rev/d19d9f409b751a282f60b9c5d0a0a284004b6fb4
Bug 1185106 - Part 6.2: Add parser test for async function expression. r=efaust,till

https://hg.mozilla.org/integration/mozilla-inbound/rev/1a245de062189dcefd7488ac740c66d30e5e2a65
Bug 1185106 - Part 6.3: Add parser test for yield in async function expression. r=till

https://hg.mozilla.org/integration/mozilla-inbound/rev/c6af45aef3045102fc696e52e468da0e55e3928b
Bug 1185106 - Part 7.1: Support async method in Parser. r=efaust,jwalden,till

https://hg.mozilla.org/integration/mozilla-inbound/rev/3c623f1b1404e2627fd054f648d567b1c0b02ec6
Bug 1185106 - Part 7.2: Add parser test for async method. r=efaust,till

https://hg.mozilla.org/integration/mozilla-inbound/rev/f43c3c900fd72163fb8083601c2719a5c0246ed4
Bug 1185106 - Part 7.3: Add parser test for yield in async method. r=till

https://hg.mozilla.org/integration/mozilla-inbound/rev/203903ea62ec88835f67ffaf938d39745461d486
Bug 1185106 - Part 7.4: Fix property name parsing with async name. r=till

https://hg.mozilla.org/integration/mozilla-inbound/rev/0f59ff767344e7856642447f5e9a3679cc2fe4ab
Bug 1185106 - Part 8.1: Treat await as keyword in module. r=efaust,till

https://hg.mozilla.org/integration/mozilla-inbound/rev/92f7082a90be77700618e8176c73ad7538ee75a3
Bug 1185106 - Part 8.2: Add parser test for await in module. r=efaust,till

https://hg.mozilla.org/integration/mozilla-inbound/rev/0e9b413f34392cd8e1bdda5cb230091a204fb5ef
Bug 1185106 - Part 9.1: Support async function statement in export default in Parser. r=efaust,till

https://hg.mozilla.org/integration/mozilla-inbound/rev/e042b0dba45525afea60180c2851bee4785a1855
Bug 1185106 - Part 9.2: Add parser test for async function statement in export default. r=efaust,till

https://hg.mozilla.org/integration/mozilla-inbound/rev/fe120f64b871c96744c63d6530f41f83022511c2
Bug 1185106 - Part 9.3: Add parser test for yield in async function statement in export default. r=till

https://hg.mozilla.org/integration/mozilla-inbound/rev/3a03d945279843d6eaa80ff56af174e0b45abf7d
Bug 1185106 - Part 10.1: Support async arrow function in Parser. r=till

https://hg.mozilla.org/integration/mozilla-inbound/rev/3e7d781a99640e24397d87c6d31bc8de45f60a8e
Bug 1185106 - Part 10.2: Support async arrow function in Reflect.parse. r=efaust,till

https://hg.mozilla.org/integration/mozilla-inbound/rev/b33af49c646c8709c004bd09191298f1153d593d
Bug 1185106 - Part 10.3: Add parser test for async arrow function. r=efaust,till

https://hg.mozilla.org/integration/mozilla-inbound/rev/5ab01476a1ccebc49962acd2737980fa6ec1f69f
Bug 1185106 - Part 11.1: Implement async functions. r=till

https://hg.mozilla.org/integration/mozilla-inbound/rev/61f472bbdbc1d8a095d1375e59423027fd736e70
Bug 1185106 - Part 11.2: Add helper functions for async/await test. r=till

https://hg.mozilla.org/integration/mozilla-inbound/rev/4bfb6261bdc98c47a4cc3b5d42ee89667e6016df
Bug 1185106 - Part 11.3: Add semantics test for async/await. r=efaust,till

https://hg.mozilla.org/integration/mozilla-inbound/rev/707c862f4d63f444a307aca6f7f5ecf1bd0cc070
Bug 1185106 - Part 11.4: Add function length test for async function. r=till

https://hg.mozilla.org/integration/mozilla-inbound/rev/a141cb00c7deef08035c09de9ebd720fd74ff7a7
Bug 1185106 - Part 11.5: Add async function constructor and prototype. r=till

https://hg.mozilla.org/integration/mozilla-inbound/rev/4dbc392a25d8a1978b5e9802561375b502d19c19
Bug 1185106 - Part 11.6: Add test for async function expression binding identity. r=till

https://hg.mozilla.org/integration/mozilla-inbound/rev/0df8a2814d0c6a7cb905086ffef6c4236fa4e2cf
Bug 1185106 - Part 12: Return wrapped function for arguments.callee. r=till

https://hg.mozilla.org/integration/mozilla-inbound/rev/6b10479b988db3c3d668611ed75791424503afd2
Bug 1185106 - Part 13: Support async function in Function.prototype.toString. r=till

https://hg.mozilla.org/integration/mozilla-inbound/rev/8fae1fb3e02eef78e34aeafb662cbc54496521e1
Bug 1185106 - Part 14: Add AsyncFunction.prototype[@@toStringTag]. r=till
Blocks: 1313956
https://hg.mozilla.org/mozilla-central/rev/bc85cad3e93b
https://hg.mozilla.org/mozilla-central/rev/9a91fa1603c4
https://hg.mozilla.org/mozilla-central/rev/be97b8687b6a
https://hg.mozilla.org/mozilla-central/rev/86663fbc0899
https://hg.mozilla.org/mozilla-central/rev/549055084ab0
https://hg.mozilla.org/mozilla-central/rev/1557532c15d1
https://hg.mozilla.org/mozilla-central/rev/0572beaf7242
https://hg.mozilla.org/mozilla-central/rev/2465f743fb4f
https://hg.mozilla.org/mozilla-central/rev/7dd9e2d62584
https://hg.mozilla.org/mozilla-central/rev/a467817a09de
https://hg.mozilla.org/mozilla-central/rev/ce9efeed3b87
https://hg.mozilla.org/mozilla-central/rev/eb5f24802ccb
https://hg.mozilla.org/mozilla-central/rev/d19d9f409b75
https://hg.mozilla.org/mozilla-central/rev/1a245de06218
https://hg.mozilla.org/mozilla-central/rev/c6af45aef304
https://hg.mozilla.org/mozilla-central/rev/3c623f1b1404
https://hg.mozilla.org/mozilla-central/rev/f43c3c900fd7
https://hg.mozilla.org/mozilla-central/rev/203903ea62ec
https://hg.mozilla.org/mozilla-central/rev/0f59ff767344
https://hg.mozilla.org/mozilla-central/rev/92f7082a90be
https://hg.mozilla.org/mozilla-central/rev/0e9b413f3439
https://hg.mozilla.org/mozilla-central/rev/e042b0dba455
https://hg.mozilla.org/mozilla-central/rev/fe120f64b871
https://hg.mozilla.org/mozilla-central/rev/3a03d9452798
https://hg.mozilla.org/mozilla-central/rev/3e7d781a9964
https://hg.mozilla.org/mozilla-central/rev/b33af49c646c
https://hg.mozilla.org/mozilla-central/rev/5ab01476a1cc
https://hg.mozilla.org/mozilla-central/rev/61f472bbdbc1
https://hg.mozilla.org/mozilla-central/rev/4bfb6261bdc9
https://hg.mozilla.org/mozilla-central/rev/707c862f4d63
https://hg.mozilla.org/mozilla-central/rev/a141cb00c7de
https://hg.mozilla.org/mozilla-central/rev/4dbc392a25d8
https://hg.mozilla.org/mozilla-central/rev/0df8a2814d0c
https://hg.mozilla.org/mozilla-central/rev/6b10479b988d
https://hg.mozilla.org/mozilla-central/rev/8fae1fb3e02e
Status: ASSIGNED → RESOLVED
Closed: 8 years ago
Keywords: leave-open
Resolution: --- → FIXED
See Also: → 1314055
Depends on: 1314128
Blocks: html5test
Blocks: 1314176
See Also: → 1305261
Changing Expected Publication Year
https://github.com/tc39/proposals/blob/master/finished-proposals.md
Summary: Implement async functions (ES7 proposal) → Implement async functions (ES 2017 proposal)
Depends on: 1316166
No longer blocks: 1314176
Release Note Request (optional, but appreciated)
[Why is this notable]:
[Affects Firefox for Android]:
[Suggested wording]:
[Links (documentation, blog post, etc)]:
relnote-firefox: --- → ?
Depends on: 1320697
Thanks a lot for writing the docs, arai! Let's finish them in bug 1305261.
Depends on: 1331009
Target Milestone: --- → mozilla52
Depends on: 1345960
Depends on: 1345968
Depends on: 1437125
You need to log in before you can comment on or make changes to this bug.