--- a/js/public/Class.h
+++ b/js/public/Class.h
@@ -780,17 +780,17 @@ struct JSClass {
// with the following flags. Failure to use JSCLASS_GLOBAL_FLAGS was
// previously allowed, but is now an ES5 violation and thus unsupported.
//
// JSCLASS_GLOBAL_APPLICATION_SLOTS is the number of slots reserved at
// the beginning of every global object's slots for use by the
// application.
#define JSCLASS_GLOBAL_APPLICATION_SLOTS 5
#define JSCLASS_GLOBAL_SLOT_COUNT \
- (JSCLASS_GLOBAL_APPLICATION_SLOTS + JSProto_LIMIT * 2 + 37)
+ (JSCLASS_GLOBAL_APPLICATION_SLOTS + JSProto_LIMIT * 2 + 39)
#define JSCLASS_GLOBAL_FLAGS_WITH_SLOTS(n) \
(JSCLASS_IS_GLOBAL | JSCLASS_HAS_RESERVED_SLOTS(JSCLASS_GLOBAL_SLOT_COUNT + (n)))
#define JSCLASS_GLOBAL_FLAGS \
JSCLASS_GLOBAL_FLAGS_WITH_SLOTS(0)
#define JSCLASS_HAS_GLOBAL_FLAG_AND_SLOTS(clasp) \
(((clasp)->flags & JSCLASS_IS_GLOBAL) \
&& JSCLASS_RESERVED_SLOTS(clasp) >= JSCLASS_GLOBAL_SLOT_COUNT)
new file mode 100644
--- /dev/null
+++ b/js/src/builtin/AsyncFunctions.js
@@ -0,0 +1,47 @@
+/* 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/. */
+
+// Called when creating async function.
+// See the comment for js::CreateAsyncFunction what unwrapped, wrapped and the
+// return value are.
+function AsyncFunction_wrap(unwrapped) {
+ var wrapper = function() {
+ // The try block is required to handle throws in default arguments properly.
+ try {
+ return AsyncFunction_start(callFunction(std_Function_apply, unwrapped, this, arguments));
+ } catch (e) {
+ var promiseCtor = GetBuiltinConstructor('Promise');
+ return callFunction(Promise_static_reject, promiseCtor, e);
+ }
+ };
+ return CreateAsyncFunction(wrapper, unwrapped);
+}
+
+function AsyncFunction_start(generator) {
+ return AsyncFunction_resume(generator, undefined, generator.next);
+}
+
+function AsyncFunction_resume(gen, v, method) {
+ var promiseCtor = GetBuiltinConstructor('Promise');
+ 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 callFunction(Promise_static_reject, promiseCtor, exc);
+ }
+
+ if (result.done)
+ return callFunction(Promise_static_resolve, promiseCtor, result.value);
+
+ // If we get here, `await` occurred. `gen` is paused at a yield point.
+ return callFunction(Promise_then,
+ callFunction(Promise_static_resolve, promiseCtor, result.value),
+ function(val) {
+ return AsyncFunction_resume(gen, val, gen.next);
+ }, function (err) {
+ return AsyncFunction_resume(gen, err, gen.throw);
+ });
+}
--- a/js/src/builtin/Promise.cpp
+++ b/js/src/builtin/Promise.cpp
@@ -674,27 +674,27 @@ CommonStaticResolveRejectImpl(JSContext*
// Step 6 of Resolve, 4 of Reject.
args.rval().setObject(*promise);
return true;
}
/**
* ES2016, 25.4.4.4, Promise.reject.
*/
-static bool
-Promise_reject(JSContext* cx, unsigned argc, Value* vp)
+bool
+js::Promise_reject(JSContext* cx, unsigned argc, Value* vp)
{
return CommonStaticResolveRejectImpl(cx, argc, vp, RejectMode);
}
/**
* ES2016, 25.4.4.5, Promise.resolve.
*/
-static bool
-Promise_resolve(JSContext* cx, unsigned argc, Value* vp)
+bool
+js::Promise_resolve(JSContext* cx, unsigned argc, Value* vp)
{
return CommonStaticResolveRejectImpl(cx, argc, vp, ResolveMode);
}
// ES2016, February 12 draft, 25.4.3.1. steps 3-11.
/* static */
PromiseObject*
PromiseObject::create(JSContext* cx, HandleObject executor, HandleObject proto /* = nullptr */)
--- a/js/src/builtin/Promise.h
+++ b/js/src/builtin/Promise.h
@@ -138,11 +138,16 @@ class PromiseTask : public JS::AsyncTask
// Called on a helper thread after StartAsyncTask. After execute()
// completes, the JS::FinishAsyncTaskCallback will be called. If this fails
// the task will be enqueued for deletion at some future point without ever
// calling finishPromise().
virtual void execute() = 0;
};
+bool
+Promise_resolve(JSContext* cx, unsigned argc, Value* vp);
+bool
+Promise_reject(JSContext* cx, unsigned argc, Value* vp);
+
} // namespace js
#endif /* builtin_Promise_h */
--- a/js/src/builtin/SelfHostingDefines.h
+++ b/js/src/builtin/SelfHostingDefines.h
@@ -115,16 +115,19 @@
#define REGEXP_FLAGS_SLOT 2
#define REGEXP_IGNORECASE_FLAG 0x01
#define REGEXP_GLOBAL_FLAG 0x02
#define REGEXP_MULTILINE_FLAG 0x04
#define REGEXP_STICKY_FLAG 0x08
#define REGEXP_UNICODE_FLAG 0x10
+#define ASYNC_WRAPPED_SLOT 1
+#define ASYNC_UNWRAPPED_SLOT 1
+
#define MODULE_OBJECT_ENVIRONMENT_SLOT 2
#define MODULE_STATE_FAILED 0
#define MODULE_STATE_PARSED 1
#define MODULE_STATE_INSTANTIATED 2
#define MODULE_STATE_EVALUATED 3
#endif
--- a/js/src/frontend/BytecodeCompiler.cpp
+++ b/js/src/frontend/BytecodeCompiler.cpp
@@ -58,17 +58,17 @@ class MOZ_STACK_CLASS BytecodeCompiler
// Call setters for optional arguments.
void maybeSetSourceCompressor(SourceCompressionTask* sourceCompressor);
void setSourceArgumentsNotIncluded();
JSScript* compileGlobalScript(ScopeKind scopeKind);
JSScript* compileEvalScript(HandleObject environment, HandleScope enclosingScope);
ModuleObject* compileModule();
bool compileFunctionBody(MutableHandleFunction fun, Handle<PropertyNameVector> formals,
- GeneratorKind generatorKind);
+ GeneratorKind generatorKind, FunctionAsyncKind asyncKind);
ScriptSourceObject* sourceObjectPtr() const;
private:
JSScript* compileScript(HandleObject environment, SharedContext* sc);
bool checkLength();
bool createScriptSource();
bool maybeCompressSource();
@@ -430,17 +430,18 @@ BytecodeCompiler::compileModule()
MOZ_ASSERT_IF(cx->isJSContext(), !cx->asJSContext()->isExceptionPending());
return module;
}
bool
BytecodeCompiler::compileFunctionBody(MutableHandleFunction fun,
Handle<PropertyNameVector> formals,
- GeneratorKind generatorKind)
+ GeneratorKind generatorKind,
+ FunctionAsyncKind asyncKind)
{
MOZ_ASSERT(fun);
MOZ_ASSERT(fun->isTenured());
fun->setArgCount(formals.length());
if (!createSourceAndParser())
return false;
@@ -448,18 +449,18 @@ BytecodeCompiler::compileFunctionBody(Mu
// Speculatively parse using the default directives implied by the context.
// If a directive is encountered (e.g., "use strict") that changes how the
// function should have been parsed, we backup and reparse with the new set
// of directives.
ParseNode* fn;
do {
Directives newDirectives = directives;
- fn = parser->standaloneFunctionBody(fun, enclosingScope, formals, generatorKind,
- SyncFunction, directives, &newDirectives);
+ fn = parser->standaloneFunctionBody(fun, enclosingScope, formals, generatorKind, asyncKind,
+ directives, &newDirectives);
if (!fn && !handleParseFailure(newDirectives))
return false;
} while (!fn);
if (!NameFunctions(cx, fn))
return false;
if (fn->pn_funbox->function()->isInterpreted()) {
@@ -675,51 +676,63 @@ frontend::CompileLazyFunction(JSContext*
return bce.emitFunctionScript(pn->pn_body);
}
// Compile a JS function body, which might appear as the value of an event
// handler attribute in an HTML <INPUT> tag, or in a Function() constructor.
static bool
CompileFunctionBody(JSContext* cx, MutableHandleFunction fun, const ReadOnlyCompileOptions& options,
Handle<PropertyNameVector> formals, SourceBufferHolder& srcBuf,
- HandleScope enclosingScope, GeneratorKind generatorKind)
+ HandleScope enclosingScope, GeneratorKind generatorKind,
+ FunctionAsyncKind asyncKind)
{
MOZ_ASSERT(!options.isRunOnce);
// FIXME: make Function pass in two strings and parse them as arguments and
// ProgramElements respectively.
BytecodeCompiler compiler(cx, cx->tempLifoAlloc(), options, srcBuf, enclosingScope,
TraceLogger_ParserCompileFunction);
compiler.setSourceArgumentsNotIncluded();
- return compiler.compileFunctionBody(fun, formals, generatorKind);
+ return compiler.compileFunctionBody(fun, formals, generatorKind, asyncKind);
}
bool
frontend::CompileFunctionBody(JSContext* cx, MutableHandleFunction fun,
const ReadOnlyCompileOptions& options,
Handle<PropertyNameVector> formals, JS::SourceBufferHolder& srcBuf,
HandleScope enclosingScope)
{
- return CompileFunctionBody(cx, fun, options, formals, srcBuf, enclosingScope, NotGenerator);
+ return CompileFunctionBody(cx, fun, options, formals, srcBuf, enclosingScope, NotGenerator,
+ SyncFunction);
}
bool
frontend::CompileFunctionBody(JSContext* cx, MutableHandleFunction fun,
const ReadOnlyCompileOptions& options,
Handle<PropertyNameVector> formals, JS::SourceBufferHolder& srcBuf)
{
RootedScope emptyGlobalScope(cx, &cx->global()->emptyGlobalScope());
return CompileFunctionBody(cx, fun, options, formals, srcBuf, emptyGlobalScope,
- NotGenerator);
+ NotGenerator, SyncFunction);
}
-
bool
frontend::CompileStarGeneratorBody(JSContext* cx, MutableHandleFunction fun,
const ReadOnlyCompileOptions& options,
Handle<PropertyNameVector> formals,
JS::SourceBufferHolder& srcBuf)
{
RootedScope emptyGlobalScope(cx, &cx->global()->emptyGlobalScope());
return CompileFunctionBody(cx, fun, options, formals, srcBuf, emptyGlobalScope,
- StarGenerator);
+ StarGenerator, SyncFunction);
}
+
+bool
+frontend::CompileAsyncFunctionBody(JSContext* cx, MutableHandleFunction fun,
+ const ReadOnlyCompileOptions& options,
+ Handle<PropertyNameVector> formals,
+ JS::SourceBufferHolder& srcBuf)
+{
+ RootedScope emptyGlobalScope(cx, &cx->global()->emptyGlobalScope());
+ return CompileFunctionBody(cx, fun, options, formals, srcBuf, emptyGlobalScope,
+ StarGenerator, AsyncFunction);
+}
--- a/js/src/frontend/BytecodeCompiler.h
+++ b/js/src/frontend/BytecodeCompiler.h
@@ -63,16 +63,21 @@ CompileFunctionBody(JSContext* cx, Mutab
const ReadOnlyCompileOptions& options,
Handle<PropertyNameVector> formals, JS::SourceBufferHolder& srcBuf);
MOZ_MUST_USE bool
CompileStarGeneratorBody(JSContext* cx, MutableHandleFunction fun,
const ReadOnlyCompileOptions& options,
Handle<PropertyNameVector> formals, JS::SourceBufferHolder& srcBuf);
+MOZ_MUST_USE bool
+CompileAsyncFunctionBody(JSContext* cx, MutableHandleFunction fun,
+ const ReadOnlyCompileOptions& options,
+ Handle<PropertyNameVector> formals, JS::SourceBufferHolder& srcBuf);
+
ScriptSourceObject*
CreateScriptSourceObject(ExclusiveContext* cx, const ReadOnlyCompileOptions& options);
/*
* True if str consists of an IdentifierStart character, followed by one or
* more IdentifierPart characters, i.e. it matches the IdentifierName production
* in the language spec.
*
--- a/js/src/frontend/BytecodeEmitter.cpp
+++ b/js/src/frontend/BytecodeEmitter.cpp
@@ -6924,16 +6924,21 @@ BytecodeEmitter::emitFunction(ParseNode*
/* Make the function object a literal in the outer script's pool. */
unsigned index = objectList.add(pn->pn_funbox);
/* 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 (funbox->isAsync()) {
+ MOZ_ASSERT(!needsProto);
+ return emitAsyncWrapper(index, funbox->needsHomeObject(), fun->isArrow());
+ }
+
if (fun->isArrow()) {
if (sc->allowNewTarget()) {
if (!emit1(JSOP_NEWTARGET))
return false;
} else {
if (!emit1(JSOP_NULL))
return false;
}
@@ -6975,42 +6980,120 @@ BytecodeEmitter::emitFunction(ParseNode*
RootedModuleObject module(cx, sc->asModuleContext()->module());
if (!module->noteFunctionDeclaration(cx, name, fun))
return false;
} else {
MOZ_ASSERT(sc->isGlobalContext() || sc->isEvalContext());
MOZ_ASSERT(pn->getOp() == JSOP_NOP);
switchToPrologue();
- if (!emitIndex32(JSOP_LAMBDA, index))
- return false;
+ if (funbox->isAsync()) {
+ if (!emitAsyncWrapper(index, fun->isMethod(), fun->isArrow()))
+ return false;
+ } else {
+ if (!emitIndex32(JSOP_LAMBDA, index))
+ return false;
+ }
if (!emit1(JSOP_DEFFUN))
return false;
if (!updateSourceCoordNotes(pn->pn_pos.begin))
return false;
switchToMain();
}
} else {
// For functions nested within functions and blocks, make a lambda and
// initialize the binding name of the function in the current scope.
- auto emitLambda = [index](BytecodeEmitter* bce, const NameLocation&, bool) {
+ bool isAsync = funbox->isAsync();
+ auto emitLambda = [index, isAsync](BytecodeEmitter* bce, const NameLocation&, bool) {
+ if (isAsync) {
+ return bce->emitAsyncWrapper(index, /* needsHomeObject = */ false,
+ /* isArrow = */ false);
+ }
return bce->emitIndexOp(JSOP_LAMBDA, index);
};
if (!emitInitializeName(name, emitLambda))
return false;
if (!emit1(JSOP_POP))
return false;
}
return true;
}
bool
+BytecodeEmitter::emitAsyncWrapperLambda(unsigned index, bool isArrow) {
+ if (isArrow) {
+ if (sc->allowNewTarget()) {
+ if (!emit1(JSOP_NEWTARGET))
+ return false;
+ } else {
+ if (!emit1(JSOP_NULL))
+ return false;
+ }
+ if (!emitIndex32(JSOP_LAMBDA_ARROW, index))
+ return false;
+ } else {
+ if (!emitIndex32(JSOP_LAMBDA, index))
+ return false;
+ }
+
+ return true;
+}
+
+bool
+BytecodeEmitter::emitAsyncWrapper(unsigned index, bool needsHomeObject, bool isArrow) {
+ // needsHomeObject can be true for propertyList for extended class.
+ // In that case push both unwrapped and wrapped function, in order to
+ // initialize home object of unwrapped function, and set wrapped function
+ // as a property.
+ //
+ // lambda // unwrapped
+ // getintrinsic // unwrapped AsyncFunction_wrap
+ // undefined // unwrapped AsyncFunction_wrap undefined
+ // dupat 2 // unwrapped AsyncFunction_wrap undefined unwrapped
+ // call 1 // unwrapped wrapped
+ //
+ // Emitted code is surrounded by the following code.
+ //
+ // // classObj classCtor classProto
+ // (emitted code) // classObj classCtor classProto unwrapped wrapped
+ // swap // classObj classCtor classProto wrapped unwrapped
+ // inithomeobject 1 // classObj classCtor classProto wrapped unwrapped
+ // // initialize the home object of unwrapped
+ // // with classProto here
+ // pop // classObj classCtor classProto wrapped
+ // inithiddenprop // classObj classCtor classProto wrapped
+ // // initialize the property of the classProto
+ // // with wrapped function here
+ // pop // classObj classCtor classProto
+ //
+ // needsHomeObject is false for other cases, push wrapped function only.
+ if (needsHomeObject) {
+ if (!emitAsyncWrapperLambda(index, isArrow))
+ return false;
+ }
+ if (!emitAtomOp(cx->names().AsyncFunction_wrap, JSOP_GETINTRINSIC))
+ return false;
+ if (!emit1(JSOP_UNDEFINED))
+ return false;
+ if (needsHomeObject) {
+ if (!emitDupAt(2))
+ return false;
+ } else {
+ if (!emitAsyncWrapperLambda(index, isArrow))
+ return false;
+ }
+ if (!emitCall(JSOP_CALL, 1))
+ return false;
+ return true;
+}
+
+bool
BytecodeEmitter::emitDo(ParseNode* pn)
{
/* Emit an annotated nop so IonBuilder can recognize the 'do' loop. */
unsigned noteIndex;
if (!newSrcNote(SRC_WHILE, ¬eIndex))
return false;
if (!emit1(JSOP_NOP))
return false;
@@ -8381,18 +8464,27 @@ BytecodeEmitter::emitPropertyList(ParseN
if (op == JSOP_INITPROP_GETTER || op == JSOP_INITPROP_SETTER)
objp.set(nullptr);
if (propdef->pn_right->isKind(PNK_FUNCTION) &&
propdef->pn_right->pn_funbox->needsHomeObject())
{
MOZ_ASSERT(propdef->pn_right->pn_funbox->function()->allowSuperProperty());
- if (!emit2(JSOP_INITHOMEOBJECT, isIndex))
- return false;
+ bool isAsync = propdef->pn_right->pn_funbox->isAsync();
+ if (isAsync) {
+ if (!emit1(JSOP_SWAP))
+ return false;
+ }
+ if (!emit2(JSOP_INITHOMEOBJECT, isIndex + isAsync))
+ return false;
+ if (isAsync) {
+ if (!emit1(JSOP_POP))
+ return false;
+ }
}
// Class methods are not enumerable.
if (type == ClassBody) {
switch (op) {
case JSOP_INITPROP: op = JSOP_INITHIDDENPROP; break;
case JSOP_INITPROP_GETTER: op = JSOP_INITHIDDENPROP_GETTER; break;
case JSOP_INITPROP_SETTER: op = JSOP_INITHIDDENPROP_SETTER; break;
--- a/js/src/frontend/BytecodeEmitter.h
+++ b/js/src/frontend/BytecodeEmitter.h
@@ -598,16 +598,19 @@ struct MOZ_STACK_CLASS BytecodeEmitter
MOZ_MUST_USE bool emitYield(ParseNode* pn);
MOZ_MUST_USE bool emitYieldOp(JSOp op);
MOZ_MUST_USE bool emitYieldStar(ParseNode* iter, ParseNode* gen);
MOZ_MUST_USE bool emitPropLHS(ParseNode* pn);
MOZ_MUST_USE bool emitPropOp(ParseNode* pn, JSOp op);
MOZ_MUST_USE bool emitPropIncDec(ParseNode* pn);
+ MOZ_MUST_USE bool emitAsyncWrapperLambda(unsigned index, bool isArrow);
+ MOZ_MUST_USE bool emitAsyncWrapper(unsigned index, bool needsHomeObject, bool isArrow);
+
MOZ_MUST_USE bool emitComputedPropertyName(ParseNode* computedPropName);
// Emit bytecode to put operands for a JSOP_GETELEM/CALLELEM/SETELEM/DELELEM
// opcode onto the stack in the right order. In the case of SETELEM, the
// value to be assigned must already be pushed.
enum class EmitElemOption { Get, Set, Call, IncDec, CompoundAssign };
MOZ_MUST_USE bool emitElemOperands(ParseNode* pn, EmitElemOption opts);
--- a/js/src/frontend/Parser.cpp
+++ b/js/src/frontend/Parser.cpp
@@ -2269,16 +2269,17 @@ Parser<FullParseHandler>::standaloneFunc
bool duplicatedParam = false;
for (uint32_t i = 0; i < formals.length(); i++) {
if (!notePositionalFormalParameter(fn, formals[i], false, &duplicatedParam))
return null();
}
funbox->hasDuplicateParameters = duplicatedParam;
YieldHandling yieldHandling = GetYieldHandling(generatorKind, asyncKind);
+ AutoAwaitIsKeyword awaitIsKeyword(&tokenStream, asyncKind == AsyncFunction);
ParseNode* pn = functionBody(InAllowed, yieldHandling, Statement, StatementListBody);
if (!pn)
return null();
TokenKind tt;
if (!tokenStream.getToken(&tt, TokenStream::Operand))
return null();
if (tt != TOK_EOF) {
@@ -2535,16 +2536,20 @@ Parser<ParseHandler>::newFunction(Handle
allocKind = gc::AllocKind::FUNCTION_EXTENDED;
}
#endif
flags = (generatorKind == NotGenerator
? JSFunction::INTERPRETED_NORMAL
: JSFunction::INTERPRETED_GENERATOR);
}
+ // We store the async wrapper in a slot for later access.
+ if (asyncKind == AsyncFunction)
+ allocKind = gc::AllocKind::FUNCTION_EXTENDED;
+
fun = NewFunctionWithProto(context, nullptr, 0, flags, nullptr, atom, proto,
allocKind, TenuredObject);
if (!fun)
return nullptr;
if (options().selfHostingMode) {
fun->setIsSelfHostedBuiltin();
#ifdef DEBUG
if (isGlobalSelfHostedBuiltin)
--- a/js/src/jit/CodeGenerator.cpp
+++ b/js/src/jit/CodeGenerator.cpp
@@ -2429,17 +2429,18 @@ CodeGenerator::visitLambda(LLambda* lir)
MOZ_ASSERT(!info.singletonType);
masm.createGCObject(output, tempReg, info.fun, gc::DefaultHeap, ool->entry());
emitLambdaInit(output, envChain, info);
if (info.flags & JSFunction::EXTENDED) {
- MOZ_ASSERT(info.fun->allowSuperProperty() || info.fun->isSelfHostedBuiltin());
+ MOZ_ASSERT(info.fun->allowSuperProperty() || info.fun->isSelfHostedBuiltin() ||
+ info.fun->isAsync());
static_assert(FunctionExtended::NUM_EXTENDED_SLOTS == 2, "All slots must be initialized");
masm.storeValue(UndefinedValue(), Address(output, FunctionExtended::offsetOfExtendedSlot(0)));
masm.storeValue(UndefinedValue(), Address(output, FunctionExtended::offsetOfExtendedSlot(1)));
}
masm.bind(ool->rejoin());
}
--- a/js/src/jsfun.cpp
+++ b/js/src/jsfun.cpp
@@ -37,16 +37,17 @@
#include "jit/InlinableNatives.h"
#include "jit/Ion.h"
#include "jit/JitFrameIterator.h"
#include "js/CallNonGenericMethod.h"
#include "js/Proxy.h"
#include "vm/Debugger.h"
#include "vm/GlobalObject.h"
#include "vm/Interpreter.h"
+#include "vm/SelfHosting.h"
#include "vm/Shape.h"
#include "vm/SharedImmutableStringsCache.h"
#include "vm/StringBuffer.h"
#include "vm/WrapperObject.h"
#include "vm/Xdr.h"
#include "jsscriptinlines.h"
@@ -1653,40 +1654,46 @@ const JSFunctionSpec js::function_method
JS_FN(js_call_str, fun_call, 1,0),
JS_FN("isGenerator", fun_isGenerator,0,0),
JS_SELF_HOSTED_FN("bind", "FunctionBind", 2, JSFUN_HAS_REST),
JS_SYM_FN(hasInstance, fun_symbolHasInstance, 1, JSPROP_READONLY | JSPROP_PERMANENT),
JS_FS_END
};
static bool
-FunctionConstructor(JSContext* cx, unsigned argc, Value* vp, GeneratorKind generatorKind)
+FunctionConstructor(JSContext* cx, unsigned argc, Value* vp, GeneratorKind generatorKind,
+ FunctionAsyncKind asyncKind)
{
CallArgs args = CallArgsFromVp(argc, vp);
/* Block this call if security callbacks forbid it. */
Rooted<GlobalObject*> global(cx, &args.callee().global());
if (!GlobalObject::isRuntimeCodeGenEnabled(cx, global)) {
JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr, JSMSG_CSP_BLOCKED_FUNCTION);
return false;
}
bool isStarGenerator = generatorKind == StarGenerator;
+ bool isAsync = asyncKind == AsyncFunction;
MOZ_ASSERT(generatorKind != LegacyGenerator);
+ MOZ_ASSERT_IF(isAsync, isStarGenerator);
+ MOZ_ASSERT_IF(!isStarGenerator, !isAsync);
RootedScript maybeScript(cx);
const char* filename;
unsigned lineno;
bool mutedErrors;
uint32_t pcOffset;
DescribeScriptedCallerForCompilation(cx, &maybeScript, &filename, &lineno, &pcOffset,
&mutedErrors);
const char* introductionType = "Function";
- if (generatorKind != NotGenerator)
+ if (isAsync)
+ introductionType = "AsyncFunction";
+ else if (generatorKind != NotGenerator)
introductionType = "GeneratorFunction";
const char* introducerFilename = filename;
if (maybeScript && maybeScript->scriptSource()->introducerFilename())
introducerFilename = maybeScript->scriptSource()->introducerFilename();
CompileOptions options(cx);
options.setMutedErrors(mutedErrors)
@@ -1770,29 +1777,32 @@ FunctionConstructor(JSContext* cx, unsig
* NB: (new Function) is not lexically closed by its caller, it's just an
* anonymous function in the top-level scope that its constructor inhabits.
* Thus 'var x = 42; f = new Function("return x"); print(f())' prints 42,
* 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) {
+ // Unwrapped function of async function should use GeneratorFunction,
+ // while wrapped function isn't generator.
proto = GlobalObject::getOrCreateStarGeneratorFunctionPrototype(cx, global);
if (!proto)
return false;
} else {
if (!GetPrototypeFromCallableConstructor(cx, args, &proto))
return false;
}
RootedObject globalLexical(cx, &global->lexicalEnvironment());
+ AllocKind allocKind = isAsync ? AllocKind::FUNCTION_EXTENDED : AllocKind::FUNCTION;
RootedFunction fun(cx, NewFunctionWithProto(cx, nullptr, 0,
JSFunction::INTERPRETED_LAMBDA, globalLexical,
anonymousAtom, proto,
- AllocKind::FUNCTION, TenuredObject));
+ allocKind, TenuredObject));
if (!fun)
return false;
if (!JSFunction::setTypeForScriptedFunction(cx, fun))
return false;
AutoStableStringChars stableChars(cx);
if (!stableChars.initTwoByte(cx, bodyText))
@@ -1870,34 +1880,49 @@ FunctionConstructor(JSContext* cx, unsig
fun->setHasRest();
mozilla::Range<const char16_t> chars = stableChars.twoByteRange();
SourceBufferHolder::Ownership ownership = stableChars.maybeGiveOwnershipToCaller()
? SourceBufferHolder::GiveOwnership
: SourceBufferHolder::NoOwnership;
bool ok;
SourceBufferHolder srcBuf(chars.start().get(), chars.length(), ownership);
- if (isStarGenerator)
+ if (isAsync)
+ ok = frontend::CompileAsyncFunctionBody(cx, &fun, options, formals, srcBuf);
+ else if (isStarGenerator)
ok = frontend::CompileStarGeneratorBody(cx, &fun, options, formals, srcBuf);
else
ok = frontend::CompileFunctionBody(cx, &fun, options, formals, srcBuf);
args.rval().setObject(*fun);
return ok;
}
bool
js::Function(JSContext* cx, unsigned argc, Value* vp)
{
- return FunctionConstructor(cx, argc, vp, NotGenerator);
+ return FunctionConstructor(cx, argc, vp, NotGenerator, SyncFunction);
}
bool
js::Generator(JSContext* cx, unsigned argc, Value* vp)
{
- return FunctionConstructor(cx, argc, vp, StarGenerator);
+ return FunctionConstructor(cx, argc, vp, StarGenerator, SyncFunction);
+}
+
+bool
+js::AsyncFunctionConstructor(JSContext* cx, unsigned argc, Value* vp)
+{
+ CallArgs args = CallArgsFromVp(argc, vp);
+ if (!FunctionConstructor(cx, argc, vp, StarGenerator, AsyncFunction))
+ return false;
+
+ FixedInvokeArgs<1> args2(cx);
+ args2[0].set(args.rval());
+ return CallSelfHostedFunction(cx, cx->names().AsyncFunction_wrap,
+ NullHandleValue, args2, args.rval());
}
bool
JSFunction::isBuiltinFunctionConstructor()
{
return maybeNative() == Function || maybeNative() == Generator;
}
--- a/js/src/jsfun.h
+++ b/js/src/jsfun.h
@@ -615,16 +615,19 @@ fun_toStringHelper(JSContext* cx, js::Ha
namespace js {
extern bool
Function(JSContext* cx, unsigned argc, Value* vp);
extern bool
Generator(JSContext* cx, unsigned argc, Value* vp);
+extern bool
+AsyncFunctionConstructor(JSContext* cx, unsigned argc, Value* vp);
+
// Allocate a new function backed by a JSNative. Note that by default this
// creates a singleton object.
extern JSFunction*
NewNativeFunction(ExclusiveContext* cx, JSNative native, unsigned nargs, HandleAtom atom,
gc::AllocKind allocKind = gc::AllocKind::FUNCTION,
NewObjectKind newKind = SingletonObject);
// Allocate a new constructor backed by a JSNative. Note that by default this
--- a/js/src/jsscript.cpp
+++ b/js/src/jsscript.cpp
@@ -3100,16 +3100,18 @@ Rebase(JSScript* dst, JSScript* src, T*
{
size_t off = reinterpret_cast<uint8_t*>(srcp) - src->data;
return reinterpret_cast<T*>(dst->data + off);
}
static JSObject*
CloneInnerInterpretedFunction(JSContext* cx, HandleScope enclosingScope, HandleFunction srcFun)
{
+ /* async function should not appear as inner function. */
+ MOZ_ASSERT(!srcFun->isAsync());
/* NB: Keep this in sync with XDRInterpretedFunction. */
RootedObject cloneProto(cx);
if (srcFun->isStarGenerator()) {
cloneProto = GlobalObject::getOrCreateStarGeneratorFunctionPrototype(cx, cx->global());
if (!cloneProto)
return nullptr;
}
--- a/js/src/moz.build
+++ b/js/src/moz.build
@@ -319,16 +319,17 @@ UNIFIED_SOURCES += [
'proxy/OpaqueCrossCompartmentWrapper.cpp',
'proxy/Proxy.cpp',
'proxy/ScriptedProxyHandler.cpp',
'proxy/SecurityWrapper.cpp',
'proxy/Wrapper.cpp',
'threading/Mutex.cpp',
'vm/ArgumentsObject.cpp',
'vm/ArrayBufferObject.cpp',
+ 'vm/AsyncFunction.cpp',
'vm/Caches.cpp',
'vm/CallNonGenericMethod.cpp',
'vm/CharacterEncoding.cpp',
'vm/CodeCoverage.cpp',
'vm/Compression.cpp',
'vm/DateTime.cpp',
'vm/Debugger.cpp',
'vm/DebuggerMemory.cpp',
@@ -744,16 +745,17 @@ GENERATED_FILES += [('selfhosted.out.h',
selfhosted = GENERATED_FILES[('selfhosted.out.h', 'selfhosted.js')]
selfhosted.script = 'builtin/embedjs.py:generate_selfhosted'
selfhosted.inputs = [
'js.msg',
'builtin/TypedObjectConstants.h',
'builtin/SelfHostingDefines.h',
'builtin/Utilities.js',
'builtin/Array.js',
+ 'builtin/AsyncFunctions.js',
'builtin/Classes.js',
'builtin/Date.js',
'builtin/Error.js',
'builtin/Function.js',
'builtin/Generator.js',
'builtin/Intl.js',
'builtin/IntlData.js',
'builtin/Iterator.js',
new file mode 100644
--- /dev/null
+++ b/js/src/vm/AsyncFunction.cpp
@@ -0,0 +1,115 @@
+/* -*- 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 "vm/AsyncFunction.h"
+
+#include "jscompartment.h"
+
+#include "builtin/SelfHostingDefines.h"
+#include "vm/GlobalObject.h"
+#include "vm/SelfHosting.h"
+
+using namespace js;
+using namespace js::gc;
+
+/* static */ bool
+GlobalObject::initAsyncFunction(JSContext* cx, Handle<GlobalObject*> global)
+{
+ if (global->getReservedSlot(ASYNC_FUNCTION_PROTO).isObject())
+ return true;
+
+ RootedObject asyncFunctionProto(cx, NewSingletonObjectWithFunctionPrototype(cx, global));
+ if (!asyncFunctionProto)
+ return false;
+
+ RootedValue function(cx, global->getConstructor(JSProto_Function));
+ if (!function.toObjectOrNull())
+ 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));
+ if (!asyncFunction)
+ return false;
+ if (!LinkConstructorAndPrototype(cx, asyncFunction, asyncFunctionProto))
+ return false;
+
+ global->setReservedSlot(ASYNC_FUNCTION, ObjectValue(*asyncFunction));
+ global->setReservedSlot(ASYNC_FUNCTION_PROTO, ObjectValue(*asyncFunctionProto));
+ return true;
+}
+
+JSFunction*
+js::GetWrappedAsyncFunction(JSFunction* unwrapped)
+{
+ MOZ_ASSERT(unwrapped->isAsync());
+ return &unwrapped->getExtendedSlot(ASYNC_WRAPPED_SLOT).toObject().as<JSFunction>();
+}
+
+JSFunction*
+js::GetUnwrappedAsyncFunction(JSFunction* wrapper)
+{
+ JSFunction* unwrapped = &wrapper->getExtendedSlot(ASYNC_UNWRAPPED_SLOT).toObject().as<JSFunction>();
+ MOZ_ASSERT(unwrapped->isAsync());
+ return unwrapped;
+}
+
+bool
+js::IsWrappedAsyncFunction(JSContext* cx, JSFunction* wrapper)
+{
+ return IsSelfHostedFunctionWithName(wrapper, cx->names().AsyncWrapped);
+}
+
+bool
+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.
+ RootedObject proto(cx, GlobalObject::getOrCreateAsyncFunctionPrototype(cx, cx->global()));
+ RootedObject scope(cx, wrapper->environment());
+ RootedAtom atom(cx, unwrapped->name());
+ RootedFunction wrapped(cx, NewFunctionWithProto(cx, nullptr, 0,
+ JSFunction::INTERPRETED_LAMBDA,
+ scope, atom, proto,
+ AllocKind::FUNCTION_EXTENDED, TenuredObject));
+ if (!wrapped)
+ return false;
+
+ wrapped->initScript(wrapper->nonLazyScript());
+
+ // 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 of `wrapper` is self-hosted, so `wrapped` should also be
+ // set as self-hosted function.
+ wrapped->setIsSelfHostedBuiltin();
+
+ // Set LAZY_FUNCTION_NAME_SLOT to "AsyncWrapped" to make it detectable in
+ // IsWrappedAsyncFunction.
+ wrapped->setExtendedSlot(LAZY_FUNCTION_NAME_SLOT, StringValue(cx->names().AsyncWrapped));
+
+ // The length of the script of `wrapper` is different than the length of
+ // `unwrapped`. We should set actual length as resolved length, to avoid
+ // using the length of the script.
+ uint16_t length;
+ if (!unwrapped->getLength(cx, &length))
+ return false;
+
+ RootedValue lengthValue(cx, NumberValue(length));
+ if (!DefineProperty(cx, wrapped, cx->names().length, lengthValue,
+ nullptr, nullptr, JSPROP_READONLY))
+ {
+ return false;
+ }
+
+ result.set(wrapped);
+ return true;
+}
new file mode 100644
--- /dev/null
+++ b/js/src/vm/AsyncFunction.h
@@ -0,0 +1,30 @@
+/* -*- 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 vm_AsyncFunction_h
+#define vm_AsyncFunction_h
+
+#include "jscntxt.h"
+#include "jsobj.h"
+
+namespace js {
+
+JSFunction*
+GetWrappedAsyncFunction(JSFunction* unwrapped);
+
+JSFunction*
+GetUnwrappedAsyncFunction(JSFunction* wrapper);
+
+bool
+IsWrappedAsyncFunction(JSContext* cx, JSFunction* wrapper);
+
+bool
+CreateAsyncFunction(JSContext* cx, HandleFunction wrapper, HandleFunction unwrapped,
+ MutableHandleFunction result);
+
+} // namespace js
+
+#endif /* vm_AsyncFunction_h */
--- a/js/src/vm/CommonPropertyNames.h
+++ b/js/src/vm/CommonPropertyNames.h
@@ -24,16 +24,19 @@
macro(ArraySpecies, ArraySpecies, "ArraySpecies") \
macro(ArraySpeciesCreate, ArraySpeciesCreate, "ArraySpeciesCreate") \
macro(ArrayToLocaleString, ArrayToLocaleString, "ArrayToLocaleString") \
macro(ArrayType, ArrayType, "ArrayType") \
macro(ArrayValues, ArrayValues, "ArrayValues") \
macro(ArrayValuesAt, ArrayValuesAt, "ArrayValuesAt") \
macro(as, as, "as") \
macro(Async, Async, "Async") \
+ macro(AsyncFunction, AsyncFunction, "AsyncFunction") \
+ macro(AsyncFunction_wrap, AsyncFunction_wrap, "AsyncFunction_wrap") \
+ macro(AsyncWrapped, AsyncWrapped, "AsyncWrapped") \
macro(async, async, "async") \
macro(await, await, "await") \
macro(Bool8x16, Bool8x16, "Bool8x16") \
macro(Bool16x8, Bool16x8, "Bool16x8") \
macro(Bool32x4, Bool32x4, "Bool32x4") \
macro(Bool64x2, Bool64x2, "Bool64x2") \
macro(boundWithSpace, boundWithSpace, "bound ") \
macro(breakdown, breakdown, "breakdown") \
--- a/js/src/vm/EnvironmentObject.cpp
+++ b/js/src/vm/EnvironmentObject.cpp
@@ -12,16 +12,17 @@
#include "jscompartment.h"
#include "jsiter.h"
#include "builtin/ModuleObject.h"
#include "frontend/ParseNode.h"
#include "gc/Policy.h"
#include "vm/ArgumentsObject.h"
+#include "vm/AsyncFunction.h"
#include "vm/GlobalObject.h"
#include "vm/ProxyObject.h"
#include "vm/Shape.h"
#include "vm/Xdr.h"
#include "jsatominlines.h"
#include "jsobjinlines.h"
#include "jsscriptinlines.h"
@@ -1018,17 +1019,19 @@ const Class LexicalEnvironmentObject::cl
JSCLASS_IS_ANONYMOUS,
JS_NULL_CLASS_OPS,
JS_NULL_CLASS_SPEC,
JS_NULL_CLASS_EXT,
JS_NULL_OBJECT_OPS
};
/* static */ NamedLambdaObject*
-NamedLambdaObject::create(JSContext* cx, HandleFunction callee, HandleObject enclosing,
+NamedLambdaObject::create(JSContext* cx, HandleFunction callee,
+ HandleFunction func,
+ HandleObject enclosing,
gc::InitialHeap heap)
{
MOZ_ASSERT(callee->isNamedLambda());
RootedScope scope(cx, callee->nonLazyScript()->maybeNamedLambdaScope());
MOZ_ASSERT(scope && scope->environmentShape());
MOZ_ASSERT(scope->environmentShape()->slot() == lambdaSlot());
MOZ_ASSERT(!scope->environmentShape()->writable());
@@ -1040,32 +1043,40 @@ NamedLambdaObject::create(JSContext* cx,
#endif
LexicalEnvironmentObject* obj =
LexicalEnvironmentObject::createTemplateObject(cx, scope.as<LexicalScope>(),
enclosing, heap);
if (!obj)
return nullptr;
- obj->initFixedSlot(lambdaSlot(), ObjectValue(*callee));
+ obj->initFixedSlot(lambdaSlot(), ObjectValue(*func));
return static_cast<NamedLambdaObject*>(obj);
}
/* static */ NamedLambdaObject*
NamedLambdaObject::createTemplateObject(JSContext* cx, HandleFunction callee, gc::InitialHeap heap)
{
- return create(cx, callee, nullptr, heap);
+ return create(cx, callee, callee, nullptr, heap);
}
/* static */ NamedLambdaObject*
NamedLambdaObject::create(JSContext* cx, AbstractFramePtr frame)
{
RootedFunction fun(cx, frame.callee());
RootedObject enclosing(cx, frame.environmentChain());
- return create(cx, fun, enclosing, gc::DefaultHeap);
+ return create(cx, fun, fun, enclosing, gc::DefaultHeap);
+}
+
+/* static */ NamedLambdaObject*
+NamedLambdaObject::create(JSContext* cx, AbstractFramePtr frame, HandleFunction replacement)
+{
+ RootedFunction fun(cx, frame.callee());
+ RootedObject enclosing(cx, frame.environmentChain());
+ return create(cx, fun, replacement, enclosing, gc::DefaultHeap);
}
/* static */ size_t
NamedLambdaObject::lambdaSlot()
{
// Named lambda environments have exactly one name.
return JSSLOT_FREE(&LexicalEnvironmentObject::class_);
}
@@ -3360,17 +3371,25 @@ js::InitFunctionEnvironmentObjects(JSCon
{
MOZ_ASSERT(frame.isFunctionFrame());
MOZ_ASSERT(frame.callee()->needsSomeEnvironmentObject());
RootedFunction callee(cx, frame.callee());
// Named lambdas may have an environment that holds itself for recursion.
if (callee->needsNamedLambdaEnvironment()) {
- NamedLambdaObject* declEnv = NamedLambdaObject::create(cx, frame);
+ NamedLambdaObject* declEnv;
+ if (callee->isAsync()) {
+ // Named async function needs special environment to return
+ // wrapped function for the binding.
+ RootedFunction fun(cx, GetWrappedAsyncFunction(callee));
+ declEnv = NamedLambdaObject::create(cx, frame, fun);
+ } else {
+ declEnv = NamedLambdaObject::create(cx, frame);
+ }
if (!declEnv)
return false;
frame.pushOnEnvironmentChain(*declEnv);
}
// If the function has parameter default expressions, there may be an
// extra environment to hold the parameters.
if (callee->needsCallObject()) {
--- a/js/src/vm/EnvironmentObject.h
+++ b/js/src/vm/EnvironmentObject.h
@@ -510,23 +510,26 @@ class LexicalEnvironmentObject : public
// For extensible lexical environments, the 'this' value for its
// scope. Otherwise asserts.
Value thisValue() const;
};
class NamedLambdaObject : public LexicalEnvironmentObject
{
static NamedLambdaObject* create(JSContext* cx, HandleFunction callee,
+ HandleFunction replacement,
HandleObject enclosing, gc::InitialHeap heap);
public:
static NamedLambdaObject* createTemplateObject(JSContext* cx, HandleFunction callee,
gc::InitialHeap heap);
static NamedLambdaObject* create(JSContext* cx, AbstractFramePtr frame);
+ static NamedLambdaObject* create(JSContext* cx, AbstractFramePtr frame,
+ HandleFunction replacement);
// For JITs.
static size_t lambdaSlot();
};
// A non-syntactic dynamic scope object that captures non-lexical
// bindings. That is, a scope object that captures both qualified var
// assignments and unqualified bareword assignments. Its parent is always the
--- a/js/src/vm/GeneratorObject.cpp
+++ b/js/src/vm/GeneratorObject.cpp
@@ -255,18 +255,18 @@ static JSObject*
NewSingletonObjectWithObjectPrototype(JSContext* cx, Handle<GlobalObject*> global)
{
RootedObject proto(cx, global->getOrCreateObjectPrototype(cx));
if (!proto)
return nullptr;
return NewObjectWithGivenProto<PlainObject>(cx, proto, SingletonObject);
}
-static JSObject*
-NewSingletonObjectWithFunctionPrototype(JSContext* cx, Handle<GlobalObject*> global)
+JSObject*
+js::NewSingletonObjectWithFunctionPrototype(JSContext* cx, Handle<GlobalObject*> global)
{
RootedObject proto(cx, global->getOrCreateFunctionPrototype(cx));
if (!proto)
return nullptr;
return NewObjectWithGivenProto<PlainObject>(cx, proto, SingletonObject);
}
/* static */ bool
--- a/js/src/vm/GlobalObject.h
+++ b/js/src/vm/GlobalObject.h
@@ -95,16 +95,18 @@ class GlobalObject : public NativeObject
EMPTY_GLOBAL_SCOPE,
ITERATOR_PROTO,
ARRAY_ITERATOR_PROTO,
STRING_ITERATOR_PROTO,
LEGACY_GENERATOR_OBJECT_PROTO,
STAR_GENERATOR_OBJECT_PROTO,
STAR_GENERATOR_FUNCTION_PROTO,
STAR_GENERATOR_FUNCTION,
+ ASYNC_FUNCTION_PROTO,
+ ASYNC_FUNCTION,
MAP_ITERATOR_PROTO,
SET_ITERATOR_PROTO,
COLLATOR_PROTO,
NUMBER_FORMAT_PROTO,
DATE_TIME_FORMAT_PROTO,
MODULE_PROTO,
IMPORT_ENTRY_PROTO,
EXPORT_ENTRY_PROTO,
@@ -574,16 +576,29 @@ class GlobalObject : public NativeObject
}
static JSObject* getOrCreateStarGeneratorFunction(JSContext* cx,
Handle<GlobalObject*> global)
{
return global->getOrCreateObject(cx, STAR_GENERATOR_FUNCTION, initStarGenerators);
}
+ static NativeObject* getOrCreateAsyncFunctionPrototype(JSContext* cx,
+ Handle<GlobalObject*> global)
+ {
+ return MaybeNativeObject(global->getOrCreateObject(cx, ASYNC_FUNCTION_PROTO,
+ initAsyncFunction));
+ }
+
+ static JSObject* getOrCreateAsyncFunction(JSContext* cx,
+ Handle<GlobalObject*> global)
+ {
+ return global->getOrCreateObject(cx, ASYNC_FUNCTION, initAsyncFunction);
+ }
+
static JSObject* getOrCreateMapIteratorPrototype(JSContext* cx,
Handle<GlobalObject*> global)
{
return global->getOrCreateObject(cx, MAP_ITERATOR_PROTO, initMapIteratorProto);
}
static JSObject* getOrCreateSetIteratorPrototype(JSContext* cx,
Handle<GlobalObject*> global)
@@ -723,16 +738,18 @@ class GlobalObject : public NativeObject
static bool initIteratorProto(JSContext* cx, Handle<GlobalObject*> global);
static bool initArrayIteratorProto(JSContext* cx, Handle<GlobalObject*> global);
static bool initStringIteratorProto(JSContext* cx, Handle<GlobalObject*> global);
// Implemented in vm/GeneratorObject.cpp.
static bool initLegacyGeneratorProto(JSContext* cx, Handle<GlobalObject*> global);
static bool initStarGenerators(JSContext* cx, Handle<GlobalObject*> global);
+ static bool initAsyncFunction(JSContext* cx, Handle<GlobalObject*> global);
+
// Implemented in builtin/MapObject.cpp.
static bool initMapIteratorProto(JSContext* cx, Handle<GlobalObject*> global);
static bool initSetIteratorProto(JSContext* cx, Handle<GlobalObject*> global);
// Implemented in Intl.cpp.
static bool initIntlObject(JSContext* cx, Handle<GlobalObject*> global);
// Implemented in builtin/ModuleObject.cpp
@@ -983,16 +1000,19 @@ inline JSProtoKey
StandardProtoKeyOrNull(const JSObject* obj)
{
JSProtoKey key = JSCLASS_CACHED_PROTO_KEY(obj->getClass());
if (key == JSProto_Error)
return GetExceptionProtoKey(obj->as<ErrorObject>().type());
return key;
}
+JSObject*
+NewSingletonObjectWithFunctionPrototype(JSContext* cx, Handle<GlobalObject*> global);
+
} // namespace js
template<>
inline bool
JSObject::is<js::GlobalObject>() const
{
return !!(getClass()->flags & JSCLASS_IS_GLOBAL);
}
--- a/js/src/vm/SelfHosting.cpp
+++ b/js/src/vm/SelfHosting.cpp
@@ -34,16 +34,17 @@
#include "builtin/TypedObject.h"
#include "builtin/WeakSetObject.h"
#include "gc/Marking.h"
#include "gc/Policy.h"
#include "jit/AtomicOperations.h"
#include "jit/InlinableNatives.h"
#include "js/CharacterEncoding.h"
#include "js/Date.h"
+#include "vm/AsyncFunction.h"
#include "vm/Compression.h"
#include "vm/GeneratorObject.h"
#include "vm/Interpreter.h"
#include "vm/RegExpObject.h"
#include "vm/String.h"
#include "vm/StringBuffer.h"
#include "vm/TypedArrayCommon.h"
#include "vm/WrapperObject.h"
@@ -1928,16 +1929,33 @@ intrinsic_HostPromiseRejectionTracker(JS
Rooted<PromiseObject*> promise(cx, &args[0].toObject().as<PromiseObject>());
mozilla::DebugOnly<bool> isHandled = args[1].toBoolean();
MOZ_ASSERT(isHandled, "HostPromiseRejectionTracker intrinsic currently only marks as handled");
cx->runtime()->removeUnhandledRejectedPromise(cx, promise);
args.rval().setUndefined();
return true;
}
+bool
+intrinsic_CreateAsyncFunction(JSContext* cx, unsigned argc, Value* vp)
+{
+ CallArgs args = CallArgsFromVp(argc, vp);
+ MOZ_ASSERT(args.length() == 2);
+
+ RootedFunction wrapper(cx, &args[0].toObject().as<JSFunction>());
+ RootedFunction unwrapped(cx, &args[1].toObject().as<JSFunction>());
+
+ RootedFunction wrapped(cx);
+ if (!CreateAsyncFunction(cx, wrapper, unwrapped, &wrapped))
+ return false;
+
+ args.rval().setObject(*wrapped);
+ return true;
+}
+
/**
* Returns the default locale as a well-formed, but not necessarily canonicalized,
* BCP-47 language tag.
*/
static bool
intrinsic_RuntimeDefaultLocale(JSContext* cx, unsigned argc, Value* vp)
{
CallArgs args = CallArgsFromVp(argc, vp);
@@ -2393,16 +2411,18 @@ static const JSFunctionSpec intrinsic_fu
JS_FN("_ConstructorForTypedArray", intrinsic_ConstructorForTypedArray, 1,0),
JS_FN("_NameForTypedArray", intrinsic_NameForTypedArray, 1,0),
JS_FN("DecompileArg", intrinsic_DecompileArg, 2,0),
JS_FN("_FinishBoundFunctionInit", intrinsic_FinishBoundFunctionInit, 3,0),
JS_FN("RuntimeDefaultLocale", intrinsic_RuntimeDefaultLocale, 0,0),
JS_FN("LocalTZA", intrinsic_LocalTZA, 0,0),
JS_FN("AddContentTelemetry", intrinsic_AddContentTelemetry, 2,0),
+ JS_FN("CreateAsyncFunction", intrinsic_CreateAsyncFunction, 1,0),
+
JS_INLINABLE_FN("_IsConstructing", intrinsic_IsConstructing, 0,0,
IntrinsicIsConstructing),
JS_INLINABLE_FN("SubstringKernel", intrinsic_SubstringKernel, 3,0,
IntrinsicSubstringKernel),
JS_INLINABLE_FN("_DefineDataProperty", intrinsic_DefineDataProperty, 4,0,
IntrinsicDefineDataProperty),
JS_INLINABLE_FN("ObjectHasPrototype", intrinsic_ObjectHasPrototype, 2,0,
IntrinsicObjectHasPrototype),
@@ -2535,16 +2555,19 @@ static const JSFunctionSpec intrinsic_fu
JS_FN("_GetObjectFromIncumbentGlobal", intrinsic_GetObjectFromIncumbentGlobal, 0, 0),
JS_FN("IsPromise", intrinsic_IsInstanceOfBuiltin<PromiseObject>, 1,0),
JS_FN("IsWrappedPromise", intrinsic_IsWrappedPromiseObject, 1, 0),
JS_FN("_EnqueuePromiseReactionJob", intrinsic_EnqueuePromiseReactionJob, 2, 0),
JS_FN("HostPromiseRejectionTracker", intrinsic_HostPromiseRejectionTracker,2, 0),
JS_FN("CallPromiseMethodIfWrapped",
CallNonGenericSelfhostedMethod<Is<PromiseObject>>, 2,0),
+ JS_FN("Promise_static_resolve", Promise_resolve, 1, 0),
+ JS_FN("Promise_static_reject", Promise_reject, 1, 0),
+
// See builtin/TypedObject.h for descriptors of the typedobj functions.
JS_FN("NewOpaqueTypedObject", js::NewOpaqueTypedObject, 1, 0),
JS_FN("NewDerivedTypedObject", js::NewDerivedTypedObject, 3, 0),
JS_FN("TypedObjectBuffer", TypedObject::GetBuffer, 1, 0),
JS_FN("TypedObjectByteOffset", TypedObject::GetByteOffset, 1, 0),
JS_FN("AttachTypedObject", js::AttachTypedObject, 3, 0),
JS_FN("TypedObjectIsAttached", js::TypedObjectIsAttached, 1, 0),
JS_FN("TypedObjectTypeDescr", js::TypedObjectTypeDescr, 1, 0),