зеркало из https://github.com/mozilla/gecko-dev.git
merge mozilla-inbound to mozilla-central. r=merge a=merge
This commit is contained in:
Коммит
9c98389a1c
|
@ -443,9 +443,9 @@ public:
|
|||
mPrincipalInfo(aPrincipalInfo),
|
||||
mOpenMode(aOpenMode),
|
||||
mWriteParams(aWriteParams),
|
||||
mOperationMayProceed(true),
|
||||
mState(eInitial),
|
||||
mResult(JS::AsmJSCache_InternalError),
|
||||
mDeleteReceived(false),
|
||||
mActorDestroyed(false),
|
||||
mOpened(false)
|
||||
{
|
||||
|
@ -486,6 +486,22 @@ private:
|
|||
MOZ_ASSERT(!IsOnOwningThread());
|
||||
}
|
||||
|
||||
bool
|
||||
IsActorDestroyed() const
|
||||
{
|
||||
AssertIsOnOwningThread();
|
||||
|
||||
return mActorDestroyed;
|
||||
}
|
||||
|
||||
// May be called on any thread, but you should call IsActorDestroyed() if
|
||||
// you know you're on the background thread because it is slightly faster.
|
||||
bool
|
||||
OperationMayProceed() const
|
||||
{
|
||||
return mOperationMayProceed;
|
||||
}
|
||||
|
||||
// This method is called on the owning thread when the JS engine is finished
|
||||
// reading/writing the cache entry.
|
||||
void
|
||||
|
@ -493,12 +509,18 @@ private:
|
|||
{
|
||||
AssertIsOnOwningThread();
|
||||
MOZ_ASSERT(mState == eOpened);
|
||||
MOZ_ASSERT(mResult == JS::AsmJSCache_Success);
|
||||
|
||||
mState = eFinished;
|
||||
|
||||
MOZ_ASSERT(mOpened);
|
||||
mOpened = false;
|
||||
|
||||
FinishOnOwningThread();
|
||||
|
||||
if (!mActorDestroyed) {
|
||||
Unused << Send__delete__(this, mResult);
|
||||
}
|
||||
}
|
||||
|
||||
// This method is called upon any failure that prevents the eventual opening
|
||||
|
@ -508,6 +530,7 @@ private:
|
|||
{
|
||||
AssertIsOnOwningThread();
|
||||
MOZ_ASSERT(mState != eFinished);
|
||||
MOZ_ASSERT(mResult != JS::AsmJSCache_Success);
|
||||
|
||||
mState = eFinished;
|
||||
|
||||
|
@ -515,7 +538,7 @@ private:
|
|||
|
||||
FinishOnOwningThread();
|
||||
|
||||
if (!mDeleteReceived && !mActorDestroyed) {
|
||||
if (!mActorDestroyed) {
|
||||
Unused << Send__delete__(this, mResult);
|
||||
}
|
||||
}
|
||||
|
@ -557,16 +580,18 @@ private:
|
|||
{
|
||||
AssertIsOnOwningThread();
|
||||
|
||||
// If shutdown just started, the QuotaManager may have been deleted.
|
||||
QuotaManager* qm = QuotaManager::Get();
|
||||
if (!qm) {
|
||||
FailOnNonOwningThread();
|
||||
if (NS_WARN_IF(Client::IsShuttingDownOnBackgroundThread()) ||
|
||||
IsActorDestroyed()) {
|
||||
Fail();
|
||||
return;
|
||||
}
|
||||
|
||||
QuotaManager* qm = QuotaManager::Get();
|
||||
MOZ_ASSERT(qm);
|
||||
|
||||
nsresult rv = qm->IOThread()->Dispatch(this, NS_DISPATCH_NORMAL);
|
||||
if (NS_FAILED(rv)) {
|
||||
FailOnNonOwningThread();
|
||||
Fail();
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
@ -579,62 +604,96 @@ private:
|
|||
DirectoryLockFailed() override;
|
||||
|
||||
// IPDL methods.
|
||||
mozilla::ipc::IPCResult
|
||||
Recv__delete__(const JS::AsmJSCacheResult& aResult) override
|
||||
{
|
||||
AssertIsOnOwningThread();
|
||||
MOZ_ASSERT(mState != eFinished);
|
||||
MOZ_ASSERT(!mDeleteReceived);
|
||||
|
||||
mDeleteReceived = true;
|
||||
|
||||
if (mOpened) {
|
||||
Close();
|
||||
} else {
|
||||
Fail();
|
||||
}
|
||||
|
||||
MOZ_ASSERT(mState == eFinished);
|
||||
|
||||
return IPC_OK();
|
||||
}
|
||||
|
||||
void
|
||||
ActorDestroy(ActorDestroyReason why) override
|
||||
{
|
||||
AssertIsOnOwningThread();
|
||||
MOZ_ASSERT(!mActorDestroyed);
|
||||
MOZ_ASSERT(mOperationMayProceed);
|
||||
|
||||
mActorDestroyed = true;
|
||||
mOperationMayProceed = false;
|
||||
|
||||
// Assume ActorDestroy can happen at any time, so probe the current state to
|
||||
// determine what needs to happen.
|
||||
|
||||
if (mState == eFinished) {
|
||||
return;
|
||||
}
|
||||
// Assume ActorDestroy can happen at any time, so we can't probe the
|
||||
// current state since mState can be modified on any thread (only one
|
||||
// thread at a time based on the state machine).
|
||||
// However we can use mOpened which is only touched on the owning thread.
|
||||
// If mOpened is true, we can also modify mState since we are guaranteed
|
||||
// that there are no pending runnables which would probe mState to decide
|
||||
// what code needs to run (there shouldn't be any running runnables on
|
||||
// other threads either).
|
||||
|
||||
if (mOpened) {
|
||||
Close();
|
||||
} else {
|
||||
Fail();
|
||||
|
||||
MOZ_ASSERT(mState == eFinished);
|
||||
}
|
||||
|
||||
MOZ_ASSERT(mState == eFinished);
|
||||
// We don't have to call Fail() if mOpened is not true since it means that
|
||||
// either nothing has been initialized yet, so nothing to cleanup or there
|
||||
// are pending runnables that will detect that the actor has been destroyed
|
||||
// and call Fail().
|
||||
}
|
||||
|
||||
mozilla::ipc::IPCResult
|
||||
RecvSelectCacheFileToRead(const uint32_t& aModuleIndex) override
|
||||
RecvSelectCacheFileToRead(const OpenMetadataForReadResponse& aResponse)
|
||||
override
|
||||
{
|
||||
AssertIsOnOwningThread();
|
||||
MOZ_ASSERT(mState == eWaitingToOpenCacheFileForRead);
|
||||
MOZ_ASSERT(mOpenMode == eOpenForRead);
|
||||
MOZ_ASSERT(!mOpened);
|
||||
|
||||
// A cache entry has been selected to open.
|
||||
if (NS_WARN_IF(Client::IsShuttingDownOnBackgroundThread())) {
|
||||
Fail();
|
||||
return IPC_OK();
|
||||
}
|
||||
|
||||
mModuleIndex = aModuleIndex;
|
||||
mState = eReadyToOpenCacheFileForRead;
|
||||
DispatchToIOThread();
|
||||
switch (aResponse.type()) {
|
||||
case OpenMetadataForReadResponse::TAsmJSCacheResult: {
|
||||
MOZ_ASSERT(aResponse.get_AsmJSCacheResult() != JS::AsmJSCache_Success);
|
||||
|
||||
mResult = aResponse.get_AsmJSCacheResult();
|
||||
|
||||
// This ParentRunnable can only be held alive by the IPDL. Fail()
|
||||
// clears that last reference. So we need to add a self reference here.
|
||||
RefPtr<ParentRunnable> kungFuDeathGrip = this;
|
||||
|
||||
Fail();
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
case OpenMetadataForReadResponse::Tuint32_t:
|
||||
// A cache entry has been selected to open.
|
||||
mModuleIndex = aResponse.get_uint32_t();
|
||||
|
||||
mState = eReadyToOpenCacheFileForRead;
|
||||
|
||||
DispatchToIOThread();
|
||||
|
||||
break;
|
||||
|
||||
default:
|
||||
MOZ_CRASH("Should never get here!");
|
||||
}
|
||||
|
||||
return IPC_OK();
|
||||
}
|
||||
|
||||
mozilla::ipc::IPCResult
|
||||
RecvClose() override
|
||||
{
|
||||
AssertIsOnOwningThread();
|
||||
MOZ_ASSERT(mState == eOpened);
|
||||
|
||||
// This ParentRunnable can only be held alive by the IPDL. Close() clears
|
||||
// that last reference. So we need to add a self reference here.
|
||||
RefPtr<ParentRunnable> kungFuDeathGrip = this;
|
||||
|
||||
Close();
|
||||
|
||||
MOZ_ASSERT(mState == eFinished);
|
||||
|
||||
return IPC_OK();
|
||||
}
|
||||
|
@ -655,6 +714,8 @@ private:
|
|||
nsCOMPtr<nsIFile> mMetadataFile;
|
||||
Metadata mMetadata;
|
||||
|
||||
Atomic<bool> mOperationMayProceed;
|
||||
|
||||
// State initialized during eWaitingToOpenCacheFileForRead
|
||||
unsigned mModuleIndex;
|
||||
|
||||
|
@ -675,7 +736,6 @@ private:
|
|||
State mState;
|
||||
JS::AsmJSCacheResult mResult;
|
||||
|
||||
bool mDeleteReceived;
|
||||
bool mActorDestroyed;
|
||||
bool mOpened;
|
||||
};
|
||||
|
@ -916,6 +976,12 @@ ParentRunnable::Run()
|
|||
case eInitial: {
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
|
||||
if (NS_WARN_IF(Client::IsShuttingDownOnNonBackgroundThread()) ||
|
||||
!OperationMayProceed()) {
|
||||
FailOnNonOwningThread();
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
rv = InitOnMainThread();
|
||||
if (NS_FAILED(rv)) {
|
||||
FailOnNonOwningThread();
|
||||
|
@ -931,7 +997,8 @@ ParentRunnable::Run()
|
|||
case eWaitingToFinishInit: {
|
||||
AssertIsOnOwningThread();
|
||||
|
||||
if (QuotaManager::IsShuttingDown()) {
|
||||
if (NS_WARN_IF(Client::IsShuttingDownOnBackgroundThread()) ||
|
||||
IsActorDestroyed()) {
|
||||
Fail();
|
||||
return NS_OK;
|
||||
}
|
||||
|
@ -950,6 +1017,12 @@ ParentRunnable::Run()
|
|||
case eWaitingToOpenDirectory: {
|
||||
AssertIsOnOwningThread();
|
||||
|
||||
if (NS_WARN_IF(Client::IsShuttingDownOnBackgroundThread()) ||
|
||||
IsActorDestroyed()) {
|
||||
Fail();
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
if (NS_WARN_IF(!QuotaManager::Get())) {
|
||||
Fail();
|
||||
return NS_OK;
|
||||
|
@ -962,6 +1035,12 @@ ParentRunnable::Run()
|
|||
case eReadyToReadMetadata: {
|
||||
AssertIsOnIOThread();
|
||||
|
||||
if (NS_WARN_IF(Client::IsShuttingDownOnNonBackgroundThread()) ||
|
||||
!OperationMayProceed()) {
|
||||
FailOnNonOwningThread();
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
rv = ReadMetadata();
|
||||
if (NS_FAILED(rv)) {
|
||||
FailOnNonOwningThread();
|
||||
|
@ -990,6 +1069,12 @@ ParentRunnable::Run()
|
|||
AssertIsOnOwningThread();
|
||||
MOZ_ASSERT(mOpenMode == eOpenForRead);
|
||||
|
||||
if (NS_WARN_IF(Client::IsShuttingDownOnBackgroundThread()) ||
|
||||
IsActorDestroyed()) {
|
||||
Fail();
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
mState = eWaitingToOpenCacheFileForRead;
|
||||
|
||||
// Metadata is now open.
|
||||
|
@ -1005,6 +1090,12 @@ ParentRunnable::Run()
|
|||
AssertIsOnIOThread();
|
||||
MOZ_ASSERT(mOpenMode == eOpenForRead);
|
||||
|
||||
if (NS_WARN_IF(Client::IsShuttingDownOnNonBackgroundThread()) ||
|
||||
!OperationMayProceed()) {
|
||||
FailOnNonOwningThread();
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
rv = OpenCacheFileForRead();
|
||||
if (NS_FAILED(rv)) {
|
||||
FailOnNonOwningThread();
|
||||
|
@ -1019,11 +1110,13 @@ ParentRunnable::Run()
|
|||
case eSendingCacheFile: {
|
||||
AssertIsOnOwningThread();
|
||||
|
||||
mState = eOpened;
|
||||
if (NS_WARN_IF(Client::IsShuttingDownOnBackgroundThread()) ||
|
||||
IsActorDestroyed()) {
|
||||
Fail();
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
// The entry is now open.
|
||||
MOZ_ASSERT(!mOpened);
|
||||
mOpened = true;
|
||||
mState = eOpened;
|
||||
|
||||
FileDescriptor::PlatformHandleType handle =
|
||||
FileDescriptor::PlatformHandleType(PR_FileDesc2NativeHandle(mFileDesc));
|
||||
|
@ -1032,6 +1125,12 @@ ParentRunnable::Run()
|
|||
return NS_OK;
|
||||
}
|
||||
|
||||
// The entry is now open.
|
||||
MOZ_ASSERT(!mOpened);
|
||||
mOpened = true;
|
||||
|
||||
mResult = JS::AsmJSCache_Success;
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
|
@ -1291,15 +1390,16 @@ private:
|
|||
MOZ_ASSERT(mState == eOpening);
|
||||
|
||||
uint32_t moduleIndex;
|
||||
if (!FindHashMatch(aMetadata, mReadParams, &moduleIndex)) {
|
||||
Fail(JS::AsmJSCache_InternalError);
|
||||
Send__delete__(this, JS::AsmJSCache_InternalError);
|
||||
return IPC_OK();
|
||||
bool ok;
|
||||
if (FindHashMatch(aMetadata, mReadParams, &moduleIndex)) {
|
||||
ok = SendSelectCacheFileToRead(moduleIndex);
|
||||
} else {
|
||||
ok = SendSelectCacheFileToRead(JS::AsmJSCache_InternalError);
|
||||
}
|
||||
|
||||
if (!SendSelectCacheFileToRead(moduleIndex)) {
|
||||
if (!ok) {
|
||||
return IPC_FAIL_NO_REASON(this);
|
||||
}
|
||||
|
||||
return IPC_OK();
|
||||
}
|
||||
|
||||
|
@ -1327,9 +1427,20 @@ private:
|
|||
Recv__delete__(const JS::AsmJSCacheResult& aResult) override
|
||||
{
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
MOZ_ASSERT(mState == eOpening);
|
||||
MOZ_ASSERT(mState == eOpening || mState == eFinishing);
|
||||
MOZ_ASSERT_IF(mState == eOpening, aResult != JS::AsmJSCache_Success);
|
||||
MOZ_ASSERT_IF(mState == eFinishing, aResult == JS::AsmJSCache_Success);
|
||||
|
||||
Fail(aResult);
|
||||
if (mState == eOpening) {
|
||||
Fail(aResult);
|
||||
} else {
|
||||
// Match the AddRef in BlockUntilOpen(). The IPDL still holds an
|
||||
// outstanding ref which will keep 'this' alive until ActorDestroy()
|
||||
// is executed.
|
||||
Release();
|
||||
|
||||
mState = eFinished;
|
||||
}
|
||||
return IPC_OK();
|
||||
}
|
||||
|
||||
|
@ -1392,10 +1503,10 @@ private:
|
|||
const OpenMode mOpenMode;
|
||||
enum State {
|
||||
eInitial, // Just created, waiting to be dispatched to the main thread
|
||||
eBackgroundChildPending, // Waiting for the background child to be created
|
||||
eOpening, // Waiting for the parent process to respond
|
||||
eOpened, // Parent process opened the entry and sent it back
|
||||
eClosing, // Waiting to be dispatched to the main thread to Send__delete__
|
||||
eFinishing, // Waiting for the parent process to close
|
||||
eFinished // Terminal state
|
||||
};
|
||||
State mState;
|
||||
|
@ -1455,28 +1566,31 @@ ChildRunnable::Run()
|
|||
|
||||
// Per FileDescriptorHolder::Finish()'s comment, call before
|
||||
// releasing the directory lock (which happens in the parent upon receipt
|
||||
// of the Send__delete__ message).
|
||||
// of the Close message).
|
||||
FileDescriptorHolder::Finish();
|
||||
|
||||
MOZ_ASSERT(mOpened);
|
||||
mOpened = false;
|
||||
|
||||
// Match the AddRef in BlockUntilOpen(). The main thread event loop still
|
||||
// holds an outstanding ref which will keep 'this' alive until returning to
|
||||
// the event loop.
|
||||
Release();
|
||||
if (mActorDestroyed) {
|
||||
// Match the AddRef in BlockUntilOpen(). The main thread event loop
|
||||
// still holds an outstanding ref which will keep 'this' alive until
|
||||
// returning to the event loop.
|
||||
Release();
|
||||
|
||||
if (!mActorDestroyed) {
|
||||
Unused << Send__delete__(this, JS::AsmJSCache_Success);
|
||||
mState = eFinished;
|
||||
} else {
|
||||
Unused << SendClose();
|
||||
|
||||
mState = eFinishing;
|
||||
}
|
||||
|
||||
mState = eFinished;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
case eBackgroundChildPending:
|
||||
case eOpening:
|
||||
case eOpened:
|
||||
case eFinishing:
|
||||
case eFinished: {
|
||||
MOZ_MAKE_COMPILER_ASSUME_IS_UNREACHABLE("Shouldn't Run() in this state");
|
||||
}
|
||||
|
|
|
@ -11,6 +11,12 @@ namespace mozilla {
|
|||
namespace dom {
|
||||
namespace asmjscache {
|
||||
|
||||
union OpenMetadataForReadResponse
|
||||
{
|
||||
AsmJSCacheResult;
|
||||
uint32_t;
|
||||
};
|
||||
|
||||
protocol PAsmJSCacheEntry
|
||||
{
|
||||
manager PBackground;
|
||||
|
@ -21,14 +27,24 @@ protocol PAsmJSCacheEntry
|
|||
child:
|
||||
async OnOpenMetadataForRead(Metadata metadata);
|
||||
parent:
|
||||
async SelectCacheFileToRead(uint32_t moduleIndex);
|
||||
async SelectCacheFileToRead(OpenMetadataForReadResponse response);
|
||||
|
||||
child:
|
||||
// Once the cache file has been opened, the child is notified and sent an
|
||||
// open file descriptor.
|
||||
async OnOpenCacheFile(int64_t fileSize, FileDescriptor fileDesc);
|
||||
|
||||
both:
|
||||
parent:
|
||||
// When the child process is done with the cache entry, the parent process
|
||||
// is notified (via Close).
|
||||
async Close();
|
||||
|
||||
child:
|
||||
// When there's an error during the opening phase, the child process is
|
||||
// notified (via __delete__) and sent an error result.
|
||||
// When the parent process receives the Close message, it closes the cache
|
||||
// entry on the parent side and the child is notified (via __delete__).
|
||||
// The protocol is destroyed in both cases.
|
||||
async __delete__(AsmJSCacheResult result);
|
||||
};
|
||||
|
||||
|
|
|
@ -63,7 +63,6 @@ var ecmaGlobals =
|
|||
"Set",
|
||||
"SharedArrayBuffer",
|
||||
{name: "SIMD", nightly: true},
|
||||
"StopIteration",
|
||||
"String",
|
||||
"Symbol",
|
||||
"SyntaxError",
|
||||
|
|
|
@ -58,7 +58,6 @@ var ecmaGlobals =
|
|||
"Set",
|
||||
"SharedArrayBuffer",
|
||||
{name: "SIMD", nightly: true},
|
||||
"StopIteration",
|
||||
"String",
|
||||
"Symbol",
|
||||
"SyntaxError",
|
||||
|
|
|
@ -58,7 +58,6 @@ var ecmaGlobals =
|
|||
"Set",
|
||||
"SharedArrayBuffer",
|
||||
{name: "SIMD", nightly: true},
|
||||
"StopIteration",
|
||||
"String",
|
||||
"Symbol",
|
||||
"SyntaxError",
|
||||
|
|
|
@ -95,10 +95,6 @@ struct ReturnSuccess
|
|||
{
|
||||
};
|
||||
|
||||
struct ReturnStopIteration
|
||||
{
|
||||
};
|
||||
|
||||
struct ReturnDeadCPOW
|
||||
{
|
||||
};
|
||||
|
@ -116,7 +112,6 @@ struct ReturnObjectOpResult
|
|||
union ReturnStatus
|
||||
{
|
||||
ReturnSuccess;
|
||||
ReturnStopIteration;
|
||||
ReturnDeadCPOW;
|
||||
ReturnException;
|
||||
ReturnObjectOpResult;
|
||||
|
|
|
@ -62,11 +62,6 @@ WrapperAnswer::fail(AutoJSAPI& jsapi, ReturnStatus* rs)
|
|||
if (!jsapi.StealException(&exn))
|
||||
return true;
|
||||
|
||||
if (JS_IsStopIteration(exn)) {
|
||||
*rs = ReturnStatus(ReturnStopIteration());
|
||||
return true;
|
||||
}
|
||||
|
||||
// If this fails, we still don't want to exit. Just return an invalid
|
||||
// exception.
|
||||
(void) toVariant(cx, exn, &rs->get_ReturnException().exn());
|
||||
|
|
|
@ -1076,9 +1076,6 @@ WrapperOwner::ok(JSContext* cx, const ReturnStatus& status)
|
|||
if (status.type() == ReturnStatus::TReturnSuccess)
|
||||
return true;
|
||||
|
||||
if (status.type() == ReturnStatus::TReturnStopIteration)
|
||||
return JS_ThrowStopIteration(cx);
|
||||
|
||||
if (status.type() == ReturnStatus::TReturnDeadCPOW) {
|
||||
JS_ReportErrorASCII(cx, "operation not possible on dead CPOW");
|
||||
return false;
|
||||
|
|
|
@ -1,9 +1,9 @@
|
|||
// |jit-test| need-for-each
|
||||
|
||||
a = b = c = d = 0;
|
||||
this.__defineGetter__("e", function () { throw StopIteration; })
|
||||
this.__defineGetter__("e", function () { throw Math; })
|
||||
try {
|
||||
for each(f in this) {}
|
||||
} catch (exc) {
|
||||
assertEq(exc, StopIteration);
|
||||
assertEq(exc, Math);
|
||||
}
|
||||
|
|
|
@ -1,9 +1,9 @@
|
|||
// |jit-test| need-for-each
|
||||
|
||||
var obj = {a: 0, b: 0, c: 0, d: 0, get e() { throw StopIteration; }};
|
||||
var obj = {a: 0, b: 0, c: 0, d: 0, get e() { throw Math; }};
|
||||
try {
|
||||
for each (x in obj) {}
|
||||
FAIL;
|
||||
} catch (exc) {
|
||||
assertEq(exc, StopIteration);
|
||||
assertEq(exc, Math);
|
||||
}
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
var arr = [StopIteration, StopIteration, StopIteration, StopIteration, {}];
|
||||
var arr = [Math, Math, Math, Math, {}];
|
||||
var obj = {};
|
||||
var x;
|
||||
var result = 'no error';
|
||||
|
|
|
@ -49,11 +49,10 @@ assertThrowsInstanceOf(function() {
|
|||
initialMap.forEach(fn);
|
||||
}, TypeError, "Map.prototype.forEach should raise TypeError if callback is not a function");
|
||||
|
||||
// testing that Map#forEach uses internal next() function and does not stop when
|
||||
// StopIteration exception is thrown
|
||||
// testing that Map#forEach uses internal next() function.
|
||||
|
||||
var m = new Map([["one", 1]]);
|
||||
Object.getPrototypeOf(m[Symbol.iterator]()).next = function () { throw "FAIL"; };
|
||||
assertThrowsInstanceOf(function () {
|
||||
m.forEach(function () { throw StopIteration; });
|
||||
}, StopIteration, "Map.prototype.forEach should use intrinsic next method.");
|
||||
assertThrowsValue(function () {
|
||||
m.forEach(function () { throw Math; });
|
||||
}, Math, "Map.prototype.forEach should use intrinsic next method.");
|
||||
|
|
|
@ -82,7 +82,6 @@
|
|||
#include "vm/SavedStacks.h"
|
||||
#include "vm/SelfHosting.h"
|
||||
#include "vm/Shape.h"
|
||||
#include "vm/StopIterationObject.h"
|
||||
#include "vm/String.h"
|
||||
#include "vm/StringBuffer.h"
|
||||
#include "vm/Symbol.h"
|
||||
|
@ -7122,19 +7121,6 @@ JSErrorNotes::end()
|
|||
return iterator(notes_.end());
|
||||
}
|
||||
|
||||
JS_PUBLIC_API(bool)
|
||||
JS_ThrowStopIteration(JSContext* cx)
|
||||
{
|
||||
AssertHeapIsIdle();
|
||||
return ThrowStopIteration(cx);
|
||||
}
|
||||
|
||||
JS_PUBLIC_API(bool)
|
||||
JS_IsStopIteration(const Value& v)
|
||||
{
|
||||
return v.isObject() && v.toObject().is<StopIterationObject>();
|
||||
}
|
||||
|
||||
extern MOZ_NEVER_INLINE JS_PUBLIC_API(void)
|
||||
JS_AbortIfWrongThread(JSContext* cx)
|
||||
{
|
||||
|
|
|
@ -6200,15 +6200,6 @@ JS_ErrorFromException(JSContext* cx, JS::HandleObject obj);
|
|||
extern JS_PUBLIC_API(JSObject*)
|
||||
ExceptionStackOrNull(JS::HandleObject obj);
|
||||
|
||||
/*
|
||||
* Throws a StopIteration exception on cx.
|
||||
*/
|
||||
extern JS_PUBLIC_API(bool)
|
||||
JS_ThrowStopIteration(JSContext* cx);
|
||||
|
||||
extern JS_PUBLIC_API(bool)
|
||||
JS_IsStopIteration(const JS::Value& v);
|
||||
|
||||
/**
|
||||
* A JS context always has an "owner thread". The owner thread is set when the
|
||||
* context is created (to the current thread) and practically all entry points
|
||||
|
|
|
@ -24,7 +24,6 @@
|
|||
#include "js/RootingAPI.h"
|
||||
#include "proxy/DeadObjectProxy.h"
|
||||
#include "vm/Debugger.h"
|
||||
#include "vm/StopIterationObject.h"
|
||||
#include "vm/WrapperObject.h"
|
||||
|
||||
#include "jsatominlines.h"
|
||||
|
@ -395,17 +394,6 @@ JSCompartment::getNonWrapperObjectForCurrentCompartment(JSContext* cx, MutableHa
|
|||
return true;
|
||||
}
|
||||
|
||||
// Translate StopIteration singleton.
|
||||
if (obj->is<StopIterationObject>()) {
|
||||
// StopIteration isn't a constructor, but it's stored in GlobalObject
|
||||
// as one, out of laziness. Hence the GetBuiltinConstructor call here.
|
||||
RootedObject stopIteration(cx);
|
||||
if (!GetBuiltinConstructor(cx, JSProto_StopIteration, &stopIteration))
|
||||
return false;
|
||||
obj.set(stopIteration);
|
||||
return true;
|
||||
}
|
||||
|
||||
// Invoke the prewrap callback. The prewrap callback is responsible for
|
||||
// doing similar reification as above, but can account for any additional
|
||||
// embedder requirements.
|
||||
|
|
|
@ -31,7 +31,6 @@
|
|||
#include "vm/GlobalObject.h"
|
||||
#include "vm/Interpreter.h"
|
||||
#include "vm/Shape.h"
|
||||
#include "vm/StopIterationObject.h"
|
||||
#include "vm/TypedArrayObject.h"
|
||||
|
||||
#include "jsscriptinlines.h"
|
||||
|
@ -537,8 +536,6 @@ js::GetPropertyKeys(JSContext* cx, HandleObject obj, unsigned flags, AutoIdVecto
|
|||
props);
|
||||
}
|
||||
|
||||
static bool property_iterator_next(JSContext* cx, unsigned argc, Value* vp);
|
||||
|
||||
static inline PropertyIteratorObject*
|
||||
NewPropertyIteratorObject(JSContext* cx, unsigned flags)
|
||||
{
|
||||
|
@ -569,26 +566,7 @@ NewPropertyIteratorObject(JSContext* cx, unsigned flags)
|
|||
return res;
|
||||
}
|
||||
|
||||
Rooted<PropertyIteratorObject*> res(cx, NewBuiltinClassInstance<PropertyIteratorObject>(cx));
|
||||
if (!res)
|
||||
return nullptr;
|
||||
|
||||
if (flags == 0) {
|
||||
// Redefine next as an own property. This ensure that deleting the
|
||||
// next method on the prototype doesn't break cross-global for .. in.
|
||||
// We don't have to do this for JSITER_ENUMERATE because that object always
|
||||
// takes an optimized path.
|
||||
RootedFunction next(cx, NewNativeFunction(cx, property_iterator_next, 0,
|
||||
HandlePropertyName(cx->names().next)));
|
||||
if (!next)
|
||||
return nullptr;
|
||||
|
||||
RootedValue value(cx, ObjectValue(*next));
|
||||
if (!DefineDataProperty(cx, res, cx->names().next, value))
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
return res;
|
||||
return NewBuiltinClassInstance<PropertyIteratorObject>(cx);
|
||||
}
|
||||
|
||||
NativeIterator*
|
||||
|
@ -1055,28 +1033,13 @@ JSCompartment::getOrCreateIterResultTemplateObject(JSContext* cx)
|
|||
return iterResultTemplate_;
|
||||
}
|
||||
|
||||
bool
|
||||
js::ThrowStopIteration(JSContext* cx)
|
||||
{
|
||||
MOZ_ASSERT(!JS_IsExceptionPending(cx));
|
||||
|
||||
// StopIteration isn't a constructor, but it's stored in GlobalObject
|
||||
// as one, out of laziness. Hence the GetBuiltinConstructor call here.
|
||||
RootedObject ctor(cx);
|
||||
if (GetBuiltinConstructor(cx, JSProto_StopIteration, &ctor))
|
||||
cx->setPendingException(ObjectValue(*ctor));
|
||||
return false;
|
||||
}
|
||||
|
||||
/*** Iterator objects ****************************************************************************/
|
||||
|
||||
MOZ_ALWAYS_INLINE bool
|
||||
NativeIteratorNext(JSContext* cx, NativeIterator* ni, MutableHandleValue rval, bool* done)
|
||||
NativeIteratorNext(JSContext* cx, NativeIterator* ni, MutableHandleValue rval)
|
||||
{
|
||||
*done = false;
|
||||
|
||||
if (ni->props_cursor >= ni->props_end) {
|
||||
*done = true;
|
||||
rval.setMagic(JS_NO_ITER_VALUE);
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -1105,36 +1068,6 @@ js::IsPropertyIterator(HandleValue v)
|
|||
return v.isObject() && v.toObject().is<PropertyIteratorObject>();
|
||||
}
|
||||
|
||||
MOZ_ALWAYS_INLINE bool
|
||||
property_iterator_next_impl(JSContext* cx, const CallArgs& args)
|
||||
{
|
||||
MOZ_ASSERT(IsPropertyIterator(args.thisv()));
|
||||
|
||||
RootedObject thisObj(cx, &args.thisv().toObject());
|
||||
|
||||
NativeIterator* ni = thisObj.as<PropertyIteratorObject>()->getNativeIterator();
|
||||
RootedValue value(cx);
|
||||
bool done;
|
||||
if (!NativeIteratorNext(cx, ni, &value, &done))
|
||||
return false;
|
||||
|
||||
// Use old iterator protocol for compatibility reasons.
|
||||
if (done) {
|
||||
ThrowStopIteration(cx);
|
||||
return false;
|
||||
}
|
||||
|
||||
args.rval().set(value);
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool
|
||||
property_iterator_next(JSContext* cx, unsigned argc, Value* vp)
|
||||
{
|
||||
CallArgs args = CallArgsFromVp(argc, vp);
|
||||
return CallNonGenericMethod<IsPropertyIterator, property_iterator_next_impl>(cx, args);
|
||||
}
|
||||
|
||||
size_t
|
||||
PropertyIteratorObject::sizeOfMisc(mozilla::MallocSizeOf mallocSizeOf) const
|
||||
{
|
||||
|
@ -1489,72 +1422,32 @@ bool
|
|||
js::IteratorMore(JSContext* cx, HandleObject iterobj, MutableHandleValue rval)
|
||||
{
|
||||
// Fast path for native iterators.
|
||||
if (iterobj->is<PropertyIteratorObject>()) {
|
||||
if (MOZ_LIKELY(iterobj->is<PropertyIteratorObject>())) {
|
||||
NativeIterator* ni = iterobj->as<PropertyIteratorObject>().getNativeIterator();
|
||||
bool done;
|
||||
if (!NativeIteratorNext(cx, ni, rval, &done))
|
||||
return false;
|
||||
|
||||
if (done)
|
||||
rval.setMagic(JS_NO_ITER_VALUE);
|
||||
return true;
|
||||
return NativeIteratorNext(cx, ni, rval);
|
||||
}
|
||||
|
||||
// We're reentering below and can call anything.
|
||||
if (!CheckRecursionLimit(cx))
|
||||
if (JS_IsDeadWrapper(iterobj)) {
|
||||
JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr, JSMSG_DEAD_OBJECT);
|
||||
return false;
|
||||
|
||||
// Call the iterator object's .next method.
|
||||
if (!GetProperty(cx, iterobj, iterobj, cx->names().next, rval))
|
||||
return false;
|
||||
|
||||
// Call the .next method. Fall through to the error-handling cases in the
|
||||
// unlikely event that either one of the fallible operations performed
|
||||
// during the call process fails.
|
||||
FixedInvokeArgs<0> args(cx);
|
||||
RootedValue iterval(cx, ObjectValue(*iterobj));
|
||||
if (!js::Call(cx, rval, iterval, args, rval)) {
|
||||
// Check for StopIteration.
|
||||
if (!cx->isExceptionPending())
|
||||
return false;
|
||||
RootedValue exception(cx);
|
||||
if (!cx->getPendingException(&exception))
|
||||
return false;
|
||||
if (!JS_IsStopIteration(exception))
|
||||
return false;
|
||||
|
||||
cx->clearPendingException();
|
||||
rval.setMagic(JS_NO_ITER_VALUE);
|
||||
}
|
||||
|
||||
return true;
|
||||
MOZ_ASSERT(IsWrapper(iterobj));
|
||||
|
||||
RootedObject obj(cx, CheckedUnwrap(iterobj));
|
||||
if (!obj)
|
||||
return false;
|
||||
|
||||
MOZ_RELEASE_ASSERT(obj->is<PropertyIteratorObject>());
|
||||
{
|
||||
AutoCompartment ac(cx, obj);
|
||||
NativeIterator* ni = obj->as<PropertyIteratorObject>().getNativeIterator();
|
||||
if (!NativeIteratorNext(cx, ni, rval))
|
||||
return false;
|
||||
}
|
||||
return cx->compartment()->wrap(cx, rval);
|
||||
}
|
||||
|
||||
static bool
|
||||
stopiter_hasInstance(JSContext* cx, HandleObject obj, MutableHandleValue v, bool* bp)
|
||||
{
|
||||
*bp = JS_IsStopIteration(v);
|
||||
return true;
|
||||
}
|
||||
|
||||
static const ClassOps StopIterationObjectClassOps = {
|
||||
nullptr, /* addProperty */
|
||||
nullptr, /* delProperty */
|
||||
nullptr, /* enumerate */
|
||||
nullptr, /* enumerate */
|
||||
nullptr, /* resolve */
|
||||
nullptr, /* mayResolve */
|
||||
nullptr, /* finalize */
|
||||
nullptr, /* call */
|
||||
stopiter_hasInstance
|
||||
};
|
||||
|
||||
const Class StopIterationObject::class_ = {
|
||||
"StopIteration",
|
||||
JSCLASS_HAS_CACHED_PROTO(JSProto_StopIteration),
|
||||
&StopIterationObjectClassOps
|
||||
};
|
||||
|
||||
static const JSFunctionSpec iterator_proto_methods[] = {
|
||||
JS_SELF_HOSTED_SYM_FN(iterator, "IteratorIdentity", 0, 0),
|
||||
JS_FS_END
|
||||
|
@ -1621,23 +1514,3 @@ GlobalObject::initStringIteratorProto(JSContext* cx, Handle<GlobalObject*> globa
|
|||
global->setReservedSlot(STRING_ITERATOR_PROTO, ObjectValue(*proto));
|
||||
return true;
|
||||
}
|
||||
|
||||
JSObject*
|
||||
js::InitStopIterationClass(JSContext* cx, HandleObject obj)
|
||||
{
|
||||
Handle<GlobalObject*> global = obj.as<GlobalObject>();
|
||||
if (!global->getPrototype(JSProto_StopIteration).isObject()) {
|
||||
RootedObject proto(cx, GlobalObject::createBlankPrototype(cx, global,
|
||||
&StopIterationObject::class_));
|
||||
if (!proto || !FreezeObject(cx, proto))
|
||||
return nullptr;
|
||||
|
||||
// This should use a non-JSProtoKey'd slot, but this is easier for now.
|
||||
if (!GlobalObject::initBuiltinConstructor(cx, global, JSProto_StopIteration, proto, proto))
|
||||
return nullptr;
|
||||
|
||||
global->setConstructor(JSProto_StopIteration, ObjectValue(*proto));
|
||||
}
|
||||
|
||||
return &global->getPrototype(JSProto_StopIteration).toObject();
|
||||
}
|
||||
|
|
|
@ -204,9 +204,6 @@ SuppressDeletedElement(JSContext* cx, HandleObject obj, uint32_t index);
|
|||
extern bool
|
||||
IteratorMore(JSContext* cx, HandleObject iterobj, MutableHandleValue rval);
|
||||
|
||||
extern bool
|
||||
ThrowStopIteration(JSContext* cx);
|
||||
|
||||
/*
|
||||
* Create an object of the form { value: VALUE, done: DONE }.
|
||||
* ES 2017 draft 7.4.7.
|
||||
|
@ -217,9 +214,6 @@ CreateIterResultObject(JSContext* cx, HandleValue value, bool done);
|
|||
bool
|
||||
IsPropertyIterator(HandleValue v);
|
||||
|
||||
extern JSObject*
|
||||
InitStopIterationClass(JSContext* cx, HandleObject obj);
|
||||
|
||||
enum class IteratorKind { Sync, Async };
|
||||
|
||||
} /* namespace js */
|
||||
|
|
|
@ -85,7 +85,6 @@
|
|||
real(LinkError, InitViaClassSpec, ERROR_CLASP(JSEXN_WASMLINKERROR)) \
|
||||
real(RuntimeError, InitViaClassSpec, ERROR_CLASP(JSEXN_WASMRUNTIMEERROR)) \
|
||||
imaginary(Iterator, dummy, dummy) \
|
||||
real(StopIteration, InitStopIterationClass, OCLASP(StopIteration)) \
|
||||
real(ArrayBuffer, InitViaClassSpec, OCLASP(ArrayBuffer)) \
|
||||
real(Int8Array, InitViaClassSpec, TYPED_ARRAY_CLASP(Int8)) \
|
||||
real(Uint8Array, InitViaClassSpec, TYPED_ARRAY_CLASP(Uint8)) \
|
||||
|
|
|
@ -37,7 +37,6 @@
|
|||
#include "vm/PIC.h"
|
||||
#include "vm/RegExpStatics.h"
|
||||
#include "vm/RegExpStaticsObject.h"
|
||||
#include "vm/StopIterationObject.h"
|
||||
#include "wasm/WasmJS.h"
|
||||
|
||||
#include "jscompartmentinlines.h"
|
||||
|
|
|
@ -1,22 +0,0 @@
|
|||
/* -*- 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_StopIterationObject_h
|
||||
#define vm_StopIterationObject_h
|
||||
|
||||
#include "jsobj.h"
|
||||
|
||||
namespace js {
|
||||
|
||||
class StopIterationObject : public JSObject
|
||||
{
|
||||
public:
|
||||
static const Class class_;
|
||||
};
|
||||
|
||||
} // namespace js
|
||||
|
||||
#endif /* vm_StopIterationObject_h */
|
|
@ -88,9 +88,6 @@ const EXCEPTION_CONSTRUCTORS = {
|
|||
result.stack = error.stack;
|
||||
return result;
|
||||
},
|
||||
StopIteration() {
|
||||
return StopIteration;
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
|
@ -124,7 +121,7 @@ this.BasePromiseWorker = function(url) {
|
|||
* }
|
||||
*
|
||||
* By default, this covers EvalError, InternalError, RangeError,
|
||||
* ReferenceError, SyntaxError, TypeError, URIError, StopIteration.
|
||||
* ReferenceError, SyntaxError, TypeError, URIError.
|
||||
*/
|
||||
this.ExceptionHandlers = Object.create(EXCEPTION_CONSTRUCTORS);
|
||||
|
||||
|
|
|
@ -169,14 +169,6 @@ AbstractWorker.prototype = {
|
|||
stack: exn.moduleStack
|
||||
};
|
||||
this.postMessage({fail: error, id, durationMs});
|
||||
} else if (exn == StopIteration) {
|
||||
// StopIteration is a well-known singleton, and requires a
|
||||
// slightly different treatment.
|
||||
this.log("Sending back StopIteration, id is", id);
|
||||
let error = {
|
||||
exn: "StopIteration"
|
||||
};
|
||||
this.postMessage({fail: error, id, durationMs});
|
||||
} else if ("toMsg" in exn) {
|
||||
// Extension mechanism for exception [de]serialization. We
|
||||
// assume that any exception with a method `toMsg()` knows how
|
||||
|
|
Загрузка…
Ссылка в новой задаче