Skip to content

Commit

Permalink
#521: baseline parser support for async/await, with toggle, without b…
Browse files Browse the repository at this point in the history
…ytecode (passes tests)
  • Loading branch information
classilla committed Aug 18, 2019
1 parent 3fd15a8 commit 0e5746a
Show file tree
Hide file tree
Showing 39 changed files with 1,236 additions and 91 deletions.
51 changes: 51 additions & 0 deletions js/src/builtin/AsyncFunctions.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
/* 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
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */

function AsyncFunction_wrap(genFunction) {
var wrapper = function() {
// The try block is required to handle throws in default arguments properly.
try {
return AsyncFunction_start(callFunction(std_Function_apply, genFunction, this, arguments));
} catch (e) {
return Promise_reject(e);
}
};
/* not yet
std_Object_setPrototypeOf(wrapper, GetBuiltinPrototype("AsyncFunction"));
*/
_DefineDataProperty(wrapper, "length", genFunction.length);
SetFunctionExtendedSlot(genFunction, 1, wrapper);
var name = GetFunName(genFunction);
if (typeof name !== 'undefined')
SetFunName(wrapper, name);
return wrapper;
}

function AsyncFunction_start(generator) {
return AsyncFunction_resume(generator, undefined, generator.next);
}

function AsyncFunction_resume(gen, v, method) {
let result;
try {
// get back into async function, run to next await point
result = callFunction(method, gen, v);
} catch (exc) {
// The async function itself failed.
return Promise_reject(exc);
}

if (result.done)
return Promise_resolve(result.value);

// If we get here, `await` occurred. `gen` is paused at a yield point.
return callFunction(Promise_then,
Promise_resolve(result.value),
function(val) {
return AsyncFunction_resume(gen, val, gen.next);
}, function (err) {
return AsyncFunction_resume(gen, err, gen.throw);
});
}

142 changes: 142 additions & 0 deletions js/src/builtin/Promise.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,142 @@
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
* vim: set ts=8 sts=4 et sw=4 tw=99:
* 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
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */

#include "builtin/Promise.h"

#include "jscntxt.h"

#include "builtin/SelfHostingDefines.h"

#include "jsobjinlines.h"

using namespace js;

static const JSFunctionSpec promise_methods[] = {
JS_SELF_HOSTED_FN("catch", "Promise_catch", 1, 0),
JS_SELF_HOSTED_FN("then", "Promise_then", 2, 0),
JS_FS_END
};

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("resolve", "Promise_resolve", 1, 0),
JS_FS_END
};

namespace js {

bool
PromiseConstructor(JSContext* cx, unsigned argc, Value* vp)
{
CallArgs args = CallArgsFromVp(argc, vp);

if (args.length() == 0) {
JS_ReportErrorNumber(cx, GetErrorMessage, nullptr, JSMSG_MORE_ARGS_NEEDED,
"ShellPromise.constructor", "0", "s");
return false;
}

HandleValue fn = args.get(0);

if (!IsCallable(fn)) {
JS_ReportErrorNumber(cx, GetErrorMessage, nullptr, JSMSG_NOT_CALLABLE,
"Argument 1 of ShellPromise.constructor");
return false;
}

RootedObject promise(cx, NewBuiltinClassInstance(cx, &ShellPromiseObject::class_));
if (!promise)
return false;

JS_SetReservedSlot(promise, PROMISE_STATE_SLOT, NumberValue(PROMISE_STATE_PENDING));
JS_SetReservedSlot(promise, PROMISE_VALUE_SLOT, NullValue());
JS_SetReservedSlot(promise, PROMISE_DEFERREDS_SLOT, NullValue());

RootedValue initRval(cx);
JS::AutoValueVector argValues(cx);
argValues.append(ObjectValue(*promise));
argValues.append(fn);
HandleValueArray arr(argValues);

JSAtom* promiseInitAtom;
if (!(promiseInitAtom = Atomize(cx, "Promise_init", 12)))
return false;

RootedPropertyName name(cx, promiseInitAtom->asPropertyName());
RootedValue selfHostedFun(cx);

if (!GlobalObject::getIntrinsicValue(cx, cx->global(), name, &selfHostedFun))
return false;

if (!JS_CallFunctionValue(cx, promise, selfHostedFun, arr, &initRval))
return false;

args.rval().setObject(*promise);

return true;
}

}

static JSObject*
CreatePromisePrototype(JSContext* cx, JSProtoKey key)
{
return cx->global()->createBlankPrototype(cx, &ShellPromiseObject::protoClass_);
}

const Class ShellPromiseObject::class_ = {
"ShellPromise",
JSCLASS_HAS_RESERVED_SLOTS(RESERVED_SLOTS) | JSCLASS_HAS_CACHED_PROTO(JSProto_ShellPromise),
nullptr, /* addProperty */
nullptr, /* delProperty */
nullptr, /* getProperty */
nullptr, /* setProperty */
nullptr, /* enumerate */
nullptr, /* resolve */
nullptr, /* mayResolve */
nullptr, /* finalize */
nullptr, /* call */
nullptr, /* hasInstance */
nullptr, /* construct */
nullptr, /* trace */
{
GenericCreateConstructor<PromiseConstructor, 2, gc::AllocKind::FUNCTION>,
CreatePromisePrototype,
promise_static_methods,
nullptr,
promise_methods
}
};

const Class ShellPromiseObject::protoClass_ = {
"ShellPromise",
JSCLASS_HAS_CACHED_PROTO(JSProto_ShellPromise),
nullptr, /* addProperty */
nullptr, /* delProperty */
nullptr, /* getProperty */
nullptr, /* setProperty */
nullptr, /* enumerate */
nullptr, /* resolve */
nullptr, /* mayResolve */
nullptr, /* finalize */
nullptr, /* call */
nullptr, /* hasInstance */
nullptr, /* construct */
nullptr, /* trace */
{
DELEGATED_CLASSSPEC(&ShellPromiseObject::class_.spec),
nullptr,
nullptr,
nullptr,
nullptr,
nullptr,
nullptr,
ClassSpec::IsDelegated
}
};

29 changes: 29 additions & 0 deletions js/src/builtin/Promise.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
* vim: set ts=8 sts=4 et sw=4 tw=99:
* 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
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */

#ifndef builtin_Promise_h
#define builtin_Promise_h

#include "vm/NativeObject.h"

namespace js {

class AutoSetNewObjectMetadata;

class ShellPromiseObject : public NativeObject
{
public:
static const unsigned RESERVED_SLOTS = 3;
static const Class class_;
static const Class protoClass_;
};

bool
PromiseConstructor(JSContext* cx, unsigned argc, Value* vp);

} // namespace js

#endif /* builtin_Promise_h */
Loading

0 comments on commit 0e5746a

Please sign in to comment.