summaryrefslogtreecommitdiffstats
path: root/js/src/vm
diff options
context:
space:
mode:
Diffstat (limited to 'js/src/vm')
-rw-r--r--js/src/vm/AsyncFunction.cpp31
-rw-r--r--js/src/vm/AsyncFunction.h3
-rw-r--r--js/src/vm/AsyncIteration.cpp644
-rw-r--r--js/src/vm/AsyncIteration.h256
-rw-r--r--js/src/vm/CommonPropertyNames.h6
-rw-r--r--js/src/vm/Debugger.cpp27
-rw-r--r--js/src/vm/Debugger.h14
-rw-r--r--js/src/vm/EnvironmentObject.cpp26
-rw-r--r--js/src/vm/GeneratorObject.cpp56
-rw-r--r--js/src/vm/GeneratorObject.h60
-rw-r--r--js/src/vm/GlobalObject.cpp92
-rw-r--r--js/src/vm/GlobalObject.h55
-rw-r--r--js/src/vm/Interpreter.cpp32
-rw-r--r--js/src/vm/Interpreter.h3
-rw-r--r--js/src/vm/NativeObject-inl.h8
-rw-r--r--js/src/vm/NativeObject.cpp14
-rw-r--r--js/src/vm/ObjectGroup.cpp2
-rw-r--r--js/src/vm/Opcodes.h34
-rw-r--r--js/src/vm/Probes-inl.h5
-rw-r--r--js/src/vm/RegExpObject.cpp5
-rw-r--r--js/src/vm/RegExpObject.h8
-rw-r--r--js/src/vm/Runtime.cpp1
-rw-r--r--js/src/vm/SelfHosting.cpp167
-rw-r--r--js/src/vm/Shape.h2
-rw-r--r--js/src/vm/Stack-inl.h2
-rw-r--r--js/src/vm/Stack.cpp4
-rw-r--r--js/src/vm/Stack.h3
-rw-r--r--js/src/vm/Time.cpp12
-rw-r--r--js/src/vm/TypeInference.cpp92
-rw-r--r--js/src/vm/TypeInference.h59
30 files changed, 1474 insertions, 249 deletions
diff --git a/js/src/vm/AsyncFunction.cpp b/js/src/vm/AsyncFunction.cpp
index e14b77424..7132ed984 100644
--- a/js/src/vm/AsyncFunction.cpp
+++ b/js/src/vm/AsyncFunction.cpp
@@ -40,8 +40,11 @@ GlobalObject::initAsyncFunction(JSContext* cx, Handle<GlobalObject*> global)
proto));
if (!asyncFunction)
return false;
- if (!LinkConstructorAndPrototype(cx, asyncFunction, asyncFunctionProto))
+ if (!LinkConstructorAndPrototype(cx, asyncFunction, asyncFunctionProto,
+ JSPROP_PERMANENT | JSPROP_READONLY, JSPROP_READONLY))
+ {
return false;
+ }
global->setReservedSlot(ASYNC_FUNCTION, ObjectValue(*asyncFunction));
global->setReservedSlot(ASYNC_FUNCTION_PROTO, ObjectValue(*asyncFunctionProto));
@@ -109,7 +112,7 @@ WrappedAsyncFunction(JSContext* cx, unsigned argc, Value* vp)
JSObject*
js::WrapAsyncFunctionWithProto(JSContext* cx, HandleFunction unwrapped, HandleObject proto)
{
- MOZ_ASSERT(unwrapped->isStarGenerator());
+ MOZ_ASSERT(unwrapped->isAsync());
MOZ_ASSERT(proto, "We need an explicit prototype to avoid the default"
"%FunctionPrototype% fallback in NewFunctionWithProto().");
@@ -171,22 +174,14 @@ AsyncFunctionResume(JSContext* cx, Handle<PromiseObject*> resultPromise, HandleV
: cx->names().StarGeneratorThrow;
FixedInvokeArgs<1> args(cx);
args[0].set(valueOrReason);
- RootedValue result(cx);
- if (!CallSelfHostedFunction(cx, funName, generatorVal, args, &result))
- return AsyncFunctionThrown(cx, resultPromise);
-
- RootedObject resultObj(cx, &result.toObject());
- RootedValue doneVal(cx);
RootedValue value(cx);
- if (!GetProperty(cx, resultObj, resultObj, cx->names().done, &doneVal))
- return false;
- if (!GetProperty(cx, resultObj, resultObj, cx->names().value, &value))
- return false;
+ if (!CallSelfHostedFunction(cx, funName, generatorVal, args, &value))
+ return AsyncFunctionThrown(cx, resultPromise);
- if (doneVal.toBoolean())
- return AsyncFunctionReturned(cx, resultPromise, value);
+ if (generatorVal.toObject().as<GeneratorObject>().isAfterAwait())
+ return AsyncFunctionAwait(cx, resultPromise, value);
- return AsyncFunctionAwait(cx, resultPromise, value);
+ return AsyncFunctionReturned(cx, resultPromise, value);
}
// Async Functions proposal 2.2 steps 3-8.
@@ -242,9 +237,3 @@ js::IsWrappedAsyncFunction(JSFunction* fun)
{
return fun->maybeNative() == WrappedAsyncFunction;
}
-
-MOZ_MUST_USE bool
-js::CheckAsyncResumptionValue(JSContext* cx, HandleValue v)
-{
- return CheckStarGeneratorResumptionValue(cx, v);
-}
diff --git a/js/src/vm/AsyncFunction.h b/js/src/vm/AsyncFunction.h
index d7f2c1311..de7c87d13 100644
--- a/js/src/vm/AsyncFunction.h
+++ b/js/src/vm/AsyncFunction.h
@@ -35,9 +35,6 @@ MOZ_MUST_USE bool
AsyncFunctionAwaitedRejected(JSContext* cx, Handle<PromiseObject*> resultPromise,
HandleValue generatorVal, HandleValue reason);
-MOZ_MUST_USE bool
-CheckAsyncResumptionValue(JSContext* cx, HandleValue v);
-
} // namespace js
#endif /* vm_AsyncFunction_h */
diff --git a/js/src/vm/AsyncIteration.cpp b/js/src/vm/AsyncIteration.cpp
new file mode 100644
index 000000000..300179374
--- /dev/null
+++ b/js/src/vm/AsyncIteration.cpp
@@ -0,0 +1,644 @@
+/* -*- 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/AsyncIteration.h"
+
+#include "jsarray.h"
+#include "jscompartment.h"
+
+#include "builtin/Promise.h"
+#include "vm/GeneratorObject.h"
+#include "vm/GlobalObject.h"
+#include "vm/Interpreter.h"
+#include "vm/SelfHosting.h"
+
+#include "jscntxtinlines.h"
+#include "jsobjinlines.h"
+
+#include "vm/NativeObject-inl.h"
+
+using namespace js;
+using namespace js::gc;
+
+#define UNWRAPPED_ASYNC_WRAPPED_SLOT 1
+#define WRAPPED_ASYNC_UNWRAPPED_SLOT 0
+
+// Async Iteration proposal 8.3.10 Runtime Semantics: EvaluateBody.
+static bool
+WrappedAsyncGenerator(JSContext* cx, unsigned argc, Value* vp)
+{
+ CallArgs args = CallArgsFromVp(argc, vp);
+
+ RootedFunction wrapped(cx, &args.callee().as<JSFunction>());
+ RootedValue unwrappedVal(cx, wrapped->getExtendedSlot(WRAPPED_ASYNC_UNWRAPPED_SLOT));
+ RootedFunction unwrapped(cx, &unwrappedVal.toObject().as<JSFunction>());
+ RootedValue thisValue(cx, args.thisv());
+
+ // Step 1.
+ RootedValue generatorVal(cx);
+ InvokeArgs args2(cx);
+ if (!args2.init(cx, argc))
+ return false;
+ for (size_t i = 0, len = argc; i < len; i++)
+ args2[i].set(args[i]);
+ if (!Call(cx, unwrappedVal, thisValue, args2, &generatorVal))
+ return false;
+
+ // Step 2.
+ Rooted<AsyncGeneratorObject*> asyncGenObj(
+ cx, AsyncGeneratorObject::create(cx, wrapped, generatorVal));
+ if (!asyncGenObj)
+ return false;
+
+ // Step 3 (skipped).
+ // Done in AsyncGeneratorObject::create and generator.
+
+ // Step 4.
+ args.rval().setObject(*asyncGenObj);
+ return true;
+}
+
+JSObject*
+js::WrapAsyncGeneratorWithProto(JSContext* cx, HandleFunction unwrapped, HandleObject proto)
+{
+ MOZ_ASSERT(unwrapped->isAsync());
+ MOZ_ASSERT(proto, "We need an explicit prototype to avoid the default"
+ "%FunctionPrototype% fallback in NewFunctionWithProto().");
+
+ // Create a new function with AsyncGeneratorPrototype, reusing the name and
+ // the length of `unwrapped`.
+
+ RootedAtom funName(cx, unwrapped->explicitName());
+ uint16_t length;
+ if (!JSFunction::getLength(cx, unwrapped, &length))
+ return nullptr;
+
+ RootedFunction wrapped(cx, NewFunctionWithProto(cx, WrappedAsyncGenerator, length,
+ JSFunction::NATIVE_FUN, nullptr,
+ funName, proto,
+ AllocKind::FUNCTION_EXTENDED,
+ TenuredObject));
+ if (!wrapped)
+ return nullptr;
+
+ if (unwrapped->hasCompileTimeName())
+ wrapped->setCompileTimeName(unwrapped->compileTimeName());
+
+ // Link them to each other to make GetWrappedAsyncGenerator and
+ // GetUnwrappedAsyncGenerator work.
+ unwrapped->setExtendedSlot(UNWRAPPED_ASYNC_WRAPPED_SLOT, ObjectValue(*wrapped));
+ wrapped->setExtendedSlot(WRAPPED_ASYNC_UNWRAPPED_SLOT, ObjectValue(*unwrapped));
+
+ return wrapped;
+}
+
+JSObject*
+js::WrapAsyncGenerator(JSContext* cx, HandleFunction unwrapped)
+{
+ RootedObject proto(cx, GlobalObject::getOrCreateAsyncGenerator(cx, cx->global()));
+ if (!proto)
+ return nullptr;
+
+ return WrapAsyncGeneratorWithProto(cx, unwrapped, proto);
+}
+
+bool
+js::IsWrappedAsyncGenerator(JSFunction* fun)
+{
+ return fun->maybeNative() == WrappedAsyncGenerator;
+}
+
+JSFunction*
+js::GetWrappedAsyncGenerator(JSFunction* unwrapped)
+{
+ MOZ_ASSERT(unwrapped->isAsync());
+ return &unwrapped->getExtendedSlot(UNWRAPPED_ASYNC_WRAPPED_SLOT).toObject().as<JSFunction>();
+}
+
+JSFunction*
+js::GetUnwrappedAsyncGenerator(JSFunction* wrapped)
+{
+ MOZ_ASSERT(IsWrappedAsyncGenerator(wrapped));
+ JSFunction* unwrapped = &wrapped->getExtendedSlot(WRAPPED_ASYNC_UNWRAPPED_SLOT)
+ .toObject().as<JSFunction>();
+ MOZ_ASSERT(unwrapped->isAsync());
+ return unwrapped;
+}
+
+// Async Iteration proposal 4.1.1 Await Fulfilled Functions.
+MOZ_MUST_USE bool
+js::AsyncGeneratorAwaitedFulfilled(JSContext* cx, Handle<AsyncGeneratorObject*> asyncGenObj,
+ HandleValue value)
+{
+ return AsyncGeneratorResume(cx, asyncGenObj, CompletionKind::Normal, value);
+}
+
+// Async Iteration proposal 4.1.2 Await Rejected Functions.
+MOZ_MUST_USE bool
+js::AsyncGeneratorAwaitedRejected(JSContext* cx, Handle<AsyncGeneratorObject*> asyncGenObj,
+ HandleValue reason)
+{
+ return AsyncGeneratorResume(cx, asyncGenObj, CompletionKind::Throw, reason);
+}
+
+// Async Iteration proposal 11.4.3.7 step 8.d-e.
+MOZ_MUST_USE bool
+js::AsyncGeneratorYieldReturnAwaitedFulfilled(JSContext* cx,
+ Handle<AsyncGeneratorObject*> asyncGenObj,
+ HandleValue value)
+{
+ return AsyncGeneratorResume(cx, asyncGenObj, CompletionKind::Return, value);
+}
+
+// Async Iteration proposal 11.4.3.7 step 8.d-e.
+MOZ_MUST_USE bool
+js::AsyncGeneratorYieldReturnAwaitedRejected(JSContext* cx,
+ Handle<AsyncGeneratorObject*> asyncGenObj,
+ HandleValue reason)
+{
+ return AsyncGeneratorResume(cx, asyncGenObj, CompletionKind::Throw, reason);
+}
+
+const Class AsyncFromSyncIteratorObject::class_ = {
+ "AsyncFromSyncIteratorObject",
+ JSCLASS_HAS_RESERVED_SLOTS(AsyncFromSyncIteratorObject::Slots)
+};
+
+// Async Iteration proposal 11.1.3.1.
+JSObject*
+js::CreateAsyncFromSyncIterator(JSContext* cx, HandleObject iter)
+{
+ // Step 1 (implicit).
+ // Done in bytecode emitted by emitAsyncIterator.
+
+ // Steps 2-4.
+ return AsyncFromSyncIteratorObject::create(cx, iter);
+}
+
+// Async Iteration proposal 11.1.3.1 steps 2-4.
+/* static */ JSObject*
+AsyncFromSyncIteratorObject::create(JSContext* cx, HandleObject iter)
+{
+ // Step 2.
+ RootedObject proto(cx, GlobalObject::getOrCreateAsyncFromSyncIteratorPrototype(cx,
+ cx->global()));
+ if (!proto)
+ return nullptr;
+
+ RootedObject obj(cx, NewNativeObjectWithGivenProto(cx, &class_, proto));
+ if (!obj)
+ return nullptr;
+
+ Handle<AsyncFromSyncIteratorObject*> asyncIter = obj.as<AsyncFromSyncIteratorObject>();
+
+ // Step 3.
+ asyncIter->setIterator(iter);
+
+ // Step 4.
+ return asyncIter;
+}
+
+// Async Iteration proposal 11.1.3.2.1 %AsyncFromSyncIteratorPrototype%.next.
+static bool
+AsyncFromSyncIteratorNext(JSContext* cx, unsigned argc, Value* vp)
+{
+ CallArgs args = CallArgsFromVp(argc, vp);
+ return AsyncFromSyncIteratorMethod(cx, args, CompletionKind::Normal);
+}
+
+// Async Iteration proposal 11.1.3.2.2 %AsyncFromSyncIteratorPrototype%.return.
+static bool
+AsyncFromSyncIteratorReturn(JSContext* cx, unsigned argc, Value* vp)
+{
+ CallArgs args = CallArgsFromVp(argc, vp);
+ return AsyncFromSyncIteratorMethod(cx, args, CompletionKind::Return);
+}
+
+// Async Iteration proposal 11.1.3.2.3 %AsyncFromSyncIteratorPrototype%.throw.
+static bool
+AsyncFromSyncIteratorThrow(JSContext* cx, unsigned argc, Value* vp)
+{
+ CallArgs args = CallArgsFromVp(argc, vp);
+ return AsyncFromSyncIteratorMethod(cx, args, CompletionKind::Throw);
+}
+
+// Async Iteration proposal 11.4.1.2 AsyncGenerator.prototype.next.
+static bool
+AsyncGeneratorNext(JSContext* cx, unsigned argc, Value* vp)
+{
+ CallArgs args = CallArgsFromVp(argc, vp);
+
+ // Steps 1-3.
+ return AsyncGeneratorEnqueue(cx, args.thisv(), CompletionKind::Normal, args.get(0),
+ args.rval());
+}
+
+// Async Iteration proposal 11.4.1.3 AsyncGenerator.prototype.return.
+static bool
+AsyncGeneratorReturn(JSContext* cx, unsigned argc, Value* vp)
+{
+ CallArgs args = CallArgsFromVp(argc, vp);
+
+ // Steps 1-3.
+ return AsyncGeneratorEnqueue(cx, args.thisv(), CompletionKind::Return, args.get(0),
+ args.rval());
+}
+
+// Async Iteration proposal 11.4.1.4 AsyncGenerator.prototype.throw.
+static bool
+AsyncGeneratorThrow(JSContext* cx, unsigned argc, Value* vp)
+{
+ CallArgs args = CallArgsFromVp(argc, vp);
+
+ // Steps 1-3.
+ return AsyncGeneratorEnqueue(cx, args.thisv(), CompletionKind::Throw, args.get(0),
+ args.rval());
+}
+
+const Class AsyncGeneratorObject::class_ = {
+ "AsyncGenerator",
+ JSCLASS_HAS_RESERVED_SLOTS(AsyncGeneratorObject::Slots)
+};
+
+// ES 2017 draft 9.1.13.
+template <typename ProtoGetter>
+static JSObject*
+OrdinaryCreateFromConstructor(JSContext* cx, HandleFunction fun,
+ ProtoGetter protoGetter, const Class* clasp)
+{
+ // Step 1 (skipped).
+
+ // Step 2.
+ RootedValue protoVal(cx);
+ if (!GetProperty(cx, fun, fun, cx->names().prototype, &protoVal))
+ return nullptr;
+
+ RootedObject proto(cx, protoVal.isObject() ? &protoVal.toObject() : nullptr);
+ if (!proto) {
+ proto = protoGetter(cx, cx->global());
+ if (!proto)
+ return nullptr;
+ }
+
+ // Step 3.
+ return NewNativeObjectWithGivenProto(cx, clasp, proto);
+}
+
+/* static */ AsyncGeneratorObject*
+AsyncGeneratorObject::create(JSContext* cx, HandleFunction asyncGen, HandleValue generatorVal)
+{
+ MOZ_ASSERT(generatorVal.isObject());
+ MOZ_ASSERT(generatorVal.toObject().is<GeneratorObject>());
+
+ RootedObject obj(
+ cx, OrdinaryCreateFromConstructor(cx, asyncGen,
+ GlobalObject::getOrCreateAsyncGeneratorPrototype,
+ &class_));
+ if (!obj)
+ return nullptr;
+
+ Handle<AsyncGeneratorObject*> asyncGenObj = obj.as<AsyncGeneratorObject>();
+
+ // Async Iteration proposal 6.4.3.2 AsyncGeneratorStart.
+ // Step 6.
+ asyncGenObj->setGenerator(generatorVal);
+
+ // Step 7.
+ asyncGenObj->setSuspendedStart();
+
+ // Step 8.
+ asyncGenObj->clearSingleQueueRequest();
+
+ return asyncGenObj;
+}
+
+static MOZ_MUST_USE bool
+InternalEnqueue(JSContext* cx, HandleArrayObject queue, HandleValue val)
+{
+ uint32_t length;
+ if (!GetLengthProperty(cx, queue, &length))
+ return false;
+
+ if (length >= MAX_ARRAY_INDEX) {
+ ReportOutOfMemory(cx);
+ return false;
+ }
+
+ if (!DefineElement(cx, queue, length, val))
+ return false;
+ return SetLengthProperty(cx, queue, length + 1);
+}
+
+static MOZ_MUST_USE bool
+InternalDequeue(JSContext* cx, HandleArrayObject queue, MutableHandleValue val)
+{
+ uint32_t length;
+ if (!GetLengthProperty(cx, queue, &length))
+ return false;
+
+ MOZ_ASSERT(length != 0, "Queue should not be empty here");
+
+ if (!GetElement(cx, queue, queue, 0, val))
+ return false;
+
+ uint32_t newlength = length - 1;
+ RootedValue tmp(cx);
+ for (uint32_t i = 0; i < newlength; i++) {
+ if (!GetElement(cx, queue, queue, i + 1, &tmp))
+ return false;
+ if (!DefineElement(cx, queue, i, tmp))
+ return false;
+ }
+ ObjectOpResult result;
+ if (!DeleteElement(cx, queue, newlength, result))
+ return false;
+ if (!result) {
+ RootedId id(cx, INT_TO_JSID(newlength));
+ return result.reportError(cx, queue, id);
+ }
+ return SetLengthProperty(cx, queue, newlength);
+}
+
+/* static */ MOZ_MUST_USE bool
+AsyncGeneratorObject::enqueueRequest(JSContext* cx, Handle<AsyncGeneratorObject*> asyncGenObj,
+ Handle<AsyncGeneratorRequest*> request)
+{
+ if (asyncGenObj->isSingleQueue()) {
+ if (asyncGenObj->isSingleQueueEmpty()) {
+ asyncGenObj->setSingleQueueRequest(request);
+ return true;
+ }
+
+ RootedArrayObject queue(cx, NewDenseEmptyArray(cx));
+ if (!queue)
+ return false;
+
+ if (!NewbornArrayPush(cx, queue, ObjectValue(*asyncGenObj->singleQueueRequest())))
+ return false;
+ if (!NewbornArrayPush(cx, queue, ObjectValue(*request)))
+ return false;
+
+ asyncGenObj->setQueue(queue);
+ return true;
+ }
+
+ RootedArrayObject queue(cx, asyncGenObj->queue());
+ RootedValue requestVal(cx, ObjectValue(*request));
+ return InternalEnqueue(cx, queue, requestVal);
+}
+
+/* static */ AsyncGeneratorRequest*
+AsyncGeneratorObject::dequeueRequest(JSContext* cx, Handle<AsyncGeneratorObject*> asyncGenObj)
+{
+ if (asyncGenObj->isSingleQueue()) {
+ AsyncGeneratorRequest* request = asyncGenObj->singleQueueRequest();
+ asyncGenObj->clearSingleQueueRequest();
+ return request;
+ }
+
+ RootedArrayObject queue(cx, asyncGenObj->queue());
+ RootedValue requestVal(cx);
+ if (!InternalDequeue(cx, queue, &requestVal))
+ return nullptr;
+
+ return &requestVal.toObject().as<AsyncGeneratorRequest>();
+}
+
+/* static */ AsyncGeneratorRequest*
+AsyncGeneratorObject::peekRequest(JSContext* cx, Handle<AsyncGeneratorObject*> asyncGenObj)
+{
+ if (asyncGenObj->isSingleQueue())
+ return asyncGenObj->singleQueueRequest();
+
+ RootedArrayObject queue(cx, asyncGenObj->queue());
+
+ RootedValue requestVal(cx);
+ if (!GetElement(cx, queue, queue, 0, &requestVal))
+ return nullptr;
+
+ return &requestVal.toObject().as<AsyncGeneratorRequest>();
+}
+
+const Class AsyncGeneratorRequest::class_ = {
+ "AsyncGeneratorRequest",
+ JSCLASS_HAS_RESERVED_SLOTS(AsyncGeneratorRequest::Slots)
+};
+
+// Async Iteration proposal 11.4.3.1.
+/* static */ AsyncGeneratorRequest*
+AsyncGeneratorRequest::create(JSContext* cx, CompletionKind completionKind_,
+ HandleValue completionValue_, HandleObject promise_)
+{
+ RootedObject obj(cx, NewNativeObjectWithGivenProto(cx, &class_, nullptr));
+ if (!obj)
+ return nullptr;
+
+ Handle<AsyncGeneratorRequest*> request = obj.as<AsyncGeneratorRequest>();
+ request->setCompletionKind(completionKind_);
+ request->setCompletionValue(completionValue_);
+ request->setPromise(promise_);
+ return request;
+}
+
+// Async Iteration proposal 11.4.3.2 AsyncGeneratorStart steps 5.d-g.
+static MOZ_MUST_USE bool
+AsyncGeneratorReturned(JSContext* cx, Handle<AsyncGeneratorObject*> asyncGenObj,
+ HandleValue value)
+{
+ // Step 5.d.
+ asyncGenObj->setCompleted();
+
+ // Step 5.e (done in bytecode).
+ // Step 5.f.i (implicit).
+
+ // Step 5.g.
+ return AsyncGeneratorResolve(cx, asyncGenObj, value, true);
+}
+
+// Async Iteration proposal 11.4.3.2 AsyncGeneratorStart steps 5.d, f.
+static MOZ_MUST_USE bool
+AsyncGeneratorThrown(JSContext* cx, Handle<AsyncGeneratorObject*> asyncGenObj)
+{
+ // Step 5.d.
+ asyncGenObj->setCompleted();
+
+ // Not much we can do about uncatchable exceptions, so just bail.
+ if (!cx->isExceptionPending())
+ return false;
+
+ // Step 5.f.i.
+ RootedValue value(cx);
+ if (!GetAndClearException(cx, &value))
+ return false;
+
+ // Step 5.f.ii.
+ return AsyncGeneratorReject(cx, asyncGenObj, value);
+}
+
+// Async Iteration proposal 11.4.3.7 (partially).
+// Most steps are done in generator.
+static MOZ_MUST_USE bool
+AsyncGeneratorYield(JSContext* cx, Handle<AsyncGeneratorObject*> asyncGenObj, HandleValue value)
+{
+ // Step 5 is done in bytecode.
+
+ // Step 6.
+ asyncGenObj->setSuspendedYield();
+
+ // Step 9.
+ return AsyncGeneratorResolve(cx, asyncGenObj, value, false);
+}
+
+// Async Iteration proposal 4.1 Await steps 2-9.
+// Async Iteration proposal 8.2.1 yield* steps 6.a.vii, 6.b.ii.7, 6.c.ix.
+// Async Iteration proposal 11.4.3.2 AsyncGeneratorStart step 5.f-g.
+// Async Iteration proposal 11.4.3.5 AsyncGeneratorResumeNext
+// steps 12-14, 16-20.
+// Execution context switching is handled in generator.
+MOZ_MUST_USE bool
+js::AsyncGeneratorResume(JSContext* cx, Handle<AsyncGeneratorObject*> asyncGenObj,
+ CompletionKind completionKind, HandleValue argument)
+{
+ RootedValue generatorVal(cx, asyncGenObj->generatorVal());
+
+ // 11.4.3.5 steps 12-14, 16-20.
+ HandlePropertyName funName = completionKind == CompletionKind::Normal
+ ? cx->names().StarGeneratorNext
+ : completionKind == CompletionKind::Throw
+ ? cx->names().StarGeneratorThrow
+ : cx->names().StarGeneratorReturn;
+ FixedInvokeArgs<1> args(cx);
+ args[0].set(argument);
+ RootedValue result(cx);
+ if (!CallSelfHostedFunction(cx, funName, generatorVal, args, &result)) {
+ // 11.4.3.2 step 5.d, f.
+ return AsyncGeneratorThrown(cx, asyncGenObj);
+ }
+
+ // 4.1 steps 2-9.
+ if (asyncGenObj->generatorObj()->isAfterAwait())
+ return AsyncGeneratorAwait(cx, asyncGenObj, result);
+
+ // The following code corresponds to the following 3 cases:
+ // * yield
+ // * yield*
+ // * return
+ // For yield and return, property access is done on an internal result
+ // object and it's not observable.
+ // For yield*, it's done on a possibly user-provided result object, and
+ // it's observable.
+ //
+ // Note that IteratorComplete steps in 8.2.1 are done in bytecode.
+
+ // 8.2.1 yield* steps 6.a.vii, 6.b.ii.7, 6.c.ix.
+ RootedObject resultObj(cx, &result.toObject());
+ RootedValue value(cx);
+
+ if (!GetProperty(cx, resultObj, resultObj, cx->names().value, &value))
+ return false;
+
+ if (asyncGenObj->generatorObj()->isAfterYield())
+ return AsyncGeneratorYield(cx, asyncGenObj, value);
+
+ // 11.4.3.2 step 5.d-g.
+ return AsyncGeneratorReturned(cx, asyncGenObj, value);
+}
+
+static const JSFunctionSpec async_iterator_proto_methods[] = {
+ JS_SELF_HOSTED_SYM_FN(asyncIterator, "AsyncIteratorIdentity", 0, 0),
+ JS_FS_END
+};
+
+static const JSFunctionSpec async_from_sync_iter_methods[] = {
+ JS_FN("next", AsyncFromSyncIteratorNext, 1, 0),
+ JS_FN("throw", AsyncFromSyncIteratorThrow, 1, 0),
+ JS_FN("return", AsyncFromSyncIteratorReturn, 1, 0),
+ JS_FS_END
+};
+
+static const JSFunctionSpec async_generator_methods[] = {
+ JS_FN("next", AsyncGeneratorNext, 1, 0),
+ JS_FN("throw", AsyncGeneratorThrow, 1, 0),
+ JS_FN("return", AsyncGeneratorReturn, 1, 0),
+ JS_FS_END
+};
+
+/* static */ MOZ_MUST_USE bool
+GlobalObject::initAsyncGenerators(JSContext* cx, Handle<GlobalObject*> global)
+{
+ if (global->getReservedSlot(ASYNC_ITERATOR_PROTO).isObject())
+ return true;
+
+ // Async Iteration proposal 11.1.2 %AsyncIteratorPrototype%.
+ RootedObject asyncIterProto(cx, GlobalObject::createBlankPrototype<PlainObject>(cx, global));
+ if (!asyncIterProto)
+ return false;
+ if (!DefinePropertiesAndFunctions(cx, asyncIterProto, nullptr, async_iterator_proto_methods))
+ return false;
+
+ // Async Iteration proposal 11.1.3.2 %AsyncFromSyncIteratorPrototype%.
+ RootedObject asyncFromSyncIterProto(
+ cx, GlobalObject::createBlankPrototypeInheriting(cx, global, &PlainObject::class_,
+ asyncIterProto));
+ if (!asyncFromSyncIterProto)
+ return false;
+ if (!DefinePropertiesAndFunctions(cx, asyncFromSyncIterProto, nullptr,
+ async_from_sync_iter_methods) ||
+ !DefineToStringTag(cx, asyncFromSyncIterProto, cx->names().AsyncFromSyncIterator))
+ {
+ return false;
+ }
+
+ // Async Iteration proposal 11.4.1 %AsyncGeneratorPrototype%.
+ RootedObject asyncGenProto(
+ cx, GlobalObject::createBlankPrototypeInheriting(cx, global, &PlainObject::class_,
+ asyncIterProto));
+ if (!asyncGenProto)
+ return false;
+ if (!DefinePropertiesAndFunctions(cx, asyncGenProto, nullptr, async_generator_methods) ||
+ !DefineToStringTag(cx, asyncGenProto, cx->names().AsyncGenerator))
+ {
+ return false;
+ }
+
+ // Async Iteration proposal 11.3.3 %AsyncGenerator%.
+ RootedObject asyncGenerator(cx, NewSingletonObjectWithFunctionPrototype(cx, global));
+ if (!asyncGenerator)
+ return false;
+ if (!JSObject::setDelegate(cx, asyncGenerator))
+ return false;
+ if (!LinkConstructorAndPrototype(cx, asyncGenerator, asyncGenProto, JSPROP_READONLY,
+ JSPROP_READONLY) ||
+ !DefineToStringTag(cx, asyncGenerator, cx->names().AsyncGeneratorFunction))
+ {
+ return false;
+ }
+
+ RootedValue function(cx, global->getConstructor(JSProto_Function));
+ if (!function.toObjectOrNull())
+ return false;
+ RootedObject proto(cx, &function.toObject());
+ RootedAtom name(cx, cx->names().AsyncGeneratorFunction);
+
+ // Async Iteration proposal 11.3.2 %AsyncGeneratorFunction%.
+ RootedObject asyncGenFunction(
+ cx, NewFunctionWithProto(cx, AsyncGeneratorConstructor, 1, JSFunction::NATIVE_CTOR,
+ nullptr, name, proto, gc::AllocKind::FUNCTION, SingletonObject));
+ if (!asyncGenFunction)
+ return false;
+ if (!LinkConstructorAndPrototype(cx, asyncGenFunction, asyncGenerator,
+ JSPROP_PERMANENT | JSPROP_READONLY, JSPROP_READONLY))
+ {
+ return false;
+ }
+
+ global->setReservedSlot(ASYNC_ITERATOR_PROTO, ObjectValue(*asyncIterProto));
+ global->setReservedSlot(ASYNC_FROM_SYNC_ITERATOR_PROTO, ObjectValue(*asyncFromSyncIterProto));
+ global->setReservedSlot(ASYNC_GENERATOR, ObjectValue(*asyncGenerator));
+ global->setReservedSlot(ASYNC_GENERATOR_FUNCTION, ObjectValue(*asyncGenFunction));
+ global->setReservedSlot(ASYNC_GENERATOR_PROTO, ObjectValue(*asyncGenProto));
+ return true;
+}
diff --git a/js/src/vm/AsyncIteration.h b/js/src/vm/AsyncIteration.h
new file mode 100644
index 000000000..58c43131b
--- /dev/null
+++ b/js/src/vm/AsyncIteration.h
@@ -0,0 +1,256 @@
+/* -*- 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_AsyncIteration_h
+#define vm_AsyncIteration_h
+
+#include "jscntxt.h"
+#include "jsobj.h"
+
+#include "builtin/Promise.h"
+#include "vm/GeneratorObject.h"
+
+namespace js {
+
+// Async generator consists of 2 functions, |wrapped| and |unwrapped|.
+// |unwrapped| is a generator function compiled from async generator script,
+// |await| behaves just like |yield| there. |unwrapped| isn't exposed to user
+// script.
+// |wrapped| is a native function that is the value of async generator.
+
+JSObject*
+WrapAsyncGeneratorWithProto(JSContext* cx, HandleFunction unwrapped, HandleObject proto);
+
+JSObject*
+WrapAsyncGenerator(JSContext* cx, HandleFunction unwrapped);
+
+bool
+IsWrappedAsyncGenerator(JSFunction* fun);
+
+JSFunction*
+GetWrappedAsyncGenerator(JSFunction* unwrapped);
+
+JSFunction*
+GetUnwrappedAsyncGenerator(JSFunction* wrapped);
+
+MOZ_MUST_USE bool
+AsyncGeneratorAwaitedFulfilled(JSContext* cx, Handle<AsyncGeneratorObject*> asyncGenObj,
+ HandleValue value);
+MOZ_MUST_USE bool
+AsyncGeneratorAwaitedRejected(JSContext* cx, Handle<AsyncGeneratorObject*> asyncGenObj,
+ HandleValue reason);
+MOZ_MUST_USE bool
+AsyncGeneratorYieldReturnAwaitedFulfilled(JSContext* cx,
+ Handle<AsyncGeneratorObject*> asyncGenObj,
+ HandleValue value);
+MOZ_MUST_USE bool
+AsyncGeneratorYieldReturnAwaitedRejected(JSContext* cx,
+ Handle<AsyncGeneratorObject*> asyncGenObj,
+ HandleValue reason);
+
+class AsyncGeneratorRequest : public NativeObject
+{
+ private:
+ enum AsyncGeneratorRequestSlots {
+ Slot_CompletionKind = 0,
+ Slot_CompletionValue,
+ Slot_Promise,
+ Slots,
+ };
+
+ void setCompletionKind(CompletionKind completionKind_) {
+ setFixedSlot(Slot_CompletionKind,
+ Int32Value(static_cast<int32_t>(completionKind_)));
+ }
+ void setCompletionValue(HandleValue completionValue_) {
+ setFixedSlot(Slot_CompletionValue, completionValue_);
+ }
+ void setPromise(HandleObject promise_) {
+ setFixedSlot(Slot_Promise, ObjectValue(*promise_));
+ }
+
+ public:
+ static const Class class_;
+
+ static AsyncGeneratorRequest*
+ create(JSContext* cx, CompletionKind completionKind, HandleValue completionValue,
+ HandleObject promise);
+
+ CompletionKind completionKind() const {
+ return static_cast<CompletionKind>(getFixedSlot(Slot_CompletionKind).toInt32());
+ }
+ JS::Value completionValue() const {
+ return getFixedSlot(Slot_CompletionValue);
+ }
+ JSObject* promise() const {
+ return &getFixedSlot(Slot_Promise).toObject();
+ }
+};
+
+class AsyncGeneratorObject : public NativeObject
+{
+ private:
+ enum AsyncGeneratorObjectSlots {
+ Slot_State = 0,
+ Slot_Generator,
+ Slot_QueueOrRequest,
+ Slots
+ };
+
+ enum State {
+ State_SuspendedStart,
+ State_SuspendedYield,
+ State_Executing,
+ // State_AwaitingYieldReturn corresponds to the case that
+ // AsyncGenerator#return is called while State_Executing,
+ // just like the case that AsyncGenerator#return is called
+ // while State_Completed.
+ State_AwaitingYieldReturn,
+ State_AwaitingReturn,
+ State_Completed
+ };
+
+ State state() const {
+ return static_cast<State>(getFixedSlot(Slot_State).toInt32());
+ }
+ void setState(State state_) {
+ setFixedSlot(Slot_State, Int32Value(state_));
+ }
+
+ void setGenerator(const Value& value) {
+ setFixedSlot(Slot_Generator, value);
+ }
+
+ // Queue is implemented in 2 ways. If only one request is queued ever,
+ // request is stored directly to the slot. Once 2 requests are queued, an
+ // array is created and requests are pushed into it, and the array is
+ // stored to the slot.
+
+ bool isSingleQueue() const {
+ return getFixedSlot(Slot_QueueOrRequest).isNull() ||
+ getFixedSlot(Slot_QueueOrRequest).toObject().is<AsyncGeneratorRequest>();
+ }
+ bool isSingleQueueEmpty() const {
+ return getFixedSlot(Slot_QueueOrRequest).isNull();
+ }
+ void setSingleQueueRequest(AsyncGeneratorRequest* request) {
+ setFixedSlot(Slot_QueueOrRequest, ObjectValue(*request));
+ }
+ void clearSingleQueueRequest() {
+ setFixedSlot(Slot_QueueOrRequest, NullHandleValue);
+ }
+ AsyncGeneratorRequest* singleQueueRequest() const {
+ return &getFixedSlot(Slot_QueueOrRequest).toObject().as<AsyncGeneratorRequest>();
+ }
+
+ ArrayObject* queue() const {
+ return &getFixedSlot(Slot_QueueOrRequest).toObject().as<ArrayObject>();
+ }
+ void setQueue(JSObject* queue_) {
+ setFixedSlot(Slot_QueueOrRequest, ObjectValue(*queue_));
+ }
+
+ public:
+ static const Class class_;
+
+ static AsyncGeneratorObject*
+ create(JSContext* cx, HandleFunction asyncGen, HandleValue generatorVal);
+
+ bool isSuspendedStart() const {
+ return state() == State_SuspendedStart;
+ }
+ bool isSuspendedYield() const {
+ return state() == State_SuspendedYield;
+ }
+ bool isExecuting() const {
+ return state() == State_Executing;
+ }
+ bool isAwaitingYieldReturn() const {
+ return state() == State_AwaitingYieldReturn;
+ }
+ bool isAwaitingReturn() const {
+ return state() == State_AwaitingReturn;
+ }
+ bool isCompleted() const {
+ return state() == State_Completed;
+ }
+
+ void setSuspendedStart() {
+ setState(State_SuspendedStart);
+ }
+ void setSuspendedYield() {
+ setState(State_SuspendedYield);
+ }
+ void setExecuting() {
+ setState(State_Executing);
+ }
+ void setAwaitingYieldReturn() {
+ setState(State_AwaitingYieldReturn);
+ }
+ void setAwaitingReturn() {
+ setState(State_AwaitingReturn);
+ }
+ void setCompleted() {
+ setState(State_Completed);
+ }
+
+ JS::Value generatorVal() const {
+ return getFixedSlot(Slot_Generator);
+ }
+ GeneratorObject* generatorObj() const {
+ return &getFixedSlot(Slot_Generator).toObject().as<GeneratorObject>();
+ }
+
+ static MOZ_MUST_USE bool
+ enqueueRequest(JSContext* cx, Handle<AsyncGeneratorObject*> asyncGenObj,
+ Handle<AsyncGeneratorRequest*> request);
+
+ static AsyncGeneratorRequest*
+ dequeueRequest(JSContext* cx, Handle<AsyncGeneratorObject*> asyncGenObj);
+
+ static AsyncGeneratorRequest*
+ peekRequest(JSContext* cx, Handle<AsyncGeneratorObject*> asyncGenObj);
+
+ bool isQueueEmpty() const {
+ if (isSingleQueue())
+ return isSingleQueueEmpty();
+ return queue()->length() == 0;
+ }
+};
+
+JSObject*
+CreateAsyncFromSyncIterator(JSContext* cx, HandleObject iter);
+
+class AsyncFromSyncIteratorObject : public NativeObject
+{
+ private:
+ enum AsyncFromSyncIteratorObjectSlots {
+ Slot_Iterator = 0,
+ Slots
+ };
+
+ void setIterator(HandleObject iterator_) {
+ setFixedSlot(Slot_Iterator, ObjectValue(*iterator_));
+ }
+
+ public:
+ static const Class class_;
+
+ static JSObject*
+ create(JSContext* cx, HandleObject iter);
+
+ JSObject* iterator() const {
+ return &getFixedSlot(Slot_Iterator).toObject();
+ }
+};
+
+MOZ_MUST_USE bool
+AsyncGeneratorResume(JSContext* cx, Handle<AsyncGeneratorObject*> asyncGenObj,
+ CompletionKind completionKind, HandleValue argument);
+
+} // namespace js
+
+#endif /* vm_AsyncIteration_h */
diff --git a/js/src/vm/CommonPropertyNames.h b/js/src/vm/CommonPropertyNames.h
index fd1c9f5e6..6a8afb56b 100644
--- a/js/src/vm/CommonPropertyNames.h
+++ b/js/src/vm/CommonPropertyNames.h
@@ -29,7 +29,10 @@
macro(ArrayValuesAt, ArrayValuesAt, "ArrayValuesAt") \
macro(as, as, "as") \
macro(Async, Async, "Async") \
+ macro(AsyncFromSyncIterator, AsyncFromSyncIterator, "Async-from-Sync Iterator") \
macro(AsyncFunction, AsyncFunction, "AsyncFunction") \
+ macro(AsyncGenerator, AsyncGenerator, "AsyncGenerator") \
+ macro(AsyncGeneratorFunction, AsyncGeneratorFunction, "AsyncGeneratorFunction") \
macro(AsyncWrapped, AsyncWrapped, "AsyncWrapped") \
macro(async, async, "async") \
macro(await, await, "await") \
@@ -97,6 +100,7 @@
macro(displayURL, displayURL, "displayURL") \
macro(do, do_, "do") \
macro(done, done, "done") \
+ macro(dotall, dotall, "dotall") \
macro(dotGenerator, dotGenerator, ".generator") \
macro(dotThis, dotThis, ".this") \
macro(each, each, "each") \
@@ -281,6 +285,7 @@
macro(RegExpFlagsGetter, RegExpFlagsGetter, "RegExpFlagsGetter") \
macro(RegExpMatcher, RegExpMatcher, "RegExpMatcher") \
macro(RegExpSearcher, RegExpSearcher, "RegExpSearcher") \
+ macro(RegExpStringIterator, RegExpStringIterator, "RegExp String Iterator") \
macro(RegExpTester, RegExpTester, "RegExpTester") \
macro(RegExp_prototype_Exec, RegExp_prototype_Exec, "RegExp_prototype_Exec") \
macro(Reify, Reify, "Reify") \
@@ -309,6 +314,7 @@
macro(star, star, "*") \
macro(starDefaultStar, starDefaultStar, "*default*") \
macro(StarGeneratorNext, StarGeneratorNext, "StarGeneratorNext") \
+ macro(StarGeneratorReturn, StarGeneratorReturn, "StarGeneratorReturn") \
macro(StarGeneratorThrow, StarGeneratorThrow, "StarGeneratorThrow") \
macro(startTimestamp, startTimestamp, "startTimestamp") \
macro(state, state, "state") \
diff --git a/js/src/vm/Debugger.cpp b/js/src/vm/Debugger.cpp
index d68d1b75e..c49df5aa9 100644
--- a/js/src/vm/Debugger.cpp
+++ b/js/src/vm/Debugger.cpp
@@ -32,7 +32,6 @@
#include "js/Vector.h"
#include "proxy/ScriptedProxyHandler.h"
#include "vm/ArgumentsObject.h"
-#include "vm/AsyncFunction.h"
#include "vm/DebuggerMemory.h"
#include "vm/GeneratorObject.h"
#include "vm/SPSProfiler.h"
@@ -1560,16 +1559,11 @@ CheckResumptionValue(JSContext* cx, AbstractFramePtr frame, const Maybe<HandleVa
JSTrapStatus status, MutableHandleValue vp)
{
if (status == JSTRAP_RETURN && frame && frame.isFunctionFrame()) {
- // Don't let a { return: ... } resumption value make a generator or
- // async function violate the iterator protocol. The return value from
+ // Don't let a { return: ... } resumption value make a generator
+ // function violate the iterator protocol. The return value from
// such a frame must have the form { done: <bool>, value: <anything> }.
RootedFunction callee(cx, frame.callee());
- if (callee->isAsync()) {
- if (!CheckAsyncResumptionValue(cx, vp)) {
- JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr, JSMSG_DEBUG_BAD_AWAIT);
- return false;
- }
- } else if (callee->isStarGenerator()) {
+ if (callee->isStarGenerator()) {
if (!CheckStarGeneratorResumptionValue(cx, vp)) {
JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr, JSMSG_DEBUG_BAD_YIELD);
return false;
@@ -7356,7 +7350,8 @@ DebuggerFrame::getEnvironment(JSContext* cx, HandleDebuggerFrame frame,
/* static */ bool
DebuggerFrame::getIsGenerator(HandleDebuggerFrame frame)
{
- return DebuggerFrame::getReferent(frame).script()->isGenerator();
+ return DebuggerFrame::getReferent(frame).script()->isStarGenerator() ||
+ DebuggerFrame::getReferent(frame).script()->isLegacyGenerator();
}
/* static */ bool
@@ -8733,7 +8728,6 @@ DebuggerObject::proxyHandlerGetter(JSContext* cx, unsigned argc, Value* vp)
return true;
}
-#ifdef SPIDERMONKEY_PROMISE
/* static */ bool
DebuggerObject::isPromiseGetter(JSContext* cx, unsigned argc, Value* vp)
{
@@ -8902,7 +8896,6 @@ DebuggerObject::promiseDependentPromisesGetter(JSContext* cx, unsigned argc, Val
args.rval().setObject(*promises);
return true;
}
-#endif // SPIDERMONKEY_PROMISE
/* static */ bool
DebuggerObject::isExtensibleMethod(JSContext* cx, unsigned argc, Value* vp)
@@ -9341,7 +9334,6 @@ const JSPropertySpec DebuggerObject::properties_[] = {
JS_PS_END
};
-#ifdef SPIDERMONKEY_PROMISE
const JSPropertySpec DebuggerObject::promiseProperties_[] = {
JS_PSG("isPromise", DebuggerObject::isPromiseGetter, 0),
JS_PSG("promiseState", DebuggerObject::promiseStateGetter, 0),
@@ -9355,7 +9347,6 @@ const JSPropertySpec DebuggerObject::promiseProperties_[] = {
JS_PSG("promiseDependentPromises", DebuggerObject::promiseDependentPromisesGetter, 0),
JS_PS_END
};
-#endif // SPIDERMONKEY_PROMISE
const JSFunctionSpec DebuggerObject::methods_[] = {
JS_FN("isExtensible", DebuggerObject::isExtensibleMethod, 0, 0),
@@ -9395,10 +9386,8 @@ DebuggerObject::initClass(JSContext* cx, HandleObject obj, HandleObject debugCto
if (!objectProto)
return nullptr;
-#ifdef SPIDERMONKEY_PROMISE
if (!DefinePropertiesAndFunctions(cx, objectProto, promiseProperties_, nullptr))
return nullptr;
-#endif // SPIDERMONKEY_PROMISE
return objectProto;
}
@@ -9466,7 +9455,6 @@ DebuggerObject::isScriptedProxy() const
return js::IsScriptedProxy(referent());
}
-#ifdef SPIDERMONKEY_PROMISE
bool
DebuggerObject::isPromise() const
{
@@ -9480,7 +9468,6 @@ DebuggerObject::isPromise() const
return referent->is<PromiseObject>();
}
-#endif // SPIDERMONKEY_PROMISE
/* static */ bool
DebuggerObject::getClassName(JSContext* cx, HandleDebuggerObject object,
@@ -9763,7 +9750,6 @@ DebuggerObject::getErrorColumnNumber(JSContext* cx, HandleDebuggerObject object,
return true;
}
-#ifdef SPIDERMONKEY_PROMISE
/* static */ bool
DebuggerObject::getPromiseValue(JSContext* cx, HandleDebuggerObject object,
MutableHandleValue result)
@@ -9783,7 +9769,6 @@ DebuggerObject::getPromiseReason(JSContext* cx, HandleDebuggerObject object,
result.set(object->promise()->reason());
return object->owner()->wrapDebuggeeValue(cx, result);
}
-#endif // SPIDERMONKEY_PROMISE
/* static */ bool
DebuggerObject::isExtensible(JSContext* cx, HandleDebuggerObject object, bool& result)
@@ -10253,7 +10238,6 @@ DebuggerObject::requireGlobal(JSContext* cx, HandleDebuggerObject object)
return true;
}
-#ifdef SPIDERMONKEY_PROMISE
/* static */ bool
DebuggerObject::requirePromise(JSContext* cx, HandleDebuggerObject object)
{
@@ -10275,7 +10259,6 @@ DebuggerObject::requirePromise(JSContext* cx, HandleDebuggerObject object)
return true;
}
-#endif // SPIDERMONKEY_PROMISE
/* static */ bool
DebuggerObject::getScriptedProxyTarget(JSContext* cx, HandleDebuggerObject object,
diff --git a/js/src/vm/Debugger.h b/js/src/vm/Debugger.h
index cdcf2d67f..204d1ca3e 100644
--- a/js/src/vm/Debugger.h
+++ b/js/src/vm/Debugger.h
@@ -1256,12 +1256,10 @@ class DebuggerObject : public NativeObject
MutableHandleDebuggerObject result);
static MOZ_MUST_USE bool getScriptedProxyHandler(JSContext* cx, HandleDebuggerObject object,
MutableHandleDebuggerObject result);
-#ifdef SPIDERMONKEY_PROMISE
static MOZ_MUST_USE bool getPromiseValue(JSContext* cx, HandleDebuggerObject object,
MutableHandleValue result);
static MOZ_MUST_USE bool getPromiseReason(JSContext* cx, HandleDebuggerObject object,
MutableHandleValue result);
-#endif // SPIDERMONKEY_PROMISE
// Methods
static MOZ_MUST_USE bool isExtensible(JSContext* cx, HandleDebuggerObject object,
@@ -1311,16 +1309,12 @@ class DebuggerObject : public NativeObject
bool isArrowFunction() const;
bool isGlobal() const;
bool isScriptedProxy() const;
-#ifdef SPIDERMONKEY_PROMISE
bool isPromise() const;
-#endif // SPIDERMONKEY_PROMISE
JSAtom* name() const;
JSAtom* displayName() const;
-#ifdef SPIDERMONKEY_PROMISE
JS::PromiseState promiseState() const;
double promiseLifetime() const;
double promiseTimeToResolution() const;
-#endif // SPIDERMONKEY_PROMISE
private:
enum {
@@ -1332,9 +1326,7 @@ class DebuggerObject : public NativeObject
static const ClassOps classOps_;
static const JSPropertySpec properties_[];
-#ifdef SPIDERMONKEY_PROMISE
static const JSPropertySpec promiseProperties_[];
-#endif // SPIDERMONKEY_PROMISE
static const JSFunctionSpec methods_[];
JSObject* referent() const {
@@ -1345,14 +1337,10 @@ class DebuggerObject : public NativeObject
Debugger* owner() const;
-#ifdef SPIDERMONKEY_PROMISE
PromiseObject* promise() const;
-#endif // SPIDERMONKEY_PROMISE
static MOZ_MUST_USE bool requireGlobal(JSContext* cx, HandleDebuggerObject object);
-#ifdef SPIDERMONKEY_PROMISE
static MOZ_MUST_USE bool requirePromise(JSContext* cx, HandleDebuggerObject object);
-#endif // SPIDERMONKEY_PROMISE
static MOZ_MUST_USE bool construct(JSContext* cx, unsigned argc, Value* vp);
@@ -1379,7 +1367,6 @@ class DebuggerObject : public NativeObject
static MOZ_MUST_USE bool isProxyGetter(JSContext* cx, unsigned argc, Value* vp);
static MOZ_MUST_USE bool proxyTargetGetter(JSContext* cx, unsigned argc, Value* vp);
static MOZ_MUST_USE bool proxyHandlerGetter(JSContext* cx, unsigned argc, Value* vp);
-#ifdef SPIDERMONKEY_PROMISE
static MOZ_MUST_USE bool isPromiseGetter(JSContext* cx, unsigned argc, Value* vp);
static MOZ_MUST_USE bool promiseStateGetter(JSContext* cx, unsigned argc, Value* vp);
static MOZ_MUST_USE bool promiseValueGetter(JSContext* cx, unsigned argc, Value* vp);
@@ -1390,7 +1377,6 @@ class DebuggerObject : public NativeObject
static MOZ_MUST_USE bool promiseResolutionSiteGetter(JSContext* cx, unsigned argc, Value* vp);
static MOZ_MUST_USE bool promiseIDGetter(JSContext* cx, unsigned argc, Value* vp);
static MOZ_MUST_USE bool promiseDependentPromisesGetter(JSContext* cx, unsigned argc, Value* vp);
-#endif // SPIDERMONKEY_PROMISE
// JSNative methods
static MOZ_MUST_USE bool isExtensibleMethod(JSContext* cx, unsigned argc, Value* vp);
diff --git a/js/src/vm/EnvironmentObject.cpp b/js/src/vm/EnvironmentObject.cpp
index a5aac2ab4..7834940f1 100644
--- a/js/src/vm/EnvironmentObject.cpp
+++ b/js/src/vm/EnvironmentObject.cpp
@@ -408,7 +408,6 @@ const ObjectOps ModuleEnvironmentObject::objectOps_ = {
ModuleEnvironmentObject::setProperty,
ModuleEnvironmentObject::getOwnPropertyDescriptor,
ModuleEnvironmentObject::deleteProperty,
- nullptr, nullptr, /* watch/unwatch */
nullptr, /* getElements */
ModuleEnvironmentObject::enumerate,
nullptr
@@ -491,7 +490,7 @@ ModuleEnvironmentObject::createImportBinding(JSContext* cx, HandleAtom importNam
{
RootedId importNameId(cx, AtomToId(importName));
RootedId localNameId(cx, AtomToId(localName));
- RootedModuleEnvironmentObject env(cx, module->environment());
+ RootedModuleEnvironmentObject env(cx, &module->initialEnvironment());
if (!importBindings().putNew(cx, importNameId, env, localNameId)) {
ReportOutOfMemory(cx);
return false;
@@ -790,7 +789,6 @@ static const ObjectOps WithEnvironmentObjectOps = {
with_SetProperty,
with_GetOwnPropertyDescriptor,
with_DeleteProperty,
- nullptr, nullptr, /* watch/unwatch */
nullptr, /* getElements */
nullptr, /* enumerate (native enumeration of target doesn't work) */
nullptr,
@@ -1159,7 +1157,6 @@ static const ObjectOps RuntimeLexicalErrorObjectObjectOps = {
lexicalError_SetProperty,
lexicalError_GetOwnPropertyDescriptor,
lexicalError_DeleteProperty,
- nullptr, nullptr, /* watch/unwatch */
nullptr, /* getElements */
nullptr, /* enumerate (native enumeration of target doesn't work) */
nullptr, /* this */
@@ -2451,7 +2448,9 @@ DebugEnvironments::addDebugEnvironment(JSContext* cx, const EnvironmentIter& ei,
MOZ_ASSERT(cx->compartment() == debugEnv->compartment());
// Generators should always have environments.
MOZ_ASSERT_IF(ei.scope().is<FunctionScope>(),
- !ei.scope().as<FunctionScope>().canonicalFunction()->isGenerator());
+ !ei.scope().as<FunctionScope>().canonicalFunction()->isStarGenerator() &&
+ !ei.scope().as<FunctionScope>().canonicalFunction()->isLegacyGenerator() &&
+ !ei.scope().as<FunctionScope>().canonicalFunction()->isAsync());
if (!CanUseDebugEnvironmentMaps(cx))
return true;
@@ -2597,8 +2596,11 @@ DebugEnvironments::onPopCall(JSContext* cx, AbstractFramePtr frame)
if (!frame.environmentChain()->is<CallObject>())
return;
- if (frame.callee()->isGenerator())
+ if (frame.callee()->isStarGenerator() || frame.callee()->isLegacyGenerator() ||
+ frame.callee()->isAsync())
+ {
return;
+ }
CallObject& callobj = frame.environmentChain()->as<CallObject>();
envs->liveEnvs.remove(&callobj);
@@ -2729,8 +2731,13 @@ DebugEnvironments::updateLiveEnvironments(JSContext* cx)
if (frame.environmentChain()->compartment() != cx->compartment())
continue;
- if (frame.isFunctionFrame() && frame.callee()->isGenerator())
- continue;
+ if (frame.isFunctionFrame()) {
+ if (frame.callee()->isStarGenerator() || frame.callee()->isLegacyGenerator() ||
+ frame.callee()->isAsync())
+ {
+ continue;
+ }
+ }
if (!frame.isDebuggee())
continue;
@@ -2885,7 +2892,8 @@ GetDebugEnvironmentForMissing(JSContext* cx, const EnvironmentIter& ei)
if (ei.scope().is<FunctionScope>()) {
RootedFunction callee(cx, ei.scope().as<FunctionScope>().canonicalFunction());
// Generators should always reify their scopes.
- MOZ_ASSERT(!callee->isGenerator());
+ MOZ_ASSERT(!callee->isStarGenerator() && !callee->isLegacyGenerator() &&
+ !callee->isAsync());
JS::ExposeObjectToActiveJS(callee);
Rooted<CallObject*> callobj(cx, CallObject::createHollowForDebug(cx, callee));
diff --git a/js/src/vm/GeneratorObject.cpp b/js/src/vm/GeneratorObject.cpp
index ba28501e6..2f5c63c28 100644
--- a/js/src/vm/GeneratorObject.cpp
+++ b/js/src/vm/GeneratorObject.cpp
@@ -19,12 +19,13 @@ using namespace js;
JSObject*
GeneratorObject::create(JSContext* cx, AbstractFramePtr frame)
{
- MOZ_ASSERT(frame.script()->isGenerator());
+ MOZ_ASSERT(frame.script()->isStarGenerator() || frame.script()->isLegacyGenerator() ||
+ frame.script()->isAsync());
MOZ_ASSERT(frame.script()->nfixed() == 0);
Rooted<GlobalObject*> global(cx, cx->global());
RootedNativeObject obj(cx);
- if (frame.script()->isStarGenerator()) {
+ if (frame.script()->isStarGenerator() || frame.script()->isAsync()) {
RootedValue pval(cx);
RootedObject fun(cx, frame.callee());
// FIXME: This would be faster if we could avoid doing a lookup to get
@@ -63,10 +64,14 @@ bool
GeneratorObject::suspend(JSContext* cx, HandleObject obj, AbstractFramePtr frame, jsbytecode* pc,
Value* vp, unsigned nvalues)
{
- MOZ_ASSERT(*pc == JSOP_INITIALYIELD || *pc == JSOP_YIELD);
+ MOZ_ASSERT(*pc == JSOP_INITIALYIELD || *pc == JSOP_YIELD || *pc == JSOP_AWAIT);
Rooted<GeneratorObject*> genObj(cx, &obj->as<GeneratorObject>());
MOZ_ASSERT(!genObj->hasExpressionStack());
+ MOZ_ASSERT_IF(*pc == JSOP_AWAIT, genObj->callee().isAsync());
+ MOZ_ASSERT_IF(*pc == JSOP_YIELD,
+ genObj->callee().isStarGenerator() ||
+ genObj->callee().isLegacyGenerator());
if (*pc == JSOP_YIELD && genObj->isClosing() && genObj->is<LegacyGeneratorObject>()) {
RootedValue val(cx, ObjectValue(*frame.callee()));
@@ -74,8 +79,8 @@ GeneratorObject::suspend(JSContext* cx, HandleObject obj, AbstractFramePtr frame
return false;
}
- uint32_t yieldIndex = GET_UINT24(pc);
- genObj->setYieldIndex(yieldIndex);
+ uint32_t yieldAndAwaitIndex = GET_UINT24(pc);
+ genObj->setYieldAndAwaitIndex(yieldAndAwaitIndex);
genObj->setEnvironmentChain(*frame.environmentChain());
if (nvalues) {
@@ -172,7 +177,7 @@ GeneratorObject::resume(JSContext* cx, InterpreterActivation& activation,
}
JSScript* script = callee->nonLazyScript();
- uint32_t offset = script->yieldOffsets()[genObj->yieldIndex()];
+ uint32_t offset = script->yieldAndAwaitOffsets()[genObj->yieldAndAwaitIndex()];
activation.regs().pc = script->offsetToPC(offset);
// Always push on a value, even if we are raising an exception. In the
@@ -311,7 +316,8 @@ GlobalObject::initStarGenerators(JSContext* cx, Handle<GlobalObject*> global)
RootedObject genFunctionProto(cx, NewSingletonObjectWithFunctionPrototype(cx, global));
if (!genFunctionProto || !JSObject::setDelegate(cx, genFunctionProto))
return false;
- if (!LinkConstructorAndPrototype(cx, genFunctionProto, genObjectProto) ||
+ if (!LinkConstructorAndPrototype(cx, genFunctionProto, genObjectProto, JSPROP_READONLY,
+ JSPROP_READONLY) ||
!DefineToStringTag(cx, genFunctionProto, cx->names().GeneratorFunction))
{
return false;
@@ -328,8 +334,11 @@ GlobalObject::initStarGenerators(JSContext* cx, Handle<GlobalObject*> global)
SingletonObject));
if (!genFunction)
return false;
- if (!LinkConstructorAndPrototype(cx, genFunction, genFunctionProto))
+ if (!LinkConstructorAndPrototype(cx, genFunction, genFunctionProto,
+ JSPROP_PERMANENT | JSPROP_READONLY, JSPROP_READONLY))
+ {
return false;
+ }
global->setReservedSlot(STAR_GENERATOR_OBJECT_PROTO, ObjectValue(*genObjectProto));
global->setReservedSlot(STAR_GENERATOR_FUNCTION, ObjectValue(*genFunction));
@@ -365,3 +374,34 @@ js::CheckStarGeneratorResumptionValue(JSContext* cx, HandleValue v)
return true;
}
+
+bool
+GeneratorObject::isAfterYield()
+{
+ return isAfterYieldOrAwait(JSOP_YIELD);
+}
+
+bool
+GeneratorObject::isAfterAwait()
+{
+ return isAfterYieldOrAwait(JSOP_AWAIT);
+}
+
+bool
+GeneratorObject::isAfterYieldOrAwait(JSOp op)
+{
+ if (isClosed() || isClosing() || isRunning())
+ return false;
+
+ JSScript* script = callee().nonLazyScript();
+ jsbytecode* code = script->code();
+ uint32_t nextOffset = script->yieldAndAwaitOffsets()[yieldAndAwaitIndex()];
+ if (code[nextOffset] != JSOP_DEBUGAFTERYIELD)
+ return false;
+
+ uint32_t offset = nextOffset - JSOP_YIELD_LENGTH;
+ MOZ_ASSERT(code[offset] == JSOP_INITIALYIELD || code[offset] == JSOP_YIELD ||
+ code[offset] == JSOP_AWAIT);
+
+ return code[offset] == op;
+}
diff --git a/js/src/vm/GeneratorObject.h b/js/src/vm/GeneratorObject.h
index ca1452b34..f19ca2aac 100644
--- a/js/src/vm/GeneratorObject.h
+++ b/js/src/vm/GeneratorObject.h
@@ -21,15 +21,15 @@ class GeneratorObject : public NativeObject
public:
// Magic values stored in the yield index slot when the generator is
// running or closing. See the yield index comment below.
- static const int32_t YIELD_INDEX_RUNNING = INT32_MAX;
- static const int32_t YIELD_INDEX_CLOSING = INT32_MAX - 1;
+ static const int32_t YIELD_AND_AWAIT_INDEX_RUNNING = INT32_MAX;
+ static const int32_t YIELD_AND_AWAIT_INDEX_CLOSING = INT32_MAX - 1;
enum {
CALLEE_SLOT = 0,
ENV_CHAIN_SLOT,
ARGS_OBJ_SLOT,
EXPRESSION_STACK_SLOT,
- YIELD_INDEX_SLOT,
+ YIELD_AND_AWAIT_INDEX_SLOT,
NEWTARGET_SLOT,
RESERVED_SLOTS
};
@@ -124,47 +124,48 @@ class GeneratorObject : public NativeObject
// The yield index slot is abused for a few purposes. It's undefined if
// it hasn't been set yet (before the initial yield), and null if the
// generator is closed. If the generator is running, the yield index is
- // YIELD_INDEX_RUNNING. If the generator is in that bizarre "closing"
- // state, the yield index is YIELD_INDEX_CLOSING.
+ // YIELD_AND_AWAIT_INDEX_RUNNING. If the generator is in that bizarre
+ // "closing" state, the yield index is YIELD_AND_AWAIT_INDEX_CLOSING.
//
// If the generator is suspended, it's the yield index (stored as
- // JSOP_INITIALYIELD/JSOP_YIELD operand) of the yield instruction that
- // suspended the generator. The yield index can be mapped to the bytecode
- // offset (interpreter) or to the native code offset (JIT).
+ // JSOP_INITIALYIELD/JSOP_YIELD/JSOP_AWAIT operand) of the yield
+ // instruction that suspended the generator. The yield index can be mapped
+ // to the bytecode offset (interpreter) or to the native code offset (JIT).
bool isRunning() const {
MOZ_ASSERT(!isClosed());
- return getFixedSlot(YIELD_INDEX_SLOT).toInt32() == YIELD_INDEX_RUNNING;
+ return getFixedSlot(YIELD_AND_AWAIT_INDEX_SLOT).toInt32() == YIELD_AND_AWAIT_INDEX_RUNNING;
}
bool isClosing() const {
- return getFixedSlot(YIELD_INDEX_SLOT).toInt32() == YIELD_INDEX_CLOSING;
+ return getFixedSlot(YIELD_AND_AWAIT_INDEX_SLOT).toInt32() == YIELD_AND_AWAIT_INDEX_CLOSING;
}
bool isSuspended() const {
// Note: also update Baseline's IsSuspendedStarGenerator code if this
// changes.
MOZ_ASSERT(!isClosed());
- static_assert(YIELD_INDEX_CLOSING < YIELD_INDEX_RUNNING,
- "test below should return false for YIELD_INDEX_RUNNING");
- return getFixedSlot(YIELD_INDEX_SLOT).toInt32() < YIELD_INDEX_CLOSING;
+ static_assert(YIELD_AND_AWAIT_INDEX_CLOSING < YIELD_AND_AWAIT_INDEX_RUNNING,
+ "test below should return false for YIELD_AND_AWAIT_INDEX_RUNNING");
+ return getFixedSlot(YIELD_AND_AWAIT_INDEX_SLOT).toInt32() < YIELD_AND_AWAIT_INDEX_CLOSING;
}
void setRunning() {
MOZ_ASSERT(isSuspended());
- setFixedSlot(YIELD_INDEX_SLOT, Int32Value(YIELD_INDEX_RUNNING));
+ setFixedSlot(YIELD_AND_AWAIT_INDEX_SLOT, Int32Value(YIELD_AND_AWAIT_INDEX_RUNNING));
}
void setClosing() {
MOZ_ASSERT(isSuspended());
- setFixedSlot(YIELD_INDEX_SLOT, Int32Value(YIELD_INDEX_CLOSING));
- }
- void setYieldIndex(uint32_t yieldIndex) {
- MOZ_ASSERT_IF(yieldIndex == 0, getFixedSlot(YIELD_INDEX_SLOT).isUndefined());
- MOZ_ASSERT_IF(yieldIndex != 0, isRunning() || isClosing());
- MOZ_ASSERT(yieldIndex < uint32_t(YIELD_INDEX_CLOSING));
- setFixedSlot(YIELD_INDEX_SLOT, Int32Value(yieldIndex));
+ setFixedSlot(YIELD_AND_AWAIT_INDEX_SLOT, Int32Value(YIELD_AND_AWAIT_INDEX_CLOSING));
+ }
+ void setYieldAndAwaitIndex(uint32_t yieldAndAwaitIndex) {
+ MOZ_ASSERT_IF(yieldAndAwaitIndex == 0,
+ getFixedSlot(YIELD_AND_AWAIT_INDEX_SLOT).isUndefined());
+ MOZ_ASSERT_IF(yieldAndAwaitIndex != 0, isRunning() || isClosing());
+ MOZ_ASSERT(yieldAndAwaitIndex < uint32_t(YIELD_AND_AWAIT_INDEX_CLOSING));
+ setFixedSlot(YIELD_AND_AWAIT_INDEX_SLOT, Int32Value(yieldAndAwaitIndex));
MOZ_ASSERT(isSuspended());
}
- uint32_t yieldIndex() const {
+ uint32_t yieldAndAwaitIndex() const {
MOZ_ASSERT(isSuspended());
- return getFixedSlot(YIELD_INDEX_SLOT).toInt32();
+ return getFixedSlot(YIELD_AND_AWAIT_INDEX_SLOT).toInt32();
}
bool isClosed() const {
return getFixedSlot(CALLEE_SLOT).isNull();
@@ -174,10 +175,17 @@ class GeneratorObject : public NativeObject
setFixedSlot(ENV_CHAIN_SLOT, NullValue());
setFixedSlot(ARGS_OBJ_SLOT, NullValue());
setFixedSlot(EXPRESSION_STACK_SLOT, NullValue());
- setFixedSlot(YIELD_INDEX_SLOT, NullValue());
+ setFixedSlot(YIELD_AND_AWAIT_INDEX_SLOT, NullValue());
setFixedSlot(NEWTARGET_SLOT, NullValue());
}
+ bool isAfterYield();
+ bool isAfterAwait();
+
+private:
+ bool isAfterYieldOrAwait(JSOp op);
+
+public:
static size_t offsetOfCalleeSlot() {
return getFixedSlotOffset(CALLEE_SLOT);
}
@@ -187,8 +195,8 @@ class GeneratorObject : public NativeObject
static size_t offsetOfArgsObjSlot() {
return getFixedSlotOffset(ARGS_OBJ_SLOT);
}
- static size_t offsetOfYieldIndexSlot() {
- return getFixedSlotOffset(YIELD_INDEX_SLOT);
+ static size_t offsetOfYieldAndAwaitIndexSlot() {
+ return getFixedSlotOffset(YIELD_AND_AWAIT_INDEX_SLOT);
}
static size_t offsetOfExpressionStackSlot() {
return getFixedSlotOffset(EXPRESSION_STACK_SLOT);
diff --git a/js/src/vm/GlobalObject.cpp b/js/src/vm/GlobalObject.cpp
index 85707e1c6..a8d401af4 100644
--- a/js/src/vm/GlobalObject.cpp
+++ b/js/src/vm/GlobalObject.cpp
@@ -21,9 +21,7 @@
#include "builtin/MapObject.h"
#include "builtin/ModuleObject.h"
#include "builtin/Object.h"
-#ifdef SPIDERMONKEY_PROMISE
#include "builtin/Promise.h"
-#endif
#include "builtin/RegExp.h"
#include "builtin/SelfHostingDefines.h"
#include "builtin/SymbolObject.h"
@@ -468,62 +466,29 @@ GlobalObject::initSelfHostingBuiltins(JSContext* cx, Handle<GlobalObject*> globa
return false;
}
- RootedValue std_isConcatSpreadable(cx);
- std_isConcatSpreadable.setSymbol(cx->wellKnownSymbols().get(JS::SymbolCode::isConcatSpreadable));
- if (!JS_DefineProperty(cx, global, "std_isConcatSpreadable", std_isConcatSpreadable,
- JSPROP_PERMANENT | JSPROP_READONLY))
- {
- return false;
- }
-
- // Define a top-level property 'std_iterator' with the name of the method
- // used by for-of loops to create an iterator.
- RootedValue std_iterator(cx);
- std_iterator.setSymbol(cx->wellKnownSymbols().get(JS::SymbolCode::iterator));
- if (!JS_DefineProperty(cx, global, "std_iterator", std_iterator,
- JSPROP_PERMANENT | JSPROP_READONLY))
- {
- return false;
- }
-
- RootedValue std_match(cx);
- std_match.setSymbol(cx->wellKnownSymbols().get(JS::SymbolCode::match));
- if (!JS_DefineProperty(cx, global, "std_match", std_match,
- JSPROP_PERMANENT | JSPROP_READONLY))
- {
- return false;
- }
-
- RootedValue std_replace(cx);
- std_replace.setSymbol(cx->wellKnownSymbols().get(JS::SymbolCode::replace));
- if (!JS_DefineProperty(cx, global, "std_replace", std_replace,
- JSPROP_PERMANENT | JSPROP_READONLY))
- {
- return false;
- }
-
- RootedValue std_search(cx);
- std_search.setSymbol(cx->wellKnownSymbols().get(JS::SymbolCode::search));
- if (!JS_DefineProperty(cx, global, "std_search", std_search,
- JSPROP_PERMANENT | JSPROP_READONLY))
- {
- return false;
- }
-
- RootedValue std_species(cx);
- std_species.setSymbol(cx->wellKnownSymbols().get(JS::SymbolCode::species));
- if (!JS_DefineProperty(cx, global, "std_species", std_species,
- JSPROP_PERMANENT | JSPROP_READONLY))
- {
- return false;
- }
-
- RootedValue std_split(cx);
- std_split.setSymbol(cx->wellKnownSymbols().get(JS::SymbolCode::split));
- if (!JS_DefineProperty(cx, global, "std_split", std_split,
- JSPROP_PERMANENT | JSPROP_READONLY))
- {
- return false;
+ struct SymbolAndName {
+ JS::SymbolCode code;
+ const char* name;
+ };
+
+ SymbolAndName wellKnownSymbols[] = {
+ {JS::SymbolCode::isConcatSpreadable, "std_isConcatSpreadable"},
+ {JS::SymbolCode::iterator, "std_iterator"},
+ {JS::SymbolCode::match, "std_match"},
+ {JS::SymbolCode::matchAll, "std_matchAll"},
+ {JS::SymbolCode::replace, "std_replace"},
+ {JS::SymbolCode::search, "std_search"},
+ {JS::SymbolCode::species, "std_species"},
+ {JS::SymbolCode::split, "std_split"},
+ };
+
+ RootedValue symVal(cx);
+ for (const auto& sym : wellKnownSymbols) {
+ symVal.setSymbol(cx->wellKnownSymbols().get(sym.code));
+ if (!JS_DefineProperty(cx, global, sym.name, symVal,
+ JSPROP_PERMANENT | JSPROP_READONLY)) {
+ return false;
+ }
}
return InitBareBuiltinCtor(cx, global, JSProto_Array) &&
@@ -619,17 +584,18 @@ GlobalObject::createBlankPrototypeInheriting(JSContext* cx, Handle<GlobalObject*
}
bool
-js::LinkConstructorAndPrototype(JSContext* cx, JSObject* ctor_, JSObject* proto_)
+js::LinkConstructorAndPrototype(JSContext* cx, JSObject* ctor_, JSObject* proto_,
+ unsigned prototypeAttrs, unsigned constructorAttrs)
{
RootedObject ctor(cx, ctor_), proto(cx, proto_);
RootedValue protoVal(cx, ObjectValue(*proto));
RootedValue ctorVal(cx, ObjectValue(*ctor));
- return DefineProperty(cx, ctor, cx->names().prototype, protoVal,
- nullptr, nullptr, JSPROP_PERMANENT | JSPROP_READONLY) &&
- DefineProperty(cx, proto, cx->names().constructor, ctorVal,
- nullptr, nullptr, 0);
+ return DefineProperty(cx, ctor, cx->names().prototype, protoVal, nullptr, nullptr,
+ prototypeAttrs) &&
+ DefineProperty(cx, proto, cx->names().constructor, ctorVal, nullptr, nullptr,
+ constructorAttrs);
}
bool
diff --git a/js/src/vm/GlobalObject.h b/js/src/vm/GlobalObject.h
index 5aacfc5dc..3fd2762f8 100644
--- a/js/src/vm/GlobalObject.h
+++ b/js/src/vm/GlobalObject.h
@@ -93,12 +93,18 @@ class GlobalObject : public NativeObject
ITERATOR_PROTO,
ARRAY_ITERATOR_PROTO,
STRING_ITERATOR_PROTO,
+ REGEXP_STRING_ITERATOR_PROTO,
LEGACY_GENERATOR_OBJECT_PROTO,
STAR_GENERATOR_OBJECT_PROTO,
STAR_GENERATOR_FUNCTION_PROTO,
STAR_GENERATOR_FUNCTION,
ASYNC_FUNCTION_PROTO,
ASYNC_FUNCTION,
+ ASYNC_ITERATOR_PROTO,
+ ASYNC_FROM_SYNC_ITERATOR_PROTO,
+ ASYNC_GENERATOR,
+ ASYNC_GENERATOR_FUNCTION,
+ ASYNC_GENERATOR_PROTO,
MAP_ITERATOR_PROTO,
SET_ITERATOR_PROTO,
COLLATOR_PROTO,
@@ -583,6 +589,12 @@ class GlobalObject : public NativeObject
}
static NativeObject*
+ getOrCreateRegExpStringIteratorPrototype(JSContext* cx, Handle<GlobalObject*> global) {
+ return MaybeNativeObject(getOrCreateObject(cx, global, REGEXP_STRING_ITERATOR_PROTO,
+ initRegExpStringIteratorProto));
+ }
+
+ static NativeObject*
getOrCreateLegacyGeneratorObjectPrototype(JSContext* cx, Handle<GlobalObject*> global) {
return MaybeNativeObject(getOrCreateObject(cx, global, LEGACY_GENERATOR_OBJECT_PROTO,
initLegacyGeneratorProto));
@@ -617,6 +629,36 @@ class GlobalObject : public NativeObject
return getOrCreateObject(cx, global, ASYNC_FUNCTION, initAsyncFunction);
}
+ static NativeObject*
+ getOrCreateAsyncIteratorPrototype(JSContext* cx, Handle<GlobalObject*> global)
+ {
+ return MaybeNativeObject(getOrCreateObject(cx, global, ASYNC_ITERATOR_PROTO,
+ initAsyncGenerators));
+ }
+
+ static NativeObject*
+ getOrCreateAsyncFromSyncIteratorPrototype(JSContext* cx, Handle<GlobalObject*> global) {
+ return MaybeNativeObject(getOrCreateObject(cx, global, ASYNC_FROM_SYNC_ITERATOR_PROTO,
+ initAsyncGenerators));
+ }
+
+ static NativeObject*
+ getOrCreateAsyncGenerator(JSContext* cx, Handle<GlobalObject*> global) {
+ return MaybeNativeObject(getOrCreateObject(cx, global, ASYNC_GENERATOR,
+ initAsyncGenerators));
+ }
+
+ static JSObject*
+ getOrCreateAsyncGeneratorFunction(JSContext* cx, Handle<GlobalObject*> global) {
+ return getOrCreateObject(cx, global, ASYNC_GENERATOR_FUNCTION, initAsyncGenerators);
+ }
+
+ static NativeObject*
+ getOrCreateAsyncGeneratorPrototype(JSContext* cx, Handle<GlobalObject*> global) {
+ return MaybeNativeObject(getOrCreateObject(cx, global, ASYNC_GENERATOR_PROTO,
+ initAsyncGenerators));
+ }
+
static JSObject*
getOrCreateMapIteratorPrototype(JSContext* cx, Handle<GlobalObject*> global) {
return getOrCreateObject(cx, global, MAP_ITERATOR_PROTO, initMapIteratorProto);
@@ -767,6 +809,7 @@ 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);
+ static bool initRegExpStringIteratorProto(JSContext* cx, Handle<GlobalObject*> global);
// Implemented in vm/GeneratorObject.cpp.
static bool initLegacyGeneratorProto(JSContext* cx, Handle<GlobalObject*> global);
@@ -774,6 +817,8 @@ class GlobalObject : public NativeObject
static bool initAsyncFunction(JSContext* cx, Handle<GlobalObject*> global);
+ static bool initAsyncGenerators(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);
@@ -977,12 +1022,14 @@ GlobalObject::createArrayFromBuffer<uint8_clamped>() const
}
/*
- * Define ctor.prototype = proto as non-enumerable, non-configurable, and
- * non-writable; define proto.constructor = ctor as non-enumerable but
- * configurable and writable.
+ * Unless otherwise specified, define ctor.prototype = proto as non-enumerable,
+ * non-configurable, and non-writable; and define proto.constructor = ctor as
+ * non-enumerable but configurable and writable.
*/
extern bool
-LinkConstructorAndPrototype(JSContext* cx, JSObject* ctor, JSObject* proto);
+LinkConstructorAndPrototype(JSContext* cx, JSObject* ctor, JSObject* proto,
+ unsigned prototypeAttrs = JSPROP_PERMANENT | JSPROP_READONLY,
+ unsigned constructorAttrs = 0);
/*
* Define properties and/or functions on any object. Either ps or fs, or both,
diff --git a/js/src/vm/Interpreter.cpp b/js/src/vm/Interpreter.cpp
index 030f0f3b6..3cf9b57f6 100644
--- a/js/src/vm/Interpreter.cpp
+++ b/js/src/vm/Interpreter.cpp
@@ -39,6 +39,7 @@
#include "jit/Ion.h"
#include "jit/IonAnalysis.h"
#include "vm/AsyncFunction.h"
+#include "vm/AsyncIteration.h"
#include "vm/Debugger.h"
#include "vm/GeneratorObject.h"
#include "vm/Opcodes.h"
@@ -1939,9 +1940,6 @@ CASE(EnableInterruptsPseudoOpcode)
CASE(JSOP_NOP)
CASE(JSOP_NOP_DESTRUCTURING)
CASE(JSOP_UNUSED126)
-CASE(JSOP_UNUSED192)
-CASE(JSOP_UNUSED209)
-CASE(JSOP_UNUSED210)
CASE(JSOP_UNUSED211)
CASE(JSOP_TRY_DESTRUCTURING_ITERCLOSE)
CASE(JSOP_UNUSED221)
@@ -3585,6 +3583,29 @@ CASE(JSOP_TOASYNC)
}
END_CASE(JSOP_TOASYNC)
+CASE(JSOP_TOASYNCGEN)
+{
+ ReservedRooted<JSFunction*> unwrapped(&rootFunction0,
+ &REGS.sp[-1].toObject().as<JSFunction>());
+ JSObject* wrapped = WrapAsyncGenerator(cx, unwrapped);
+ if (!wrapped)
+ goto error;
+
+ REGS.sp[-1].setObject(*wrapped);
+}
+END_CASE(JSOP_TOASYNCGEN)
+
+CASE(JSOP_TOASYNCITER)
+{
+ ReservedRooted<JSObject*> iter(&rootObject1, &REGS.sp[-1].toObject());
+ JSObject* asyncIter = CreateAsyncFromSyncIterator(cx, iter);
+ if (!asyncIter)
+ goto error;
+
+ REGS.sp[-1].setObject(*asyncIter);
+}
+END_CASE(JSOP_TOASYNCITER)
+
CASE(JSOP_SETFUNNAME)
{
MOZ_ASSERT(REGS.stackDepth() >= 2);
@@ -3994,6 +4015,7 @@ CASE(JSOP_INITIALYIELD)
}
CASE(JSOP_YIELD)
+CASE(JSOP_AWAIT)
{
MOZ_ASSERT(!cx->isExceptionPending());
MOZ_ASSERT(REGS.fp()->isFunctionFrame());
@@ -5126,6 +5148,10 @@ js::ThrowCheckIsObject(JSContext* cx, CheckIsObjectKind kind)
case CheckIsObjectKind::GetIterator:
JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr, JSMSG_GET_ITER_RETURNED_PRIMITIVE);
break;
+ case CheckIsObjectKind::GetAsyncIterator:
+ JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr,
+ JSMSG_GET_ASYNC_ITER_RETURNED_PRIMITIVE);
+ break;
default:
MOZ_CRASH("Unknown kind");
}
diff --git a/js/src/vm/Interpreter.h b/js/src/vm/Interpreter.h
index 9fefd75cc..5e7087f7f 100644
--- a/js/src/vm/Interpreter.h
+++ b/js/src/vm/Interpreter.h
@@ -561,7 +561,8 @@ enum class CheckIsObjectKind : uint8_t {
IteratorNext,
IteratorReturn,
IteratorThrow,
- GetIterator
+ GetIterator,
+ GetAsyncIterator
};
bool
diff --git a/js/src/vm/NativeObject-inl.h b/js/src/vm/NativeObject-inl.h
index e55e3db04..030d92c12 100644
--- a/js/src/vm/NativeObject-inl.h
+++ b/js/src/vm/NativeObject-inl.h
@@ -158,11 +158,11 @@ NativeObject::extendDenseElements(ExclusiveContext* cx,
MOZ_ASSERT(!denseElementsAreFrozen());
/*
- * Don't grow elements for non-extensible objects or watched objects. Dense
- * elements can be added/written with no extensible or watchpoint checks as
- * long as there is capacity for them.
+ * Don't grow elements for non-extensible objects. Dense elements can be
+ * added/written with no extensible checks as long as there is capacity
+ * for them.
*/
- if (!nonProxyIsExtensible() || watched()) {
+ if (!nonProxyIsExtensible()) {
MOZ_ASSERT(getDenseCapacity() == 0);
return DenseElementResult::Incomplete;
}
diff --git a/js/src/vm/NativeObject.cpp b/js/src/vm/NativeObject.cpp
index da0f59fe2..d801fad06 100644
--- a/js/src/vm/NativeObject.cpp
+++ b/js/src/vm/NativeObject.cpp
@@ -9,8 +9,6 @@
#include "mozilla/ArrayUtils.h"
#include "mozilla/Casting.h"
-#include "jswatchpoint.h"
-
#include "gc/Marking.h"
#include "js/Value.h"
#include "vm/Debugger.h"
@@ -602,7 +600,7 @@ NativeObject::maybeDensifySparseElements(js::ExclusiveContext* cx, HandleNativeO
return DenseElementResult::Incomplete;
/* Watch for conditions under which an object's elements cannot be dense. */
- if (!obj->nonProxyIsExtensible() || obj->watched())
+ if (!obj->nonProxyIsExtensible())
return DenseElementResult::Incomplete;
/*
@@ -2410,17 +2408,9 @@ SetExistingProperty(JSContext* cx, HandleNativeObject obj, HandleId id, HandleVa
}
bool
-js::NativeSetProperty(JSContext* cx, HandleNativeObject obj, HandleId id, HandleValue value,
+js::NativeSetProperty(JSContext* cx, HandleNativeObject obj, HandleId id, HandleValue v,
HandleValue receiver, QualifiedBool qualified, ObjectOpResult& result)
{
- // Fire watchpoints, if any.
- RootedValue v(cx, value);
- if (MOZ_UNLIKELY(obj->watched())) {
- WatchpointMap* wpmap = cx->compartment()->watchpointMap;
- if (wpmap && !wpmap->triggerWatchpoint(cx, obj, id, &v))
- return false;
- }
-
// Step numbers below reference ES6 rev 27 9.1.9, the [[Set]] internal
// method for ordinary objects. We substitute our own names for these names
// used in the spec: O -> pobj, P -> id, ownDesc -> shape.
diff --git a/js/src/vm/ObjectGroup.cpp b/js/src/vm/ObjectGroup.cpp
index ec0a7aec1..91070b3f6 100644
--- a/js/src/vm/ObjectGroup.cpp
+++ b/js/src/vm/ObjectGroup.cpp
@@ -184,7 +184,7 @@ ObjectGroup::useSingletonForNewObject(JSContext* cx, JSScript* script, jsbytecod
* Sub2 lets us continue to distinguish the two subclasses and any extra
* properties added to those prototype objects.
*/
- if (script->isGenerator())
+ if (script->isStarGenerator() || script->isLegacyGenerator() || script->isAsync())
return false;
if (JSOp(*pc) != JSOP_NEW)
return false;
diff --git a/js/src/vm/Opcodes.h b/js/src/vm/Opcodes.h
index 3c4d61a67..e13cd6221 100644
--- a/js/src/vm/Opcodes.h
+++ b/js/src/vm/Opcodes.h
@@ -1952,7 +1952,15 @@
* Stack: this => this
*/ \
macro(JSOP_CHECKTHISREINIT,191,"checkthisreinit",NULL,1, 1, 1, JOF_BYTE) \
- macro(JSOP_UNUSED192, 192,"unused192", NULL, 1, 0, 0, JOF_BYTE) \
+ /*
+ * Pops the top of stack value as 'unwrapped', converts it to async
+ * generator 'wrapped', and pushes 'wrapped' back on the stack.
+ * Category: Statements
+ * Type: Generator
+ * Operands:
+ * Stack: unwrapped => wrapped
+ */ \
+ macro(JSOP_TOASYNCGEN, 192, "toasyncgen", NULL, 1, 1, 1, JOF_BYTE) \
\
/*
* Pops the top two values on the stack as 'propval' and 'obj', pushes
@@ -2055,7 +2063,7 @@
* interpretation.
* Category: Statements
* Type: Generator
- * Operands: uint24_t yieldIndex
+ * Operands: uint24_t yieldAndAwaitIndex
* Stack: generator =>
*/ \
macro(JSOP_INITIALYIELD, 202,"initialyield", NULL, 4, 1, 1, JOF_UINT24) \
@@ -2064,7 +2072,7 @@
* returns 'rval1'. Pushes sent value from 'send()' onto the stack.
* Category: Statements
* Type: Generator
- * Operands: uint24_t yieldIndex
+ * Operands: uint24_t yieldAndAwaitIndex
* Stack: rval1, gen => rval2
*/ \
macro(JSOP_YIELD, 203,"yield", NULL, 4, 2, 1, JOF_UINT24) \
@@ -2119,8 +2127,24 @@
* Stack: =>
*/ \
macro(JSOP_DEBUGAFTERYIELD, 208, "debugafteryield", NULL, 1, 0, 0, JOF_BYTE) \
- macro(JSOP_UNUSED209, 209, "unused209", NULL, 1, 0, 0, JOF_BYTE) \
- macro(JSOP_UNUSED210, 210, "unused210", NULL, 1, 0, 0, JOF_BYTE) \
+ /*
+ * Pops the generator and the return value 'promise', stops interpretation
+ * and returns 'promise'. Pushes resolved value onto the stack.
+ * Category: Statements
+ * Type: Generator
+ * Operands: uint24_t yieldAndAwaitIndex
+ * Stack: promise, gen => resolved
+ */ \
+ macro(JSOP_AWAIT, 209, "await", NULL, 4, 2, 1, JOF_UINT24) \
+ /*
+ * Pops the iterator from the top of the stack, and create async iterator
+ * from it and push the async iterator back onto the stack.
+ * Category: Statements
+ * Type: Generator
+ * Operands:
+ * Stack: iter => asynciter
+ */ \
+ macro(JSOP_TOASYNCITER, 210, "toasynciter", NULL, 1, 1, 1, JOF_BYTE) \
macro(JSOP_UNUSED211, 211, "unused211", NULL, 1, 0, 0, JOF_BYTE) \
/*
* Initializes generator frame, creates a generator and pushes it on the
diff --git a/js/src/vm/Probes-inl.h b/js/src/vm/Probes-inl.h
index 347f842b8..822a8ac59 100644
--- a/js/src/vm/Probes-inl.h
+++ b/js/src/vm/Probes-inl.h
@@ -41,7 +41,10 @@ probes::EnterScript(JSContext* cx, JSScript* script, JSFunction* maybeFun,
if (rt->spsProfiler.enabled()) {
if (!rt->spsProfiler.enter(cx, script, maybeFun))
return false;
- MOZ_ASSERT_IF(!fp->script()->isGenerator(), !fp->hasPushedSPSFrame());
+ MOZ_ASSERT_IF(!fp->script()->isStarGenerator() &&
+ !fp->script()->isLegacyGenerator() &&
+ !fp->script()->isAsync(),
+ !fp->hasPushedSPSFrame());
fp->setPushedSPSFrame();
}
diff --git a/js/src/vm/RegExpObject.cpp b/js/src/vm/RegExpObject.cpp
index ef97ed816..cd0b54c9d 100644
--- a/js/src/vm/RegExpObject.cpp
+++ b/js/src/vm/RegExpObject.cpp
@@ -49,6 +49,7 @@ JS_STATIC_ASSERT(GlobalFlag == JSREG_GLOB);
JS_STATIC_ASSERT(MultilineFlag == JSREG_MULTILINE);
JS_STATIC_ASSERT(StickyFlag == JSREG_STICKY);
JS_STATIC_ASSERT(UnicodeFlag == JSREG_UNICODE);
+JS_STATIC_ASSERT(DotAllFlag == JSREG_DOTALL);
RegExpObject*
js::RegExpAlloc(ExclusiveContext* cx, HandleObject proto /* = nullptr */)
@@ -267,7 +268,7 @@ RegExpObject::create(ExclusiveContext* cx, HandleAtom source, RegExpFlag flags,
tokenStream = dummyTokenStream.ptr();
}
- if (!irregexp::ParsePatternSyntax(*tokenStream, alloc, source, flags & UnicodeFlag))
+ if (!irregexp::ParsePatternSyntax(*tokenStream, alloc, source, flags & UnicodeFlag, flags & DotAllFlag))
return nullptr;
Rooted<RegExpObject*> regexp(cx, RegExpAlloc(cx));
@@ -1017,7 +1018,7 @@ RegExpShared::compile(JSContext* cx, HandleAtom pattern, HandleLinearString inpu
irregexp::RegExpCompileData data;
if (!irregexp::ParsePattern(dummyTokenStream, cx->tempLifoAlloc(), pattern,
multiline(), mode == MatchOnly, unicode(), ignoreCase(),
- global(), sticky(), &data))
+ global(), sticky(), dotall(), &data))
{
return false;
}
diff --git a/js/src/vm/RegExpObject.h b/js/src/vm/RegExpObject.h
index f1ea101ed..95c64fa67 100644
--- a/js/src/vm/RegExpObject.h
+++ b/js/src/vm/RegExpObject.h
@@ -53,16 +53,18 @@ enum RegExpFlag
MultilineFlag = 0x04,
StickyFlag = 0x08,
UnicodeFlag = 0x10,
+ DotAllFlag = 0x20,
NoFlags = 0x00,
- AllFlags = 0x1f
+ AllFlags = 0x3f
};
static_assert(IgnoreCaseFlag == REGEXP_IGNORECASE_FLAG &&
GlobalFlag == REGEXP_GLOBAL_FLAG &&
MultilineFlag == REGEXP_MULTILINE_FLAG &&
StickyFlag == REGEXP_STICKY_FLAG &&
- UnicodeFlag == REGEXP_UNICODE_FLAG,
+ UnicodeFlag == REGEXP_UNICODE_FLAG &&
+ DotAllFlag == REGEXP_DOTALL_FLAG,
"Flag values should be in sync with self-hosted JS");
enum RegExpRunStatus
@@ -193,6 +195,7 @@ class RegExpShared
bool multiline() const { return flags & MultilineFlag; }
bool sticky() const { return flags & StickyFlag; }
bool unicode() const { return flags & UnicodeFlag; }
+ bool dotall() const { return flags & DotAllFlag; }
bool isCompiled(CompilationMode mode, bool latin1,
ForceByteCodeEnum force = DontForceByteCode) const {
@@ -480,6 +483,7 @@ class RegExpObject : public NativeObject
bool multiline() const { return getFlags() & MultilineFlag; }
bool sticky() const { return getFlags() & StickyFlag; }
bool unicode() const { return getFlags() & UnicodeFlag; }
+ bool dotall() const { return getFlags() & DotAllFlag; }
static bool isOriginalFlagGetter(JSNative native, RegExpFlag* mask);
diff --git a/js/src/vm/Runtime.cpp b/js/src/vm/Runtime.cpp
index 5fc8e0e17..284a4f3d7 100644
--- a/js/src/vm/Runtime.cpp
+++ b/js/src/vm/Runtime.cpp
@@ -34,7 +34,6 @@
#include "jsnativestack.h"
#include "jsobj.h"
#include "jsscript.h"
-#include "jswatchpoint.h"
#include "jswin.h"
#include "jswrapper.h"
diff --git a/js/src/vm/SelfHosting.cpp b/js/src/vm/SelfHosting.cpp
index 792a00490..2216bf91e 100644
--- a/js/src/vm/SelfHosting.cpp
+++ b/js/src/vm/SelfHosting.cpp
@@ -27,6 +27,7 @@
#include "builtin/MapObject.h"
#include "builtin/ModuleObject.h"
#include "builtin/Object.h"
+#include "builtin/Promise.h"
#include "builtin/Reflect.h"
#include "builtin/SelfHostingDefines.h"
#include "builtin/SIMD.h"
@@ -857,33 +858,20 @@ intrinsic_NewStringIterator(JSContext* cx, unsigned argc, Value* vp)
}
static bool
-intrinsic_NewListIterator(JSContext* cx, unsigned argc, Value* vp)
+intrinsic_NewRegExpStringIterator(JSContext* cx, unsigned argc, Value* vp)
{
CallArgs args = CallArgsFromVp(argc, vp);
MOZ_ASSERT(args.length() == 0);
- RootedObject proto(cx, GlobalObject::getOrCreateIteratorPrototype(cx, cx->global()));
+ RootedObject proto(cx, GlobalObject::getOrCreateRegExpStringIteratorPrototype(cx, cx->global()));
if (!proto)
return false;
- RootedObject iterator(cx);
- iterator = NewObjectWithGivenProto(cx, &ListIteratorObject::class_, proto);
- if (!iterator)
+ JSObject* obj = NewObjectWithGivenProto(cx, &RegExpStringIteratorObject::class_, proto);
+ if (!obj)
return false;
- args.rval().setObject(*iterator);
- return true;
-}
-
-static bool
-intrinsic_ActiveFunction(JSContext* cx, unsigned argc, Value* vp)
-{
- CallArgs args = CallArgsFromVp(argc, vp);
- MOZ_ASSERT(args.length() == 0);
-
- ScriptFrameIter iter(cx);
- MOZ_ASSERT(iter.isFunctionFrame());
- args.rval().setObject(*iter.callee(cx));
+ args.rval().setObject(*obj);
return true;
}
@@ -2133,6 +2121,120 @@ intrinsic_ModuleNamespaceExports(JSContext* cx, unsigned argc, Value* vp)
return true;
}
+static bool
+intrinsic_PromiseResolve(JSContext* cx, unsigned argc, Value* vp)
+{
+ CallArgs args = CallArgsFromVp(argc, vp);
+ MOZ_ASSERT(args.length() == 2);
+
+ RootedObject constructor(cx, &args[0].toObject());
+ JSObject* promise = js::PromiseResolve(cx, constructor, args[1]);
+ if (!promise)
+ return false;
+
+ args.rval().setObject(*promise);
+ return true;
+}
+
+static bool
+intrinsic_CreatePendingPromise(JSContext* cx, unsigned argc, Value* vp)
+{
+ CallArgs args = CallArgsFromVp(argc, vp);
+ MOZ_ASSERT(args.length() == 0);
+ RootedObject promise(cx, PromiseObject::createSkippingExecutor(cx));
+ if (!promise)
+ return false;
+ args.rval().setObject(*promise);
+ return true;
+}
+
+static bool
+intrinsic_CreatePromiseResolvedWith(JSContext* cx, unsigned argc, Value* vp)
+{
+ CallArgs args = CallArgsFromVp(argc, vp);
+ MOZ_ASSERT(args.length() == 1);
+ RootedObject promise(cx, PromiseObject::unforgeableResolve(cx, args[0]));
+ if (!promise)
+ return false;
+ args.rval().setObject(*promise);
+ return true;
+}
+
+static bool
+intrinsic_CreatePromiseRejectedWith(JSContext* cx, unsigned argc, Value* vp)
+{
+ CallArgs args = CallArgsFromVp(argc, vp);
+ MOZ_ASSERT(args.length() == 1);
+ RootedObject promise(cx, PromiseObject::unforgeableReject(cx, args[0]));
+ if (!promise)
+ return false;
+ args.rval().setObject(*promise);
+ return true;
+}
+
+static bool
+intrinsic_ResolvePromise(JSContext* cx, unsigned argc, Value* vp)
+{
+ CallArgs args = CallArgsFromVp(argc, vp);
+ MOZ_ASSERT(args.length() == 2);
+ Rooted<PromiseObject*> promise(cx, &args[0].toObject().as<PromiseObject>());
+ if (!PromiseObject::resolve(cx, promise, args[1]))
+ return false;
+ args.rval().setUndefined();
+ return true;
+}
+
+static bool
+intrinsic_RejectPromise(JSContext* cx, unsigned argc, Value* vp)
+{
+ CallArgs args = CallArgsFromVp(argc, vp);
+ MOZ_ASSERT(args.length() == 2);
+ Rooted<PromiseObject*> promise(cx, &args[0].toObject().as<PromiseObject>());
+ if (!PromiseObject::reject(cx, promise, args[1]))
+ return false;
+ args.rval().setUndefined();
+ return true;
+}
+
+static bool
+intrinsic_CallOriginalPromiseThen(JSContext* cx, unsigned argc, Value* vp)
+{
+ CallArgs args = CallArgsFromVp(argc, vp);
+ MOZ_ASSERT(args.length() >= 2);
+
+ RootedObject promise(cx, &args[0].toObject());
+ Value val = args[1];
+ RootedObject onResolvedObj(cx, val.isUndefined() ? nullptr : val.toObjectOrNull());
+ val = args.get(2);
+ RootedObject onRejectedObj(cx, val.isUndefined() ? nullptr : val.toObjectOrNull());
+
+ RootedObject resultPromise(cx, JS::CallOriginalPromiseThen(cx, promise, onResolvedObj,
+ onRejectedObj));
+ if (!resultPromise)
+ return false;
+ args.rval().setObject(*resultPromise);
+ return true;
+}
+
+static bool
+intrinsic_AddPromiseReactions(JSContext* cx, unsigned argc, Value* vp)
+{
+ CallArgs args = CallArgsFromVp(argc, vp);
+ MOZ_ASSERT(args.length() >= 2);
+
+ RootedObject promise(cx, &args[0].toObject());
+ Value val = args[1];
+ RootedObject onResolvedObj(cx, val.isUndefined() ? nullptr : val.toObjectOrNull());
+ val = args.get(2);
+ RootedObject onRejectedObj(cx, val.isUndefined() ? nullptr : val.toObjectOrNull());
+
+ bool result = JS::AddPromiseReactions(cx, promise, onResolvedObj, onRejectedObj);
+ if (!result)
+ return false;
+ args.rval().setUndefined();
+ return true;
+}
+
// The self-hosting global isn't initialized with the normal set of builtins.
// Instead, individual C++-implemented functions that're required by
// self-hosted code are defined as global functions. Accessing these
@@ -2290,11 +2392,6 @@ static const JSFunctionSpec intrinsic_functions[] = {
JS_FN("CallArrayIteratorMethodIfWrapped",
CallNonGenericSelfhostedMethod<Is<ArrayIteratorObject>>, 2,0),
- JS_FN("NewListIterator", intrinsic_NewListIterator, 0,0),
- JS_FN("CallListIteratorMethodIfWrapped",
- CallNonGenericSelfhostedMethod<Is<ListIteratorObject>>, 2,0),
- JS_FN("ActiveFunction", intrinsic_ActiveFunction, 0,0),
-
JS_FN("_SetCanonicalName", intrinsic_SetCanonicalName, 2,0),
JS_INLINABLE_FN("GuardToArrayIterator",
@@ -2309,9 +2406,8 @@ static const JSFunctionSpec intrinsic_functions[] = {
JS_INLINABLE_FN("GuardToStringIterator",
intrinsic_GuardToBuiltin<StringIteratorObject>, 1,0,
IntrinsicGuardToStringIterator),
- JS_INLINABLE_FN("IsListIterator",
- intrinsic_IsInstanceOfBuiltin<ListIteratorObject>, 1,0,
- IntrinsicIsListIterator),
+ JS_FN("GuardToRegExpStringIterator",
+ intrinsic_GuardToBuiltin<RegExpStringIteratorObject>, 1,0),
JS_FN("_CreateMapIterationResultPair", intrinsic_CreateMapIterationResultPair, 0, 0),
JS_INLINABLE_FN("_GetNextMapEntryForIterator", intrinsic_GetNextMapEntryForIterator, 2,0,
@@ -2329,6 +2425,9 @@ static const JSFunctionSpec intrinsic_functions[] = {
JS_FN("NewStringIterator", intrinsic_NewStringIterator, 0,0),
JS_FN("CallStringIteratorMethodIfWrapped",
CallNonGenericSelfhostedMethod<Is<StringIteratorObject>>, 2,0),
+ JS_FN("NewRegExpStringIterator", intrinsic_NewRegExpStringIterator, 0,0),
+ JS_FN("CallRegExpStringIteratorMethodIfWrapped",
+ CallNonGenericSelfhostedMethod<Is<RegExpStringIteratorObject>>, 2,0),
JS_FN("IsStarGeneratorObject",
intrinsic_IsInstanceOfBuiltin<StarGeneratorObject>, 1,0),
@@ -2533,11 +2632,22 @@ static const JSFunctionSpec intrinsic_functions[] = {
intrinsic_InstantiateModuleFunctionDeclarations, 1, 0),
JS_FN("SetModuleState", intrinsic_SetModuleState, 1, 0),
JS_FN("EvaluateModule", intrinsic_EvaluateModule, 1, 0),
- JS_FN("IsModuleNamespace", intrinsic_IsInstanceOfBuiltin<ModuleNamespaceObject>, 1, 0),
JS_FN("NewModuleNamespace", intrinsic_NewModuleNamespace, 2, 0),
JS_FN("AddModuleNamespaceBinding", intrinsic_AddModuleNamespaceBinding, 4, 0),
JS_FN("ModuleNamespaceExports", intrinsic_ModuleNamespaceExports, 1, 0),
+ JS_FN("CreatePendingPromise", intrinsic_CreatePendingPromise, 0, 0),
+ JS_FN("CreatePromiseResolvedWith", intrinsic_CreatePromiseResolvedWith, 1, 0),
+ JS_FN("CreatePromiseRejectedWith", intrinsic_CreatePromiseRejectedWith, 1, 0),
+ JS_FN("ResolvePromise", intrinsic_ResolvePromise, 2, 0),
+ JS_FN("RejectPromise", intrinsic_RejectPromise, 2, 0),
+ JS_FN("AddPromiseReactions", intrinsic_AddPromiseReactions, 3, 0),
+ JS_FN("CallOriginalPromiseThen", intrinsic_CallOriginalPromiseThen, 3, 0),
+
+ JS_FN("IsPromiseObject", intrinsic_IsInstanceOfBuiltin<PromiseObject>, 1, 0),
+ JS_FN("CallPromiseMethodIfWrapped", CallNonGenericSelfhostedMethod<Is<PromiseObject>>, 2, 0),
+ JS_FN("PromiseResolve", intrinsic_PromiseResolve, 2, 0),
+
JS_FS_END
};
@@ -3003,7 +3113,8 @@ JSRuntime::cloneSelfHostedFunctionScript(JSContext* cx, HandlePropertyName name,
return false;
// JSFunction::generatorKind can't handle lazy self-hosted functions, so we make sure there
// aren't any.
- MOZ_ASSERT(!sourceFun->isGenerator());
+ MOZ_ASSERT(!sourceFun->isStarGenerator() && !sourceFun->isLegacyGenerator() &&
+ !sourceFun->isAsync());
MOZ_ASSERT(targetFun->isExtended());
MOZ_ASSERT(targetFun->isInterpretedLazy());
MOZ_ASSERT(targetFun->isSelfHostedBuiltin());
diff --git a/js/src/vm/Shape.h b/js/src/vm/Shape.h
index fd6d843e0..85bc044a5 100644
--- a/js/src/vm/Shape.h
+++ b/js/src/vm/Shape.h
@@ -387,7 +387,7 @@ class BaseShape : public gc::TenuredCell
INDEXED = 0x20,
/* (0x40 is unused) */
HAD_ELEMENTS_ACCESS = 0x80,
- WATCHED = 0x100,
+ /* (0x100 is unused) */
ITERATED_SINGLETON = 0x200,
NEW_GROUP_UNKNOWN = 0x400,
UNCACHEABLE_PROTO = 0x800,
diff --git a/js/src/vm/Stack-inl.h b/js/src/vm/Stack-inl.h
index 11a19d175..2f2b591e5 100644
--- a/js/src/vm/Stack-inl.h
+++ b/js/src/vm/Stack-inl.h
@@ -335,7 +335,7 @@ InterpreterStack::resumeGeneratorCallFrame(JSContext* cx, InterpreterRegs& regs,
HandleFunction callee, HandleValue newTarget,
HandleObject envChain)
{
- MOZ_ASSERT(callee->isGenerator());
+ MOZ_ASSERT(callee->isStarGenerator() || callee->isLegacyGenerator() || callee->isAsync());
RootedScript script(cx, JSFunction::getOrCreateScript(cx, callee));
InterpreterFrame* prev = regs.fp();
jsbytecode* prevpc = regs.pc;
diff --git a/js/src/vm/Stack.cpp b/js/src/vm/Stack.cpp
index c5f2cf5f3..95940eeaf 100644
--- a/js/src/vm/Stack.cpp
+++ b/js/src/vm/Stack.cpp
@@ -270,7 +270,9 @@ InterpreterFrame::epilogue(JSContext* cx, jsbytecode* pc)
UnwindAllEnvironmentsInFrame(cx, ei);
if (isFunctionFrame()) {
- if (!callee().isGenerator() &&
+ if (!callee().isStarGenerator() &&
+ !callee().isLegacyGenerator() &&
+ !callee().isAsync() &&
isConstructing() &&
thisArgument().isObject() &&
returnValue().isPrimitive())
diff --git a/js/src/vm/Stack.h b/js/src/vm/Stack.h
index 23e621344..fe04a00f2 100644
--- a/js/src/vm/Stack.h
+++ b/js/src/vm/Stack.h
@@ -693,7 +693,8 @@ class InterpreterFrame
}
void resumeGeneratorFrame(JSObject* envChain) {
- MOZ_ASSERT(script()->isGenerator());
+ MOZ_ASSERT(script()->isStarGenerator() || script()->isLegacyGenerator() ||
+ script()->isAsync());
MOZ_ASSERT(isFunctionFrame());
flags_ |= HAS_INITIAL_ENV;
envChain_ = envChain;
diff --git a/js/src/vm/Time.cpp b/js/src/vm/Time.cpp
index 87531c148..a9a5b7f0f 100644
--- a/js/src/vm/Time.cpp
+++ b/js/src/vm/Time.cpp
@@ -11,6 +11,10 @@
#include "mozilla/DebugOnly.h"
#include "mozilla/MathAlgorithms.h"
+#ifdef XP_SOLARIS
+#define _REENTRANT 1
+#endif
+
#include <string.h>
#include <time.h>
@@ -30,6 +34,10 @@
#ifdef XP_UNIX
+#ifdef _SVID_GETTOD /* Defined only on Solaris, see Solaris <sys/types.h> */
+extern int gettimeofday(struct timeval* tv);
+#endif
+
#include <sys/time.h>
#endif /* XP_UNIX */
@@ -42,7 +50,11 @@ PRMJ_Now()
{
struct timeval tv;
+#ifdef _SVID_GETTOD /* Defined only on Solaris, see Solaris <sys/types.h> */
+ gettimeofday(&tv);
+#else
gettimeofday(&tv, 0);
+#endif /* _SVID_GETTOD */
return int64_t(tv.tv_sec) * PRMJ_USEC_PER_SEC + int64_t(tv.tv_usec);
}
diff --git a/js/src/vm/TypeInference.cpp b/js/src/vm/TypeInference.cpp
index 7c2c0194e..2b1fa0e3b 100644
--- a/js/src/vm/TypeInference.cpp
+++ b/js/src/vm/TypeInference.cpp
@@ -2670,14 +2670,6 @@ ObjectGroup::updateNewPropertyTypes(ExclusiveContext* cx, JSObject* objArg, jsid
if (shape)
UpdatePropertyType(cx, types, obj, shape, false);
}
-
- if (obj->watched()) {
- /*
- * Mark the property as non-data, to inhibit optimizations on it
- * and avoid bypassing the watchpoint handler.
- */
- types->setNonDataProperty(cx);
- }
}
void
@@ -3084,29 +3076,39 @@ class TypeConstraintClearDefiniteGetterSetter : public TypeConstraint
};
bool
-js::AddClearDefiniteGetterSetterForPrototypeChain(JSContext* cx, ObjectGroup* group, HandleId id)
+js::AddClearDefiniteGetterSetterForPrototypeChain(JSContext* cx,
+ DPAConstraintInfo& constraintInfo,
+ ObjectGroup* group,
+ HandleId id,
+ bool* added)
{
/*
* Ensure that if the properties named here could have a getter, setter or
* a permanent property in any transitive prototype, the definite
* properties get cleared from the group.
*/
+
+ *added = false;
+
RootedObject proto(cx, group->proto().toObjectOrNull());
while (proto) {
ObjectGroup* protoGroup = JSObject::getGroup(cx, proto);
if (!protoGroup) {
- cx->recoverFromOutOfMemory();
return false;
}
if (protoGroup->unknownProperties())
- return false;
+ return true;
HeapTypeSet* protoTypes = protoGroup->getProperty(cx, proto, id);
- if (!protoTypes || protoTypes->nonDataProperty() || protoTypes->nonWritableProperty())
+ if (!protoTypes)
return false;
- if (!protoTypes->addConstraint(cx, cx->typeLifoAlloc().new_<TypeConstraintClearDefiniteGetterSetter>(group)))
+ if (protoTypes->nonDataProperty() || protoTypes->nonWritableProperty())
+ return true;
+ if (!constraintInfo.addProtoConstraint(proto, id))
return false;
proto = proto->staticPrototype();
}
+
+ *added = true;
return true;
}
@@ -3612,6 +3614,43 @@ struct DestroyTypeNewScript
} // namespace
+bool DPAConstraintInfo::finishConstraints(JSContext* cx, ObjectGroup* group) {
+ for (const ProtoConstraint& constraint : protoConstraints_) {
+ ObjectGroup* protoGroup = constraint.proto->group();
+
+ // Note: we rely on the group's type information being unchanged since
+ // AddClearDefiniteGetterSetterForPrototypeChain.
+
+ bool unknownProperties = protoGroup->unknownProperties();
+ MOZ_RELEASE_ASSERT(!unknownProperties);
+
+ HeapTypeSet* protoTypes =
+ protoGroup->getProperty(cx, constraint.proto, constraint.id);
+ MOZ_RELEASE_ASSERT(protoTypes);
+
+ MOZ_ASSERT(!protoTypes->nonDataProperty());
+ MOZ_ASSERT(!protoTypes->nonWritableProperty());
+
+ if (!protoTypes->addConstraint(
+ cx,
+ cx->typeLifoAlloc().new_<TypeConstraintClearDefiniteGetterSetter>(
+ group))) {
+ ReportOutOfMemory(cx);
+ return false;
+ }
+ }
+
+ for (const InliningConstraint& constraint : inliningConstraints_) {
+ if (!AddClearDefiniteFunctionUsesInScript(cx, group, constraint.caller,
+ constraint.callee)) {
+ ReportOutOfMemory(cx);
+ return false;
+ }
+ }
+
+ return true;
+}
+
bool
TypeNewScript::maybeAnalyze(JSContext* cx, ObjectGroup* group, bool* regenerate, bool force)
{
@@ -3715,10 +3754,17 @@ TypeNewScript::maybeAnalyze(JSContext* cx, ObjectGroup* group, bool* regenerate,
return false;
Vector<Initializer> initializerVector(cx);
+
+ DPAConstraintInfo constraintInfo(cx);
RootedPlainObject templateRoot(cx, templateObject());
RootedFunction fun(cx, function());
- if (!jit::AnalyzeNewScriptDefiniteProperties(cx, fun, group, templateRoot, &initializerVector))
+ if (!jit::AnalyzeNewScriptDefiniteProperties(cx,
+ constraintInfo,
+ fun,
+ group,
+ templateRoot,
+ &initializerVector))
return false;
if (!group->newScript())
@@ -3772,6 +3818,14 @@ TypeNewScript::maybeAnalyze(JSContext* cx, ObjectGroup* group, bool* regenerate,
// The definite properties analysis found exactly the properties that
// are held in common by the preliminary objects. No further analysis
// is needed.
+
+ if (!constraintInfo.finishConstraints(cx, group)) {
+ return false;
+ }
+ if (!group->newScript()) {
+ return true;
+ }
+
group->addDefiniteProperties(cx, templateObject()->lastProperty());
destroyNewScript.group = nullptr;
@@ -3793,6 +3847,16 @@ TypeNewScript::maybeAnalyze(JSContext* cx, ObjectGroup* group, bool* regenerate,
if (!initialGroup)
return false;
+ // Add the constraints. Use the initialGroup as group referenced by the
+ // constraints because that's the group that will have the TypeNewScript
+ // associated with it. See the detachNewScript and setNewScript calls below.
+ if (!constraintInfo.finishConstraints(cx, initialGroup)) {
+ return false;
+ }
+ if (!group->newScript()) {
+ return true;
+ }
+
initialGroup->addDefiniteProperties(cx, templateObject()->lastProperty());
group->addDefiniteProperties(cx, prefixShape);
diff --git a/js/src/vm/TypeInference.h b/js/src/vm/TypeInference.h
index 94ce7e871..fd021fc96 100644
--- a/js/src/vm/TypeInference.h
+++ b/js/src/vm/TypeInference.h
@@ -789,8 +789,65 @@ class TemporaryTypeSet : public TypeSet
TypedArraySharedness* sharedness);
};
+// Stack class to record information about constraints that need to be added
+// after finishing the Definite Properties Analysis. When the analysis succeeds,
+// the |finishConstraints| method must be called to add the constraints to the
+// TypeSets.
+//
+// There are two constraint types managed here:
+//
+// 1. Proto constraints for HeapTypeSets, to guard against things like getters
+// and setters on the proto chain.
+//
+// 2. Inlining constraints for StackTypeSets, to invalidate when additional
+// functions could be called at call sites where we inlined a function.
+//
+// This class uses bare GC-thing pointers because GC is suppressed when the
+// analysis runs.
+class MOZ_RAII DPAConstraintInfo {
+ struct ProtoConstraint {
+ JSObject* proto;
+ jsid id;
+ ProtoConstraint(JSObject* proto, jsid id) : proto(proto), id(id) {}
+ };
+ struct InliningConstraint {
+ JSScript* caller;
+ JSScript* callee;
+ InliningConstraint(JSScript* caller, JSScript* callee)
+ : caller(caller), callee(callee) {}
+ };
+
+ JS::AutoCheckCannotGC nogc_;
+ Vector<ProtoConstraint, 8> protoConstraints_;
+ Vector<InliningConstraint, 4> inliningConstraints_;
+
+public:
+ explicit DPAConstraintInfo(JSContext* cx)
+ : nogc_(cx)
+ , protoConstraints_(cx)
+ , inliningConstraints_(cx)
+ {
+ }
+
+ DPAConstraintInfo(const DPAConstraintInfo&) = delete;
+ void operator=(const DPAConstraintInfo&) = delete;
+
+ MOZ_MUST_USE bool addProtoConstraint(JSObject* proto, jsid id) {
+ return protoConstraints_.emplaceBack(proto, id);
+ }
+ MOZ_MUST_USE bool addInliningConstraint(JSScript* caller, JSScript* callee) {
+ return inliningConstraints_.emplaceBack(caller, callee);
+ }
+
+ MOZ_MUST_USE bool finishConstraints(JSContext* cx, ObjectGroup* group);
+};
+
bool
-AddClearDefiniteGetterSetterForPrototypeChain(JSContext* cx, ObjectGroup* group, HandleId id);
+AddClearDefiniteGetterSetterForPrototypeChain(JSContext* cx,
+ DPAConstraintInfo& constraintInfo,
+ ObjectGroup* group,
+ HandleId id,
+ bool* added);
bool
AddClearDefiniteFunctionUsesInScript(JSContext* cx, ObjectGroup* group,