mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-10-08 10:44:56 +00:00
Merge m-c to fx-team. a=merge
This commit is contained in:
commit
621dd98985
@ -18,7 +18,7 @@ function test() {
|
||||
is(workers.length, 0);
|
||||
|
||||
executeSoon(() => {
|
||||
evalInTab(tab, "let worker1 = new Worker('" + WORKER1_URL + "');");
|
||||
evalInTab(tab, "var worker1 = new Worker('" + WORKER1_URL + "');");
|
||||
});
|
||||
yield waitForWorkerListChanged(tabClient);
|
||||
|
||||
@ -27,7 +27,7 @@ function test() {
|
||||
is(workers[0].url, WORKER1_URL);
|
||||
|
||||
executeSoon(() => {
|
||||
evalInTab(tab, "let worker2 = new Worker('" + WORKER2_URL + "');");
|
||||
evalInTab(tab, "var worker2 = new Worker('" + WORKER2_URL + "');");
|
||||
});
|
||||
yield waitForWorkerListChanged(tabClient);
|
||||
|
||||
|
@ -111,7 +111,7 @@ function runTests()
|
||||
{
|
||||
method: "run",
|
||||
prepare: function() {
|
||||
sp.editor.setText("var foobarBug636725cache = 'foo';" +
|
||||
sp.editor.setText("window.foobarBug636725cache = 'foo';" +
|
||||
"typeof foobarBug636725cache;");
|
||||
},
|
||||
then: function([, , result]) {
|
||||
@ -122,7 +122,7 @@ function runTests()
|
||||
{
|
||||
method: "run",
|
||||
prepare: function() {
|
||||
sp.editor.setText("var foobarBug636725cache2 = 'foo';" +
|
||||
sp.editor.setText("window.foobarBug636725cache2 = 'foo';" +
|
||||
"typeof foobarBug636725cache2;");
|
||||
},
|
||||
then: function([, , result]) {
|
||||
@ -152,4 +152,4 @@ function runTests()
|
||||
"delete foobarBug636725cache2;");
|
||||
sp.run().then(finish);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
@ -11637,14 +11637,30 @@ public:
|
||||
return sList.getLast();
|
||||
}
|
||||
|
||||
enum IteratorOption
|
||||
{
|
||||
// When we are committing fullscreen changes or preparing for
|
||||
// that, we generally want to iterate all requests in the same
|
||||
// window with eDocumentsWithSameRoot option.
|
||||
eDocumentsWithSameRoot,
|
||||
// If we are removing a document from the tree, we would only
|
||||
// want to remove the requests from the given document and its
|
||||
// descendants. For that case, use eInclusiveDescendants.
|
||||
eInclusiveDescendants
|
||||
};
|
||||
|
||||
class Iterator
|
||||
{
|
||||
public:
|
||||
explicit Iterator(nsIDocument* aDoc)
|
||||
explicit Iterator(nsIDocument* aDoc, IteratorOption aOption)
|
||||
: mCurrent(PendingFullscreenRequestList::sList.getFirst())
|
||||
, mRootShellForIteration(aDoc->GetDocShell())
|
||||
{
|
||||
if (mCurrent) {
|
||||
mRootShell = GetRootShell(aDoc);
|
||||
if (mRootShellForIteration && aOption == eDocumentsWithSameRoot) {
|
||||
mRootShellForIteration->
|
||||
GetRootTreeItem(getter_AddRefs(mRootShellForIteration));
|
||||
}
|
||||
SkipToNextMatch();
|
||||
}
|
||||
}
|
||||
@ -11658,16 +11674,6 @@ public:
|
||||
const FullscreenRequest& Get() const { return *mCurrent; }
|
||||
|
||||
private:
|
||||
already_AddRefed<nsIDocShellTreeItem> GetRootShell(nsIDocument* aDoc)
|
||||
{
|
||||
if (nsIDocShellTreeItem* shell = aDoc->GetDocShell()) {
|
||||
nsCOMPtr<nsIDocShellTreeItem> rootShell;
|
||||
shell->GetRootTreeItem(getter_AddRefs(rootShell));
|
||||
return rootShell.forget();
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
void DeleteAndNextInternal()
|
||||
{
|
||||
FullscreenRequest* thisRequest = mCurrent;
|
||||
@ -11678,21 +11684,28 @@ public:
|
||||
{
|
||||
while (mCurrent) {
|
||||
nsCOMPtr<nsIDocShellTreeItem>
|
||||
rootShell = GetRootShell(mCurrent->GetDocument());
|
||||
if (!rootShell) {
|
||||
docShell = mCurrent->GetDocument()->GetDocShell();
|
||||
if (!docShell) {
|
||||
// Always automatically drop documents which has been
|
||||
// detached from the doc shell.
|
||||
DeleteAndNextInternal();
|
||||
} else if (rootShell != mRootShell) {
|
||||
mCurrent = mCurrent->getNext();
|
||||
} else {
|
||||
break;
|
||||
while (docShell && docShell != mRootShellForIteration) {
|
||||
docShell->GetParent(getter_AddRefs(docShell));
|
||||
}
|
||||
if (!docShell) {
|
||||
// We've gone over the root, but haven't find the target
|
||||
// ancestor, so skip this item.
|
||||
mCurrent = mCurrent->getNext();
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
FullscreenRequest* mCurrent;
|
||||
nsCOMPtr<nsIDocShellTreeItem> mRootShell;
|
||||
nsCOMPtr<nsIDocShellTreeItem> mRootShellForIteration;
|
||||
};
|
||||
|
||||
private:
|
||||
@ -11733,7 +11746,8 @@ nsDocument::RequestFullScreen(UniquePtr<FullscreenRequest>&& aRequest)
|
||||
if ((static_cast<nsGlobalWindow*>(rootWin.get())->FullScreen() &&
|
||||
// The iterator being at end at the beginning indicates there is
|
||||
// no pending fullscreen request which relates to this document.
|
||||
PendingFullscreenRequestList::Iterator(this).AtEnd()) ||
|
||||
PendingFullscreenRequestList::Iterator(
|
||||
this, PendingFullscreenRequestList::eDocumentsWithSameRoot).AtEnd()) ||
|
||||
nsContentUtils::GetRootDocument(this)->IsFullScreenDoc()) {
|
||||
ApplyFullscreen(*aRequest);
|
||||
return;
|
||||
@ -11766,7 +11780,8 @@ nsDocument::RequestFullScreen(UniquePtr<FullscreenRequest>&& aRequest)
|
||||
nsIDocument::HandlePendingFullscreenRequests(nsIDocument* aDoc)
|
||||
{
|
||||
bool handled = false;
|
||||
PendingFullscreenRequestList::Iterator iter(aDoc);
|
||||
PendingFullscreenRequestList::Iterator iter(
|
||||
aDoc, PendingFullscreenRequestList::eDocumentsWithSameRoot);
|
||||
while (!iter.AtEnd()) {
|
||||
const FullscreenRequest& request = iter.Get();
|
||||
if (request.GetDocument()->ApplyFullscreen(request)) {
|
||||
@ -11780,7 +11795,8 @@ nsIDocument::HandlePendingFullscreenRequests(nsIDocument* aDoc)
|
||||
static void
|
||||
ClearPendingFullscreenRequests(nsIDocument* aDoc)
|
||||
{
|
||||
PendingFullscreenRequestList::Iterator iter(aDoc);
|
||||
PendingFullscreenRequestList::Iterator iter(
|
||||
aDoc, PendingFullscreenRequestList::eInclusiveDescendants);
|
||||
while (!iter.AtEnd()) {
|
||||
iter.DeleteAndNext();
|
||||
}
|
||||
|
@ -391,8 +391,6 @@ WebGLContext::GetParameter(JSContext* cx, GLenum pname, ErrorResult& rv)
|
||||
case LOCAL_GL_MAX_VARYING_VECTORS:
|
||||
return JS::Int32Value(mGLMaxVaryingVectors);
|
||||
|
||||
case LOCAL_GL_NUM_COMPRESSED_TEXTURE_FORMATS:
|
||||
return JS::Int32Value(0);
|
||||
case LOCAL_GL_COMPRESSED_TEXTURE_FORMATS: {
|
||||
uint32_t length = mCompressedTextureFormats.Length();
|
||||
JSObject* obj = dom::Uint32Array::Create(cx, this, length,
|
||||
|
@ -25,11 +25,7 @@
|
||||
// For HTTP seeking, if number of bytes needing to be
|
||||
// seeked forward is less than this value then a read is
|
||||
// done rather than a byte range request.
|
||||
//
|
||||
// If we assume a 100Mbit connection, and assume reissuing an HTTP seek causes
|
||||
// a delay of 200ms, then in that 200ms we could have simply read ahead 2MB. So
|
||||
// setting SEEK_VS_READ_THRESHOLD to 1MB sounds reasonable.
|
||||
static const int64_t SEEK_VS_READ_THRESHOLD = 1 * 1024 * 1024;
|
||||
static const int64_t SEEK_VS_READ_THRESHOLD = 32*1024;
|
||||
|
||||
static const uint32_t HTTP_REQUESTED_RANGE_NOT_SATISFIABLE_CODE = 416;
|
||||
|
||||
|
@ -623,18 +623,18 @@ skip-if = toolkit == 'android' # bug 1043403
|
||||
[test_eme_persistent_sessions.html]
|
||||
skip-if = toolkit == 'android' # bug 1043403
|
||||
[test_eme_playback.html]
|
||||
skip-if = toolkit == 'android' || (os == 'win' && debug) # bug 1043403, bug 1187903
|
||||
skip-if = toolkit == 'android' || toolkit == 'gonk' || os == 'win' # bug 1043403, bug 1187903, bug 1186406, bug 1193351
|
||||
[test_eme_requestKeySystemAccess.html]
|
||||
skip-if = toolkit == 'android' # bug 1043403
|
||||
[test_eme_stream_capture_blocked_case1.html]
|
||||
tags=msg capturestream
|
||||
skip-if = toolkit == 'android' || os == 'win' # bug 1043403, bug 1140675, bug 1187903
|
||||
skip-if = toolkit == 'android' || toolkit == 'gonk' || os == 'win' # bug 1043403, bug 1140675, bug 1187903, bug 1193351
|
||||
[test_eme_stream_capture_blocked_case2.html]
|
||||
tags=msg capturestream
|
||||
skip-if = toolkit == 'android' || os == 'win' # bug 1043403, bug 1140675, bug 1187903
|
||||
skip-if = toolkit == 'android' || toolkit == 'gonk' || os == 'win' # bug 1043403, bug 1140675, bug 1187903, bug 1193351
|
||||
[test_eme_stream_capture_blocked_case3.html]
|
||||
tags=msg capturestream
|
||||
skip-if = toolkit == 'android' || os == 'win' # bug 1043403, bug 1140675, bug 1187903
|
||||
skip-if = toolkit == 'android' || toolkit == 'gonk' || os == 'win' # bug 1043403, bug 1140675, bug 1187903, bug 1193351
|
||||
[test_empty_resource.html]
|
||||
[test_error_in_video_document.html]
|
||||
skip-if = toolkit == 'android' || (os == 'win' && !debug) || (os == 'mac' && !debug) # bug 608634
|
||||
|
@ -40,12 +40,17 @@ NS_IMPL_CYCLE_COLLECTION_ROOT_NATIVE(AudioBuffer, AddRef)
|
||||
NS_IMPL_CYCLE_COLLECTION_UNROOT_NATIVE(AudioBuffer, Release)
|
||||
|
||||
AudioBuffer::AudioBuffer(AudioContext* aContext, uint32_t aNumberOfChannels,
|
||||
uint32_t aLength, float aSampleRate)
|
||||
uint32_t aLength, float aSampleRate,
|
||||
already_AddRefed<ThreadSharedFloatArrayBufferList>
|
||||
aInitialContents)
|
||||
: mOwnerWindow(do_GetWeakReference(aContext->GetOwner())),
|
||||
mSharedChannels(aInitialContents),
|
||||
mLength(aLength),
|
||||
mSampleRate(aSampleRate)
|
||||
{
|
||||
mJSChannels.SetCapacity(aNumberOfChannels);
|
||||
MOZ_ASSERT(!mSharedChannels ||
|
||||
mSharedChannels->GetChannels() == aNumberOfChannels);
|
||||
mJSChannels.SetLength(aNumberOfChannels);
|
||||
mozilla::HoldJSObjects(this);
|
||||
}
|
||||
|
||||
@ -64,6 +69,8 @@ AudioBuffer::ClearJSChannels()
|
||||
/* static */ already_AddRefed<AudioBuffer>
|
||||
AudioBuffer::Create(AudioContext* aContext, uint32_t aNumberOfChannels,
|
||||
uint32_t aLength, float aSampleRate,
|
||||
already_AddRefed<ThreadSharedFloatArrayBufferList>
|
||||
aInitialContents,
|
||||
JSContext* aJSContext, ErrorResult& aRv)
|
||||
{
|
||||
// Note that a buffer with zero channels is permitted here for the sake of
|
||||
@ -78,7 +85,12 @@ AudioBuffer::Create(AudioContext* aContext, uint32_t aNumberOfChannels,
|
||||
}
|
||||
|
||||
nsRefPtr<AudioBuffer> buffer =
|
||||
new AudioBuffer(aContext, aNumberOfChannels, aLength, aSampleRate);
|
||||
new AudioBuffer(aContext, aNumberOfChannels, aLength, aSampleRate,
|
||||
Move(aInitialContents));
|
||||
|
||||
if (buffer->mSharedChannels) {
|
||||
return buffer.forget();
|
||||
}
|
||||
|
||||
for (uint32_t i = 0; i < aNumberOfChannels; ++i) {
|
||||
JS::Rooted<JSObject*> array(aJSContext,
|
||||
@ -87,7 +99,7 @@ AudioBuffer::Create(AudioContext* aContext, uint32_t aNumberOfChannels,
|
||||
aRv.Throw(NS_ERROR_OUT_OF_MEMORY);
|
||||
return nullptr;
|
||||
}
|
||||
buffer->mJSChannels.AppendElement(array.get());
|
||||
buffer->mJSChannels[i] = array;
|
||||
}
|
||||
|
||||
return buffer.forget();
|
||||
@ -184,15 +196,6 @@ AudioBuffer::CopyToChannel(JSContext* aJSContext, const Float32Array& aSource,
|
||||
aSource.Data(), length);
|
||||
}
|
||||
|
||||
void
|
||||
AudioBuffer::SetRawChannelContents(uint32_t aChannel, float* aContents)
|
||||
{
|
||||
MOZ_ASSERT(!GetWrapperPreserveColor() && !mSharedChannels,
|
||||
"The AudioBuffer object should not have been handed to JS or have C++ callers neuter its typed array");
|
||||
JS::AutoCheckCannotGC nogc;
|
||||
PodCopy(JS_GetFloat32ArrayData(mJSChannels[aChannel], nogc), aContents, mLength);
|
||||
}
|
||||
|
||||
void
|
||||
AudioBuffer::GetChannelData(JSContext* aJSContext, uint32_t aChannel,
|
||||
JS::MutableHandle<JSObject*> aRetval,
|
||||
|
@ -33,11 +33,23 @@ class AudioContext;
|
||||
class AudioBuffer final : public nsWrapperCache
|
||||
{
|
||||
public:
|
||||
// If non-null, aInitialContents must have number of channels equal to
|
||||
// aNumberOfChannels and their lengths must be at least aLength.
|
||||
static already_AddRefed<AudioBuffer>
|
||||
Create(AudioContext* aContext, uint32_t aNumberOfChannels,
|
||||
uint32_t aLength, float aSampleRate,
|
||||
already_AddRefed<ThreadSharedFloatArrayBufferList> aInitialContents,
|
||||
JSContext* aJSContext, ErrorResult& aRv);
|
||||
|
||||
static already_AddRefed<AudioBuffer>
|
||||
Create(AudioContext* aContext, uint32_t aNumberOfChannels,
|
||||
uint32_t aLength, float aSampleRate,
|
||||
JSContext* aJSContext, ErrorResult& aRv)
|
||||
{
|
||||
return Create(aContext, aNumberOfChannels, aLength, aSampleRate,
|
||||
nullptr, aJSContext, aRv);
|
||||
}
|
||||
|
||||
size_t SizeOfIncludingThis(mozilla::MallocSizeOf aMallocSizeOf) const;
|
||||
|
||||
NS_INLINE_DECL_CYCLE_COLLECTING_NATIVE_REFCOUNTING(AudioBuffer)
|
||||
@ -91,15 +103,11 @@ public:
|
||||
*/
|
||||
ThreadSharedFloatArrayBufferList* GetThreadSharedChannelsForRate(JSContext* aContext);
|
||||
|
||||
// This replaces the contents of the JS array for the given channel.
|
||||
// This function needs to be called on an AudioBuffer which has not been
|
||||
// handed off to the content yet, and right after the object has been
|
||||
// initialized.
|
||||
void SetRawChannelContents(uint32_t aChannel, float* aContents);
|
||||
|
||||
protected:
|
||||
AudioBuffer(AudioContext* aContext, uint32_t aNumberOfChannels,
|
||||
uint32_t aLength, float aSampleRate);
|
||||
uint32_t aLength, float aSampleRate,
|
||||
already_AddRefed<ThreadSharedFloatArrayBufferList>
|
||||
aInitialContents);
|
||||
~AudioBuffer();
|
||||
|
||||
bool RestoreJSChannelData(JSContext* aJSContext);
|
||||
|
@ -32,8 +32,6 @@ static uint8_t gWebAudioOutputKey;
|
||||
class OfflineDestinationNodeEngine final : public AudioNodeEngine
|
||||
{
|
||||
public:
|
||||
typedef AutoFallibleTArray<nsAutoArrayPtr<float>, 2> InputChannels;
|
||||
|
||||
OfflineDestinationNodeEngine(AudioDestinationNode* aNode,
|
||||
uint32_t aNumberOfChannels,
|
||||
uint32_t aLength,
|
||||
@ -56,65 +54,53 @@ public:
|
||||
// will not go anywhere.
|
||||
*aOutput = aInput;
|
||||
|
||||
// The output buffer is allocated lazily, on the rendering thread.
|
||||
if (!mBufferAllocated) {
|
||||
// The output buffer is allocated lazily, on the rendering thread, when
|
||||
// non-null input is received.
|
||||
if (!mBufferAllocated && !aInput.IsNull()) {
|
||||
// These allocations might fail if content provides a huge number of
|
||||
// channels or size, but it's OK since we'll deal with the failure
|
||||
// gracefully.
|
||||
if (mInputChannels.SetLength(mNumberOfChannels, fallible)) {
|
||||
mBuffer = ThreadSharedFloatArrayBufferList::
|
||||
Create(mNumberOfChannels, mLength, fallible);
|
||||
if (mBuffer && mWriteIndex) {
|
||||
// Zero leading for any null chunks that were skipped.
|
||||
for (uint32_t i = 0; i < mNumberOfChannels; ++i) {
|
||||
mInputChannels[i] = new (fallible) float[mLength];
|
||||
if (!mInputChannels[i]) {
|
||||
mInputChannels.Clear();
|
||||
break;
|
||||
}
|
||||
float* channelData = mBuffer->GetDataForWrite(i);
|
||||
PodZero(channelData, mWriteIndex);
|
||||
}
|
||||
}
|
||||
|
||||
mBufferAllocated = true;
|
||||
}
|
||||
|
||||
// Handle the case of allocation failure in the input buffer
|
||||
if (mInputChannels.IsEmpty()) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (mWriteIndex >= mLength) {
|
||||
NS_ASSERTION(mWriteIndex == mLength, "Overshot length");
|
||||
// Don't record any more.
|
||||
return;
|
||||
}
|
||||
// Skip copying if there is no buffer.
|
||||
uint32_t outputChannelCount = mBuffer ? mNumberOfChannels : 0;
|
||||
|
||||
// Record our input buffer
|
||||
MOZ_ASSERT(mWriteIndex < mLength, "How did this happen?");
|
||||
const uint32_t duration = std::min(WEBAUDIO_BLOCK_SIZE, mLength - mWriteIndex);
|
||||
const uint32_t commonChannelCount = std::min(mInputChannels.Length(),
|
||||
aInput.mChannelData.Length());
|
||||
// First, copy as many channels in the input as we have
|
||||
for (uint32_t i = 0; i < commonChannelCount; ++i) {
|
||||
if (aInput.IsNull()) {
|
||||
PodZero(mInputChannels[i] + mWriteIndex, duration);
|
||||
const uint32_t inputChannelCount = aInput.mChannelData.Length();
|
||||
for (uint32_t i = 0; i < outputChannelCount; ++i) {
|
||||
float* outputData = mBuffer->GetDataForWrite(i) + mWriteIndex;
|
||||
if (aInput.IsNull() || i >= inputChannelCount) {
|
||||
PodZero(outputData, duration);
|
||||
} else {
|
||||
const float* inputBuffer = static_cast<const float*>(aInput.mChannelData[i]);
|
||||
if (duration == WEBAUDIO_BLOCK_SIZE) {
|
||||
// Use the optimized version of the copy with scale operation
|
||||
AudioBlockCopyChannelWithScale(inputBuffer, aInput.mVolume,
|
||||
mInputChannels[i] + mWriteIndex);
|
||||
outputData);
|
||||
} else {
|
||||
if (aInput.mVolume == 1.0f) {
|
||||
PodCopy(mInputChannels[i] + mWriteIndex, inputBuffer, duration);
|
||||
PodCopy(outputData, inputBuffer, duration);
|
||||
} else {
|
||||
for (uint32_t j = 0; j < duration; ++j) {
|
||||
mInputChannels[i][mWriteIndex + j] = aInput.mVolume * inputBuffer[j];
|
||||
outputData[j] = aInput.mVolume * inputBuffer[j];
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
// Then, silence all of the remaining channels
|
||||
for (uint32_t i = commonChannelCount; i < mInputChannels.Length(); ++i) {
|
||||
PodZero(mInputChannels[i] + mWriteIndex, duration);
|
||||
}
|
||||
mWriteIndex += duration;
|
||||
|
||||
if (mWriteIndex >= mLength) {
|
||||
@ -165,14 +151,11 @@ public:
|
||||
// Create the input buffer
|
||||
ErrorResult rv;
|
||||
nsRefPtr<AudioBuffer> renderedBuffer =
|
||||
AudioBuffer::Create(context, mInputChannels.Length(),
|
||||
mLength, mSampleRate, cx, rv);
|
||||
AudioBuffer::Create(context, mNumberOfChannels, mLength, mSampleRate,
|
||||
mBuffer.forget(), cx, rv);
|
||||
if (rv.Failed()) {
|
||||
return;
|
||||
}
|
||||
for (uint32_t i = 0; i < mInputChannels.Length(); ++i) {
|
||||
renderedBuffer->SetRawChannelContents(i, mInputChannels[i]);
|
||||
}
|
||||
|
||||
aNode->ResolvePromise(renderedBuffer);
|
||||
|
||||
@ -186,7 +169,7 @@ public:
|
||||
virtual size_t SizeOfExcludingThis(MallocSizeOf aMallocSizeOf) const override
|
||||
{
|
||||
size_t amount = AudioNodeEngine::SizeOfExcludingThis(aMallocSizeOf);
|
||||
amount += mInputChannels.ShallowSizeOfExcludingThis(aMallocSizeOf);
|
||||
amount += mBuffer->SizeOfIncludingThis(aMallocSizeOf);
|
||||
return amount;
|
||||
}
|
||||
|
||||
@ -196,11 +179,11 @@ public:
|
||||
}
|
||||
|
||||
private:
|
||||
// The input to the destination node is recorded in the mInputChannels buffer.
|
||||
// The input to the destination node is recorded in mBuffer.
|
||||
// When this buffer fills up with mLength frames, the buffered input is sent
|
||||
// to the main thread in order to dispatch OfflineAudioCompletionEvent.
|
||||
InputChannels mInputChannels;
|
||||
// An index representing the next offset in mInputChannels to be written to.
|
||||
nsRefPtr<ThreadSharedFloatArrayBufferList> mBuffer;
|
||||
// An index representing the next offset in mBuffer to be written to.
|
||||
uint32_t mWriteIndex;
|
||||
uint32_t mNumberOfChannels;
|
||||
// How many frames the OfflineAudioContext intends to produce.
|
||||
|
@ -12,6 +12,26 @@
|
||||
|
||||
namespace mozilla {
|
||||
|
||||
already_AddRefed<ThreadSharedFloatArrayBufferList>
|
||||
ThreadSharedFloatArrayBufferList::Create(uint32_t aChannelCount,
|
||||
size_t aLength,
|
||||
const mozilla::fallible_t&)
|
||||
{
|
||||
nsRefPtr<ThreadSharedFloatArrayBufferList> buffer =
|
||||
new ThreadSharedFloatArrayBufferList(aChannelCount);
|
||||
|
||||
for (uint32_t i = 0; i < aChannelCount; ++i) {
|
||||
float* channelData = js_pod_malloc<float>(aLength);
|
||||
if (!channelData) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
buffer->SetData(i, channelData, js_free, channelData);
|
||||
}
|
||||
|
||||
return buffer.forget();
|
||||
}
|
||||
|
||||
void
|
||||
AllocateAudioBlock(uint32_t aChannelCount, AudioChunk* aChunk)
|
||||
{
|
||||
|
@ -31,12 +31,19 @@ class ThreadSharedFloatArrayBufferList final : public ThreadSharedObject
|
||||
{
|
||||
public:
|
||||
/**
|
||||
* Construct with null data.
|
||||
* Construct with null channel data pointers.
|
||||
*/
|
||||
explicit ThreadSharedFloatArrayBufferList(uint32_t aCount)
|
||||
{
|
||||
mContents.SetLength(aCount);
|
||||
}
|
||||
/**
|
||||
* Create with buffers suitable for transfer to
|
||||
* JS_NewArrayBufferWithContents(). The buffer contents are uninitialized
|
||||
* and so should be set using GetDataForWrite().
|
||||
*/
|
||||
static already_AddRefed<ThreadSharedFloatArrayBufferList>
|
||||
Create(uint32_t aChannelCount, size_t aLength, const mozilla::fallible_t&);
|
||||
|
||||
struct Storage final
|
||||
{
|
||||
@ -58,7 +65,7 @@ public:
|
||||
}
|
||||
void* mDataToFree;
|
||||
void (*mFree)(void*);
|
||||
const float* mSampleData;
|
||||
float* mSampleData;
|
||||
};
|
||||
|
||||
/**
|
||||
@ -69,12 +76,21 @@ public:
|
||||
* This can be called on any thread.
|
||||
*/
|
||||
const float* GetData(uint32_t aIndex) const { return mContents[aIndex].mSampleData; }
|
||||
/**
|
||||
* This can be called on any thread, but only when the calling thread is the
|
||||
* only owner.
|
||||
*/
|
||||
float* GetDataForWrite(uint32_t aIndex)
|
||||
{
|
||||
MOZ_ASSERT(!IsShared());
|
||||
return mContents[aIndex].mSampleData;
|
||||
}
|
||||
|
||||
/**
|
||||
* Call this only during initialization, before the object is handed to
|
||||
* any other thread.
|
||||
*/
|
||||
void SetData(uint32_t aIndex, void* aDataToFree, void (*aFreeFunc)(void*), const float* aData)
|
||||
void SetData(uint32_t aIndex, void* aDataToFree, void (*aFreeFunc)(void*), float* aData)
|
||||
{
|
||||
Storage* s = &mContents[aIndex];
|
||||
if (s->mFree) {
|
||||
|
@ -347,19 +347,9 @@ MediaDecodeTask::FinishDecode()
|
||||
// Allocate the channel buffers. Note that if we end up resampling, we may
|
||||
// write fewer bytes than mResampledFrames to the output buffer, in which
|
||||
// case mWriteIndex will tell us how many valid samples we have.
|
||||
bool memoryAllocationSuccess = true;
|
||||
if (!mDecodeJob.mChannelBuffers.SetLength(channelCount, fallible)) {
|
||||
memoryAllocationSuccess = false;
|
||||
} else {
|
||||
for (uint32_t i = 0; i < channelCount; ++i) {
|
||||
mDecodeJob.mChannelBuffers[i] = new (fallible) float[resampledFrames];
|
||||
if (!mDecodeJob.mChannelBuffers[i]) {
|
||||
memoryAllocationSuccess = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (!memoryAllocationSuccess) {
|
||||
mDecodeJob.mBuffer = ThreadSharedFloatArrayBufferList::
|
||||
Create(channelCount, resampledFrames, fallible);
|
||||
if (!mDecodeJob.mBuffer) {
|
||||
ReportFailureOnMainThread(WebAudioDecodeJob::UnknownError);
|
||||
return;
|
||||
}
|
||||
@ -376,11 +366,12 @@ MediaDecodeTask::FinishDecode()
|
||||
for (uint32_t i = 0; i < audioData->mChannels; ++i) {
|
||||
uint32_t inSamples = audioData->mFrames;
|
||||
uint32_t outSamples = maxOutSamples;
|
||||
float* outData =
|
||||
mDecodeJob.mBuffer->GetDataForWrite(i) + mDecodeJob.mWriteIndex;
|
||||
|
||||
WebAudioUtils::SpeexResamplerProcess(
|
||||
resampler, i, &bufferData[i * audioData->mFrames], &inSamples,
|
||||
mDecodeJob.mChannelBuffers[i] + mDecodeJob.mWriteIndex,
|
||||
&outSamples);
|
||||
outData, &outSamples);
|
||||
|
||||
if (i == audioData->mChannels - 1) {
|
||||
mDecodeJob.mWriteIndex += outSamples;
|
||||
@ -390,9 +381,10 @@ MediaDecodeTask::FinishDecode()
|
||||
}
|
||||
} else {
|
||||
for (uint32_t i = 0; i < audioData->mChannels; ++i) {
|
||||
float* outData =
|
||||
mDecodeJob.mBuffer->GetDataForWrite(i) + mDecodeJob.mWriteIndex;
|
||||
ConvertAudioSamples(&bufferData[i * audioData->mFrames],
|
||||
mDecodeJob.mChannelBuffers[i] + mDecodeJob.mWriteIndex,
|
||||
audioData->mFrames);
|
||||
outData, audioData->mFrames);
|
||||
|
||||
if (i == audioData->mChannels - 1) {
|
||||
mDecodeJob.mWriteIndex += audioData->mFrames;
|
||||
@ -407,11 +399,12 @@ MediaDecodeTask::FinishDecode()
|
||||
for (uint32_t i = 0; i < channelCount; ++i) {
|
||||
uint32_t inSamples = inputLatency;
|
||||
uint32_t outSamples = maxOutSamples;
|
||||
float* outData =
|
||||
mDecodeJob.mBuffer->GetDataForWrite(i) + mDecodeJob.mWriteIndex;
|
||||
|
||||
WebAudioUtils::SpeexResamplerProcess(
|
||||
resampler, i, (AudioDataValue*)nullptr, &inSamples,
|
||||
mDecodeJob.mChannelBuffers[i] + mDecodeJob.mWriteIndex,
|
||||
&outSamples);
|
||||
outData, &outSamples);
|
||||
|
||||
if (i == channelCount - 1) {
|
||||
mDecodeJob.mWriteIndex += outSamples;
|
||||
@ -464,17 +457,11 @@ WebAudioDecodeJob::AllocateBuffer()
|
||||
|
||||
// Now create the AudioBuffer
|
||||
ErrorResult rv;
|
||||
mOutput = AudioBuffer::Create(mContext, mChannelBuffers.Length(),
|
||||
mWriteIndex, mContext->SampleRate(), cx, rv);
|
||||
if (rv.Failed()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
for (uint32_t i = 0; i < mChannelBuffers.Length(); ++i) {
|
||||
mOutput->SetRawChannelContents(i, mChannelBuffers[i]);
|
||||
}
|
||||
|
||||
return true;
|
||||
uint32_t channelCount = mBuffer->GetChannels();
|
||||
mOutput = AudioBuffer::Create(mContext, channelCount,
|
||||
mWriteIndex, mContext->SampleRate(),
|
||||
mBuffer.forget(), cx, rv);
|
||||
return !rv.Failed();
|
||||
}
|
||||
|
||||
void
|
||||
@ -614,10 +601,7 @@ WebAudioDecodeJob::SizeOfExcludingThis(MallocSizeOf aMallocSizeOf) const
|
||||
if (mOutput) {
|
||||
amount += mOutput->SizeOfIncludingThis(aMallocSizeOf);
|
||||
}
|
||||
amount += mChannelBuffers.ShallowSizeOfExcludingThis(aMallocSizeOf);
|
||||
for (uint32_t i = 0; i < mChannelBuffers.Length(); ++i) {
|
||||
amount += mChannelBuffers[i].SizeOfExcludingThis(aMallocSizeOf);
|
||||
}
|
||||
amount += mBuffer->SizeOfIncludingThis(aMallocSizeOf);
|
||||
return amount;
|
||||
}
|
||||
|
||||
|
@ -16,6 +16,8 @@
|
||||
|
||||
namespace mozilla {
|
||||
|
||||
class ThreadSharedFloatArrayBufferList;
|
||||
|
||||
namespace dom {
|
||||
class AudioBuffer;
|
||||
class AudioContext;
|
||||
@ -46,7 +48,6 @@ struct WebAudioDecodeJob final
|
||||
};
|
||||
|
||||
typedef void (WebAudioDecodeJob::*ResultFn)(ErrorCode);
|
||||
typedef nsAutoArrayPtr<float> ChannelBuffer;
|
||||
|
||||
void OnSuccess(ErrorCode /* ignored */);
|
||||
void OnFailure(ErrorCode aErrorCode);
|
||||
@ -63,7 +64,7 @@ struct WebAudioDecodeJob final
|
||||
nsRefPtr<dom::DecodeSuccessCallback> mSuccessCallback;
|
||||
nsRefPtr<dom::DecodeErrorCallback> mFailureCallback; // can be null
|
||||
nsRefPtr<dom::AudioBuffer> mOutput;
|
||||
FallibleTArray<ChannelBuffer> mChannelBuffers;
|
||||
nsRefPtr<ThreadSharedFloatArrayBufferList> mBuffer;
|
||||
|
||||
private:
|
||||
~WebAudioDecodeJob();
|
||||
|
@ -240,8 +240,6 @@ private:
|
||||
class ScriptProcessorNodeEngine final : public AudioNodeEngine
|
||||
{
|
||||
public:
|
||||
typedef nsAutoTArray<nsAutoArrayPtr<float>, 2> InputChannels;
|
||||
|
||||
ScriptProcessorNodeEngine(ScriptProcessorNode* aNode,
|
||||
AudioDestinationNode* aDestination,
|
||||
uint32_t aBufferSize,
|
||||
@ -250,11 +248,9 @@ public:
|
||||
, mSource(nullptr)
|
||||
, mDestination(aDestination->Stream())
|
||||
, mBufferSize(aBufferSize)
|
||||
, mInputChannelCount(aNumberOfInputChannels)
|
||||
, mInputWriteIndex(0)
|
||||
, mSeenNonSilenceInput(false)
|
||||
{
|
||||
mInputChannels.SetLength(aNumberOfInputChannels);
|
||||
AllocateInputBlock();
|
||||
}
|
||||
|
||||
void SetSourceStream(AudioNodeStream* aSource)
|
||||
@ -294,23 +290,34 @@ public:
|
||||
if (!mIsConnected) {
|
||||
aOutput->SetNull(WEBAUDIO_BLOCK_SIZE);
|
||||
mSharedBuffers->Reset();
|
||||
mSeenNonSilenceInput = false;
|
||||
mInputWriteIndex = 0;
|
||||
return;
|
||||
}
|
||||
|
||||
// First, record our input buffer
|
||||
for (uint32_t i = 0; i < mInputChannels.Length(); ++i) {
|
||||
// The input buffer is allocated lazily when non-null input is received.
|
||||
if (!aInput.IsNull() && !mInputBuffer) {
|
||||
mInputBuffer = ThreadSharedFloatArrayBufferList::
|
||||
Create(mInputChannelCount, mBufferSize, fallible);
|
||||
if (mInputBuffer && mInputWriteIndex) {
|
||||
// Zero leading for null chunks that were skipped.
|
||||
for (uint32_t i = 0; i < mInputChannelCount; ++i) {
|
||||
float* channelData = mInputBuffer->GetDataForWrite(i);
|
||||
PodZero(channelData, mInputWriteIndex);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// First, record our input buffer, if its allocation succeeded.
|
||||
uint32_t inputChannelCount = mInputBuffer ? mInputBuffer->GetChannels() : 0;
|
||||
for (uint32_t i = 0; i < inputChannelCount; ++i) {
|
||||
float* writeData = mInputBuffer->GetDataForWrite(i) + mInputWriteIndex;
|
||||
if (aInput.IsNull()) {
|
||||
PodZero(mInputChannels[i] + mInputWriteIndex,
|
||||
aInput.GetDuration());
|
||||
PodZero(writeData, aInput.GetDuration());
|
||||
} else {
|
||||
mSeenNonSilenceInput = true;
|
||||
MOZ_ASSERT(aInput.GetDuration() == WEBAUDIO_BLOCK_SIZE, "sanity check");
|
||||
MOZ_ASSERT(aInput.mChannelData.Length() == mInputChannels.Length());
|
||||
MOZ_ASSERT(aInput.mChannelData.Length() == inputChannelCount);
|
||||
AudioBlockCopyChannelWithScale(static_cast<const float*>(aInput.mChannelData[i]),
|
||||
aInput.mVolume,
|
||||
mInputChannels[i] + mInputWriteIndex);
|
||||
aInput.mVolume, writeData);
|
||||
}
|
||||
}
|
||||
mInputWriteIndex += aInput.GetDuration();
|
||||
@ -323,8 +330,6 @@ public:
|
||||
if (mInputWriteIndex >= mBufferSize) {
|
||||
SendBuffersToMainThread(aStream);
|
||||
mInputWriteIndex -= mBufferSize;
|
||||
mSeenNonSilenceInput = false;
|
||||
AllocateInputBlock();
|
||||
}
|
||||
}
|
||||
|
||||
@ -335,10 +340,7 @@ public:
|
||||
// - mDestination (probably)
|
||||
size_t amount = AudioNodeEngine::SizeOfExcludingThis(aMallocSizeOf);
|
||||
amount += mSharedBuffers->SizeOfIncludingThis(aMallocSizeOf);
|
||||
amount += mInputChannels.ShallowSizeOfExcludingThis(aMallocSizeOf);
|
||||
for (size_t i = 0; i < mInputChannels.Length(); i++) {
|
||||
amount += mInputChannels[i].SizeOfExcludingThis(aMallocSizeOf);
|
||||
}
|
||||
amount += mInputBuffer->SizeOfIncludingThis(aMallocSizeOf);
|
||||
|
||||
return amount;
|
||||
}
|
||||
@ -349,15 +351,6 @@ public:
|
||||
}
|
||||
|
||||
private:
|
||||
void AllocateInputBlock()
|
||||
{
|
||||
for (unsigned i = 0; i < mInputChannels.Length(); ++i) {
|
||||
if (!mInputChannels[i]) {
|
||||
mInputChannels[i] = new float[mBufferSize];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void SendBuffersToMainThread(AudioNodeStream* aStream)
|
||||
{
|
||||
MOZ_ASSERT(!NS_IsMainThread());
|
||||
@ -376,19 +369,12 @@ private:
|
||||
{
|
||||
public:
|
||||
Command(AudioNodeStream* aStream,
|
||||
InputChannels& aInputChannels,
|
||||
double aPlaybackTime,
|
||||
bool aNullInput)
|
||||
already_AddRefed<ThreadSharedFloatArrayBufferList> aInputBuffer,
|
||||
double aPlaybackTime)
|
||||
: mStream(aStream)
|
||||
, mInputBuffer(aInputBuffer)
|
||||
, mPlaybackTime(aPlaybackTime)
|
||||
, mNullInput(aNullInput)
|
||||
{
|
||||
mInputChannels.SetLength(aInputChannels.Length());
|
||||
if (!aNullInput) {
|
||||
for (uint32_t i = 0; i < mInputChannels.Length(); ++i) {
|
||||
mInputChannels[i] = aInputChannels[i].forget();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
NS_IMETHOD Run() override
|
||||
@ -431,22 +417,19 @@ private:
|
||||
return nullptr;
|
||||
}
|
||||
JSContext* cx = jsapi.cx();
|
||||
uint32_t inputChannelCount = aNode->ChannelCount();
|
||||
|
||||
// Create the input buffer
|
||||
nsRefPtr<AudioBuffer> inputBuffer;
|
||||
if (!mNullInput) {
|
||||
if (mInputBuffer) {
|
||||
ErrorResult rv;
|
||||
inputBuffer =
|
||||
AudioBuffer::Create(context, mInputChannels.Length(),
|
||||
aNode->BufferSize(),
|
||||
context->SampleRate(), cx, rv);
|
||||
AudioBuffer::Create(context, inputChannelCount,
|
||||
aNode->BufferSize(), context->SampleRate(),
|
||||
mInputBuffer.forget(), cx, rv);
|
||||
if (rv.Failed()) {
|
||||
return nullptr;
|
||||
}
|
||||
// Put the channel data inside it
|
||||
for (uint32_t i = 0; i < mInputChannels.Length(); ++i) {
|
||||
inputBuffer->SetRawChannelContents(i, mInputChannels[i]);
|
||||
}
|
||||
}
|
||||
|
||||
// Ask content to produce data in the output buffer
|
||||
@ -457,7 +440,7 @@ private:
|
||||
nsRefPtr<AudioProcessingEvent> event =
|
||||
new AudioProcessingEvent(aNode, nullptr, nullptr);
|
||||
event->InitEvent(inputBuffer,
|
||||
mInputChannels.Length(),
|
||||
inputChannelCount,
|
||||
context->StreamTimeToDOMTime(mPlaybackTime));
|
||||
aNode->DispatchTrustedEvent(event);
|
||||
|
||||
@ -478,14 +461,12 @@ private:
|
||||
}
|
||||
private:
|
||||
nsRefPtr<AudioNodeStream> mStream;
|
||||
InputChannels mInputChannels;
|
||||
nsRefPtr<ThreadSharedFloatArrayBufferList> mInputBuffer;
|
||||
double mPlaybackTime;
|
||||
bool mNullInput;
|
||||
};
|
||||
|
||||
NS_DispatchToMainThread(new Command(aStream, mInputChannels,
|
||||
playbackTime,
|
||||
!mSeenNonSilenceInput));
|
||||
NS_DispatchToMainThread(new Command(aStream, mInputBuffer.forget(),
|
||||
playbackTime));
|
||||
}
|
||||
|
||||
friend class ScriptProcessorNode;
|
||||
@ -493,12 +474,12 @@ private:
|
||||
nsAutoPtr<SharedBuffers> mSharedBuffers;
|
||||
AudioNodeStream* mSource;
|
||||
AudioNodeStream* mDestination;
|
||||
InputChannels mInputChannels;
|
||||
nsRefPtr<ThreadSharedFloatArrayBufferList> mInputBuffer;
|
||||
const uint32_t mBufferSize;
|
||||
const uint32_t mInputChannelCount;
|
||||
// The write index into the current input buffer
|
||||
uint32_t mInputWriteIndex;
|
||||
bool mIsConnected = false;
|
||||
bool mSeenNonSilenceInput;
|
||||
};
|
||||
|
||||
ScriptProcessorNode::ScriptProcessorNode(AudioContext* aContext,
|
||||
|
@ -10,9 +10,10 @@ support-files =
|
||||
[test_abort.html]
|
||||
skip-if = toolkit == 'android' || toolkit == 'gonk' # bug 1037287
|
||||
[test_audio_capture_error.html]
|
||||
skip-if = toolkit == 'gonk' # Bug 1191270
|
||||
[test_call_start_from_end_handler.html]
|
||||
tags=capturestream
|
||||
skip-if = ((android_version == '18' || buildapp == 'b2g') && debug) # bug 967606
|
||||
skip-if = (android_version == '18' && debug) || buildapp == 'b2g' # bug 967606
|
||||
[test_nested_eventloop.html]
|
||||
skip-if = buildapp == 'mulet' || buildapp == 'b2g' || toolkit == 'android' || e10s # b2g(showmodaldialog)
|
||||
[test_preference_enable.html]
|
||||
|
@ -1725,9 +1725,11 @@ ScriptExecutorRunnable::WorkerRun(JSContext* aCx, WorkerPrivate* aWorkerPrivate)
|
||||
NS_ASSERTION(!loadInfo.mExecutionResult, "Should not have executed yet!");
|
||||
|
||||
if (NS_FAILED(loadInfo.mLoadResult)) {
|
||||
scriptloader::ReportLoadError(aCx, loadInfo.mURL, loadInfo.mLoadResult,
|
||||
false);
|
||||
aWorkerPrivate->MaybeDispatchLoadFailedRunnable();
|
||||
scriptloader::ReportLoadError(aCx, loadInfo.mLoadResult);
|
||||
// Top level scripts only!
|
||||
if (mIsWorkerScript) {
|
||||
aWorkerPrivate->MaybeDispatchLoadFailedRunnable();
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
@ -1888,25 +1890,21 @@ ChannelFromScriptURLWorkerThread(JSContext* aCx,
|
||||
return getter->GetResult();
|
||||
}
|
||||
|
||||
void ReportLoadError(JSContext* aCx, const nsAString& aURL,
|
||||
nsresult aLoadResult, bool aIsMainThread)
|
||||
void ReportLoadError(JSContext* aCx, nsresult aLoadResult)
|
||||
{
|
||||
NS_LossyConvertUTF16toASCII url(aURL);
|
||||
|
||||
switch (aLoadResult) {
|
||||
case NS_BINDING_ABORTED:
|
||||
// Canceled, don't set an exception.
|
||||
break;
|
||||
|
||||
case NS_ERROR_MALFORMED_URI:
|
||||
JS_ReportError(aCx, "Malformed script URI: %s", url.get());
|
||||
break;
|
||||
|
||||
case NS_ERROR_FILE_NOT_FOUND:
|
||||
case NS_ERROR_NOT_AVAILABLE:
|
||||
JS_ReportError(aCx, "Script file not found: %s", url.get());
|
||||
Throw(aCx, NS_ERROR_DOM_NETWORK_ERR);
|
||||
break;
|
||||
|
||||
case NS_ERROR_MALFORMED_URI:
|
||||
aLoadResult = NS_ERROR_DOM_SYNTAX_ERR;
|
||||
// fall through
|
||||
case NS_ERROR_DOM_SECURITY_ERR:
|
||||
case NS_ERROR_DOM_SYNTAX_ERR:
|
||||
Throw(aCx, aLoadResult);
|
||||
|
@ -47,8 +47,7 @@ ChannelFromScriptURLWorkerThread(JSContext* aCx,
|
||||
const nsAString& aScriptURL,
|
||||
nsIChannel** aChannel);
|
||||
|
||||
void ReportLoadError(JSContext* aCx, const nsAString& aURL,
|
||||
nsresult aLoadResult, bool aIsMainThread);
|
||||
void ReportLoadError(JSContext* aCx, nsresult aLoadResult);
|
||||
|
||||
bool LoadMainScript(JSContext* aCx, const nsAString& aScriptURL,
|
||||
WorkerScriptType aWorkerScriptType);
|
||||
|
@ -4153,7 +4153,8 @@ WorkerPrivate::Constructor(JSContext* aCx,
|
||||
aIsChromeWorker, InheritLoadGroup,
|
||||
aWorkerType, stackLoadInfo.ptr());
|
||||
if (NS_FAILED(rv)) {
|
||||
scriptloader::ReportLoadError(aCx, aScriptURL, rv, !parent);
|
||||
// XXXkhuey this is weird, why throw again after setting an exception?
|
||||
scriptloader::ReportLoadError(aCx, rv);
|
||||
aRv.Throw(rv);
|
||||
return nullptr;
|
||||
}
|
||||
|
@ -6,6 +6,12 @@ function callByScript() {
|
||||
importScripts(['importscript.sjs']);
|
||||
importScripts(['importscript.sjs']);
|
||||
|
||||
try {
|
||||
importScripts(['there-is-nothing-here.js']);
|
||||
} catch (ex) {
|
||||
// Importing a non-existent script should not abort the SW load, bug 1198982.
|
||||
}
|
||||
|
||||
onmessage = function(e) {
|
||||
self.clients.matchAll().then(function(res) {
|
||||
if (!res.length) {
|
||||
|
@ -25,7 +25,7 @@ Tests of DOM Worker Threads
|
||||
|
||||
worker.onerror = function(event) {
|
||||
is(event.target, worker);
|
||||
is(event.message, "Error: Script file not found: nonexistent_worker.js");
|
||||
is(event.message, ": NetworkError: A network error occurred.");
|
||||
event.preventDefault();
|
||||
SimpleTest.finish();
|
||||
};
|
||||
|
@ -25,7 +25,7 @@ function test(script) {
|
||||
|
||||
worker.onerror = function(event) {
|
||||
is(event.target, worker);
|
||||
is(event.message, "Error: Script file not found: " + script);
|
||||
is(event.message, ": NetworkError: A network error occurred.");
|
||||
event.preventDefault();
|
||||
runTests();
|
||||
};
|
||||
|
@ -142,7 +142,7 @@ function printCommand(rest) {
|
||||
// This is the real deal.
|
||||
var cv = saveExcursion(
|
||||
() => focusedFrame == null
|
||||
? debuggeeGlobalWrapper.evalInGlobalWithBindings(rest, debuggeeValues)
|
||||
? debuggeeGlobalWrapper.executeInGlobalWithBindings(rest, debuggeeValues)
|
||||
: focusedFrame.evalWithBindings(rest, debuggeeValues));
|
||||
if (cv === null) {
|
||||
if (!dbg.enabled)
|
||||
|
@ -382,7 +382,7 @@ code), the call throws a [`Debugger.DebuggeeWouldRun`][wouldrun] exception.
|
||||
the referent is not callable, throw a `TypeError`. This function
|
||||
follows the [invocation function conventions][inv fr].
|
||||
|
||||
<code>evalInGlobal(<i>code</i>, [<i>options</i>])</code>
|
||||
<code>executeInGlobal(<i>code</i>, [<i>options</i>])</code>
|
||||
: If the referent is a global object, evaluate <i>code</i> in that global
|
||||
environment, and return a [completion value][cv] describing how it completed.
|
||||
<i>Code</i> is a string. All extant handler methods, breakpoints,
|
||||
@ -393,15 +393,15 @@ code), the call throws a [`Debugger.DebuggeeWouldRun`][wouldrun] exception.
|
||||
<i>Code</i> is interpreted as strict mode code when it contains a Use
|
||||
Strict Directive.
|
||||
|
||||
If <i>code</i> is not strict mode code, then variable declarations in
|
||||
<i>code</i> affect the referent global object. (In the terms used by the
|
||||
ECMAScript specification, the `VariableEnvironment` of the execution
|
||||
context for the eval code is the referent.)
|
||||
This evaluation is semantically equivalent to executing statements at the
|
||||
global level, not an indirect eval. Regardless of <i>code</i> being strict
|
||||
mode code, variable declarations in <i>code</i> affect the referent global
|
||||
object.
|
||||
|
||||
The <i>options</i> argument is as for [`Debugger.Frame.prototype.eval`][fr eval].
|
||||
|
||||
<code>evalInGlobalWithBindings(<i>code</i>, <i>bindings</i>, [<i>options</i>])</code>
|
||||
: Like `evalInGlobal`, but evaluate <i>code</i> using the referent as the
|
||||
<code>executeInGlobalWithBindings(<i>code</i>, <i>bindings</i>, [<i>options</i>])</code>
|
||||
: Like `executeInGlobal`, but evaluate <i>code</i> using the referent as the
|
||||
variable object, but with a lexical environment extended with bindings
|
||||
from the object <i>bindings</i>. For each own enumerable property of
|
||||
<i>bindings</i> named <i>name</i> whose value is <i>value</i>, include a
|
||||
@ -416,14 +416,12 @@ code), the call throws a [`Debugger.DebuggeeWouldRun`][wouldrun] exception.
|
||||
debuggee values, and do so without mutating any existing debuggee
|
||||
environment.
|
||||
|
||||
Note that, like `evalInGlobal`, if the code passed to
|
||||
`evalInGlobalWithBindings` is not strict mode code, then any
|
||||
declarations it contains affect the referent global object, even as
|
||||
<i>code</i> is evaluated in an environment extended according to
|
||||
<i>bindings</i>. (In the terms used by the ECMAScript specification, the
|
||||
`VariableEnvironment` of the execution context for non-strict eval code
|
||||
is the referent, and the <i>bindings</i> appear in a new declarative
|
||||
environment, which is the eval code's `LexicalEnvironment`.)
|
||||
Note that, like `executeInGlobal`, any declarations it contains affect the
|
||||
referent global object, even as <i>code</i> is evaluated in an environment
|
||||
extended according to <i>bindings</i>. (In the terms used by the ECMAScript
|
||||
specification, the `VariableEnvironment` of the execution context for
|
||||
<i>code</i> is the referent, and the <i>bindings</i> appear in a new
|
||||
declarative environment, which is the eval code's `LexicalEnvironment`.)
|
||||
|
||||
The <i>options</i> argument is as for [`Debugger.Frame.prototype.eval`][fr eval].
|
||||
|
||||
|
@ -74,7 +74,8 @@ class MOZ_STACK_CLASS BytecodeCompiler
|
||||
bool createScript(bool savedCallerFun = false);
|
||||
bool createEmitter(SharedContext* sharedContext, HandleScript evalCaller = nullptr,
|
||||
bool insideNonGlobalEval = false);
|
||||
bool isInsideNonGlobalEval();
|
||||
bool isEvalCompilationUnit();
|
||||
bool isNonGlobalEvalCompilationUnit();
|
||||
bool createParseContext(Maybe<ParseContext<FullParseHandler>>& parseContext,
|
||||
SharedContext& globalsc, uint32_t blockScopeDepth = 0);
|
||||
bool saveCallerFun(HandleScript evalCaller, ParseContext<FullParseHandler>& parseContext);
|
||||
@ -82,7 +83,7 @@ class MOZ_STACK_CLASS BytecodeCompiler
|
||||
Maybe<ParseContext<FullParseHandler>>& parseContext,
|
||||
SharedContext& globalsc);
|
||||
bool handleParseFailure(const Directives& newDirectives);
|
||||
bool prepareAndEmitTree(ParseNode** pn);
|
||||
bool prepareAndEmitTree(ParseNode** pn, ParseContext<FullParseHandler>& pc);
|
||||
bool checkArgumentsWithinEval(JSContext* cx, HandleFunction fun);
|
||||
bool maybeCheckEvalFreeVariables(HandleScript evalCaller, HandleObject scopeChain,
|
||||
ParseContext<FullParseHandler>& pc);
|
||||
@ -275,10 +276,17 @@ BytecodeCompiler::createEmitter(SharedContext* sharedContext, HandleScript evalC
|
||||
return emitter->init();
|
||||
}
|
||||
|
||||
bool BytecodeCompiler::isInsideNonGlobalEval()
|
||||
bool
|
||||
BytecodeCompiler::isEvalCompilationUnit()
|
||||
{
|
||||
return enclosingStaticScope && enclosingStaticScope->is<StaticEvalObject>() &&
|
||||
enclosingStaticScope->as<StaticEvalObject>().enclosingScopeForStaticScopeIter();
|
||||
return enclosingStaticScope && enclosingStaticScope->is<StaticEvalObject>();
|
||||
}
|
||||
|
||||
bool
|
||||
BytecodeCompiler::isNonGlobalEvalCompilationUnit()
|
||||
{
|
||||
return isEvalCompilationUnit() &&
|
||||
enclosingStaticScope->as<StaticEvalObject>().enclosingScopeForStaticScopeIter();
|
||||
}
|
||||
|
||||
bool
|
||||
@ -365,8 +373,13 @@ BytecodeCompiler::handleParseFailure(const Directives& newDirectives)
|
||||
}
|
||||
|
||||
bool
|
||||
BytecodeCompiler::prepareAndEmitTree(ParseNode** ppn)
|
||||
BytecodeCompiler::prepareAndEmitTree(ParseNode** ppn, ParseContext<FullParseHandler>& pc)
|
||||
{
|
||||
// Accumulate the maximum block scope depth, so that emitTree can assert
|
||||
// when emitting JSOP_GETLOCAL that the local is indeed within the fixed
|
||||
// part of the stack frame.
|
||||
script->bindings.updateNumBlockScoped(pc.blockScopeDepth);
|
||||
|
||||
if (!FoldConstants(cx, ppn, parser.ptr()) ||
|
||||
!NameFunctions(cx, *ppn) ||
|
||||
!emitter->updateLocalsToFrameSlots() ||
|
||||
@ -532,7 +545,7 @@ BytecodeCompiler::compileScript(HandleObject scopeChain, HandleScript evalCaller
|
||||
return nullptr;
|
||||
|
||||
GlobalSharedContext globalsc(cx, enclosingStaticScope, directives, options.extraWarningsOption);
|
||||
if (!createEmitter(&globalsc, evalCaller, isInsideNonGlobalEval()))
|
||||
if (!createEmitter(&globalsc, evalCaller, isNonGlobalEvalCompilationUnit()))
|
||||
return nullptr;
|
||||
|
||||
// Syntax parsing may cause us to restart processing of top level
|
||||
@ -545,42 +558,55 @@ BytecodeCompiler::compileScript(HandleObject scopeChain, HandleScript evalCaller
|
||||
if (savedCallerFun && !saveCallerFun(evalCaller, pc.ref()))
|
||||
return nullptr;
|
||||
|
||||
bool canHaveDirectives = true;
|
||||
for (;;) {
|
||||
TokenKind tt;
|
||||
if (!parser->tokenStream.peekToken(&tt, TokenStream::Operand))
|
||||
return nullptr;
|
||||
if (tt == TOK_EOF)
|
||||
break;
|
||||
|
||||
parser->tokenStream.tell(&startPosition);
|
||||
|
||||
ParseNode* pn = parser->statement(YieldIsName, canHaveDirectives);
|
||||
if (!pn) {
|
||||
if (!handleStatementParseFailure(scopeChain, evalCaller, pc, globalsc))
|
||||
// Global scripts are parsed incrementally, statement by statement.
|
||||
//
|
||||
// Eval scripts cannot be, as the block depth needs to be computed for all
|
||||
// lexical bindings in the entire eval script.
|
||||
if (isEvalCompilationUnit()) {
|
||||
ParseNode* pn;
|
||||
do {
|
||||
pn = parser->evalBody();
|
||||
if (!pn && !handleStatementParseFailure(scopeChain, evalCaller, pc, globalsc))
|
||||
return nullptr;
|
||||
} while (!pn);
|
||||
|
||||
pn = parser->statement(YieldIsName);
|
||||
if (!pn) {
|
||||
MOZ_ASSERT(!parser->hadAbortedSyntaxParse());
|
||||
return nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
// Accumulate the maximum block scope depth, so that emitTree can assert
|
||||
// when emitting JSOP_GETLOCAL that the local is indeed within the fixed
|
||||
// part of the stack frame.
|
||||
script->bindings.updateNumBlockScoped(pc->blockScopeDepth);
|
||||
|
||||
if (canHaveDirectives) {
|
||||
if (!parser->maybeParseDirective(/* stmtList = */ nullptr, pn, &canHaveDirectives))
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
if (!prepareAndEmitTree(&pn))
|
||||
if (!prepareAndEmitTree(&pn, *pc))
|
||||
return nullptr;
|
||||
|
||||
parser->handler.freeTree(pn);
|
||||
} else {
|
||||
bool canHaveDirectives = true;
|
||||
for (;;) {
|
||||
TokenKind tt;
|
||||
if (!parser->tokenStream.peekToken(&tt, TokenStream::Operand))
|
||||
return nullptr;
|
||||
if (tt == TOK_EOF)
|
||||
break;
|
||||
|
||||
parser->tokenStream.tell(&startPosition);
|
||||
|
||||
ParseNode* pn = parser->statement(YieldIsName, canHaveDirectives);
|
||||
if (!pn) {
|
||||
if (!handleStatementParseFailure(scopeChain, evalCaller, pc, globalsc))
|
||||
return nullptr;
|
||||
|
||||
pn = parser->statement(YieldIsName);
|
||||
if (!pn) {
|
||||
MOZ_ASSERT(!parser->hadAbortedSyntaxParse());
|
||||
return nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
if (canHaveDirectives) {
|
||||
if (!parser->maybeParseDirective(/* stmtList = */ nullptr, pn, &canHaveDirectives))
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
if (!prepareAndEmitTree(&pn, *pc))
|
||||
return nullptr;
|
||||
|
||||
parser->handler.freeTree(pn);
|
||||
}
|
||||
}
|
||||
|
||||
if (!maybeCheckEvalFreeVariables(evalCaller, scopeChain, *pc) ||
|
||||
|
@ -580,7 +580,7 @@ class NonLocalExitScope {
|
||||
}
|
||||
~NonLocalExitScope() {
|
||||
for (uint32_t n = savedScopeIndex; n < bce->blockScopeList.length(); n++)
|
||||
bce->blockScopeList.recordEnd(n, bce->offset());
|
||||
bce->blockScopeList.recordEnd(n, bce->offset(), bce->inPrologue());
|
||||
bce->stackDepth = savedDepth;
|
||||
}
|
||||
|
||||
@ -588,7 +588,7 @@ class NonLocalExitScope {
|
||||
uint32_t scopeObjectIndex = bce->blockScopeList.findEnclosingScope(blockScopeIndex);
|
||||
uint32_t parent = openScopeIndex;
|
||||
|
||||
if (!bce->blockScopeList.append(scopeObjectIndex, bce->offset(), parent))
|
||||
if (!bce->blockScopeList.append(scopeObjectIndex, bce->offset(), bce->inPrologue(), parent))
|
||||
return false;
|
||||
openScopeIndex = bce->blockScopeList.length() - 1;
|
||||
return true;
|
||||
@ -924,7 +924,7 @@ BytecodeEmitter::enterNestedScope(StmtInfoBCE* stmt, ObjectBox* objbox, StmtType
|
||||
parent = stmt->blockScopeIndex;
|
||||
|
||||
stmt->blockScopeIndex = blockScopeList.length();
|
||||
if (!blockScopeList.append(scopeObjectIndex, offset(), parent))
|
||||
if (!blockScopeList.append(scopeObjectIndex, offset(), inPrologue(), parent))
|
||||
return false;
|
||||
|
||||
pushStatement(stmt, stmtType, offset());
|
||||
@ -980,7 +980,7 @@ BytecodeEmitter::leaveNestedScope(StmtInfoBCE* stmt)
|
||||
return false;
|
||||
}
|
||||
|
||||
blockScopeList.recordEnd(blockScopeIndex, offset());
|
||||
blockScopeList.recordEnd(blockScopeIndex, offset(), inPrologue());
|
||||
|
||||
return true;
|
||||
}
|
||||
@ -1345,6 +1345,23 @@ BytecodeEmitter::emitVarIncDec(ParseNode* pn)
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
BytecodeEmitter::atBodyLevel() const
|
||||
{
|
||||
// 'eval' scripts are always under an invisible lexical scope, but
|
||||
// since it is not syntactic, it should still be considered at body
|
||||
// level.
|
||||
if (sc->staticScope() && sc->staticScope()->is<StaticEvalObject>()) {
|
||||
bool bl = !innermostStmt()->enclosing;
|
||||
MOZ_ASSERT_IF(bl, innermostStmt()->type == StmtType::BLOCK);
|
||||
MOZ_ASSERT_IF(bl, innermostStmt()->staticScope
|
||||
->as<StaticBlockObject>()
|
||||
.maybeEnclosingEval() == sc->staticScope());
|
||||
return bl;
|
||||
}
|
||||
return !innermostStmt() || sc->isModuleBox();
|
||||
}
|
||||
|
||||
uint32_t
|
||||
BytecodeEmitter::computeHops(ParseNode* pn, BytecodeEmitter** bceOfDefOut)
|
||||
{
|
||||
@ -3023,6 +3040,16 @@ bool
|
||||
BytecodeEmitter::enterBlockScope(StmtInfoBCE* stmtInfo, ObjectBox* objbox, JSOp initialValueOp,
|
||||
unsigned alreadyPushed)
|
||||
{
|
||||
// This is so terrible. The eval body-level lexical scope needs to be
|
||||
// emitted in the prologue so DEFFUN can pick up the right scope chain.
|
||||
bool isEvalBodyLexicalScope = sc->staticScope() &&
|
||||
sc->staticScope()->is<StaticEvalObject>() &&
|
||||
!innermostStmt();
|
||||
if (isEvalBodyLexicalScope) {
|
||||
MOZ_ASSERT(code().length() == 0);
|
||||
switchToPrologue();
|
||||
}
|
||||
|
||||
// Initial values for block-scoped locals. Whether it is undefined or the
|
||||
// JS_UNINITIALIZED_LEXICAL magic value depends on the context. The
|
||||
// current way we emit for-in and for-of heads means its let bindings will
|
||||
@ -3037,6 +3064,9 @@ BytecodeEmitter::enterBlockScope(StmtInfoBCE* stmtInfo, ObjectBox* objbox, JSOp
|
||||
if (!initializeBlockScopedLocalsFromStack(blockObj))
|
||||
return false;
|
||||
|
||||
if (isEvalBodyLexicalScope)
|
||||
switchToMain();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@ -5886,7 +5916,7 @@ BytecodeEmitter::emitFunction(ParseNode* pn, bool needsProto)
|
||||
if (sc->isGlobalContext()) {
|
||||
MOZ_ASSERT(pn->pn_scopecoord.isFree());
|
||||
MOZ_ASSERT(pn->getOp() == JSOP_NOP);
|
||||
MOZ_ASSERT(!innermostStmt() || sc->isModuleBox());
|
||||
MOZ_ASSERT(atBodyLevel());
|
||||
switchToPrologue();
|
||||
if (!emitIndex32(JSOP_DEFFUN, index))
|
||||
return false;
|
||||
@ -6365,16 +6395,10 @@ bool
|
||||
BytecodeEmitter::emitStatementList(ParseNode* pn, ptrdiff_t top)
|
||||
{
|
||||
MOZ_ASSERT(pn->isArity(PN_LIST));
|
||||
|
||||
StmtInfoBCE stmtInfo(cx);
|
||||
pushStatement(&stmtInfo, StmtType::BLOCK, top);
|
||||
|
||||
for (ParseNode* pn2 = pn->pn_head; pn2; pn2 = pn2->pn_next) {
|
||||
if (!emitTree(pn2))
|
||||
return false;
|
||||
}
|
||||
|
||||
popStatement();
|
||||
return true;
|
||||
}
|
||||
|
||||
@ -8427,14 +8451,16 @@ CGTryNoteList::finish(TryNoteArray* array)
|
||||
}
|
||||
|
||||
bool
|
||||
CGBlockScopeList::append(uint32_t scopeObject, uint32_t offset, uint32_t parent)
|
||||
CGBlockScopeList::append(uint32_t scopeObject, uint32_t offset, bool inPrologue,
|
||||
uint32_t parent)
|
||||
{
|
||||
BlockScopeNote note;
|
||||
CGBlockScopeNote note;
|
||||
mozilla::PodZero(¬e);
|
||||
|
||||
note.index = scopeObject;
|
||||
note.start = offset;
|
||||
note.parent = parent;
|
||||
note.startInPrologue = inPrologue;
|
||||
|
||||
return list.append(note);
|
||||
}
|
||||
@ -8445,10 +8471,11 @@ CGBlockScopeList::findEnclosingScope(uint32_t index)
|
||||
MOZ_ASSERT(index < length());
|
||||
MOZ_ASSERT(list[index].index != BlockScopeNote::NoBlockScopeIndex);
|
||||
|
||||
DebugOnly<bool> inPrologue = list[index].startInPrologue;
|
||||
DebugOnly<uint32_t> pos = list[index].start;
|
||||
while (index--) {
|
||||
MOZ_ASSERT(list[index].start <= pos);
|
||||
if (list[index].length == 0) {
|
||||
MOZ_ASSERT_IF(inPrologue == list[index].startInPrologue, list[index].start <= pos);
|
||||
if (list[index].end == 0) {
|
||||
// We are looking for the nearest enclosing live scope. If the
|
||||
// scope contains POS, it should still be open, so its length should
|
||||
// be zero.
|
||||
@ -8456,7 +8483,7 @@ CGBlockScopeList::findEnclosingScope(uint32_t index)
|
||||
} else {
|
||||
// Conversely, if the length is not zero, it should not contain
|
||||
// POS.
|
||||
MOZ_ASSERT(list[index].start + list[index].length <= pos);
|
||||
MOZ_ASSERT_IF(inPrologue == list[index].endInPrologue, list[index].end <= pos);
|
||||
}
|
||||
}
|
||||
|
||||
@ -8464,22 +8491,28 @@ CGBlockScopeList::findEnclosingScope(uint32_t index)
|
||||
}
|
||||
|
||||
void
|
||||
CGBlockScopeList::recordEnd(uint32_t index, uint32_t offset)
|
||||
CGBlockScopeList::recordEnd(uint32_t index, uint32_t offset, bool inPrologue)
|
||||
{
|
||||
MOZ_ASSERT(index < length());
|
||||
MOZ_ASSERT(offset >= list[index].start);
|
||||
MOZ_ASSERT(list[index].length == 0);
|
||||
|
||||
list[index].length = offset - list[index].start;
|
||||
list[index].end = offset;
|
||||
list[index].endInPrologue = inPrologue;
|
||||
}
|
||||
|
||||
void
|
||||
CGBlockScopeList::finish(BlockScopeArray* array)
|
||||
CGBlockScopeList::finish(BlockScopeArray* array, uint32_t prologueLength)
|
||||
{
|
||||
MOZ_ASSERT(length() == array->length);
|
||||
|
||||
for (unsigned i = 0; i < length(); i++)
|
||||
for (unsigned i = 0; i < length(); i++) {
|
||||
if (!list[i].startInPrologue)
|
||||
list[i].start += prologueLength;
|
||||
if (!list[i].endInPrologue)
|
||||
list[i].end += prologueLength;
|
||||
list[i].length = list[i].end - list[i].start;
|
||||
array->vector[i] = list[i];
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
|
@ -63,15 +63,28 @@ struct CGTryNoteList {
|
||||
void finish(TryNoteArray* array);
|
||||
};
|
||||
|
||||
struct CGBlockScopeNote : public BlockScopeNote
|
||||
{
|
||||
// The end offset. Used to compute the length; may need adjusting first if
|
||||
// in the prologue.
|
||||
uint32_t end;
|
||||
|
||||
// Is the start offset in the prologue?
|
||||
bool startInPrologue;
|
||||
|
||||
// Is the end offset in the prologue?
|
||||
bool endInPrologue;
|
||||
};
|
||||
|
||||
struct CGBlockScopeList {
|
||||
Vector<BlockScopeNote> list;
|
||||
Vector<CGBlockScopeNote> list;
|
||||
explicit CGBlockScopeList(ExclusiveContext* cx) : list(cx) {}
|
||||
|
||||
bool append(uint32_t scopeObject, uint32_t offset, uint32_t parent);
|
||||
bool append(uint32_t scopeObject, uint32_t offset, bool inPrologue, uint32_t parent);
|
||||
uint32_t findEnclosingScope(uint32_t index);
|
||||
void recordEnd(uint32_t index, uint32_t offset);
|
||||
void recordEnd(uint32_t index, uint32_t offset, bool inPrologue);
|
||||
size_t length() const { return list.length(); }
|
||||
void finish(BlockScopeArray* array);
|
||||
void finish(BlockScopeArray* array, uint32_t prologueLength);
|
||||
};
|
||||
|
||||
struct CGYieldOffsetList {
|
||||
@ -228,6 +241,7 @@ struct BytecodeEmitter
|
||||
return parser->blockScopes[blockid];
|
||||
}
|
||||
|
||||
bool atBodyLevel() const;
|
||||
uint32_t computeHops(ParseNode* pn, BytecodeEmitter** bceOfDefOut);
|
||||
bool isAliasedName(BytecodeEmitter* bceOfDef, ParseNode* pn);
|
||||
bool computeDefinitionIsAliased(BytecodeEmitter* bceOfDef, Definition* dn, JSOp* op);
|
||||
@ -267,6 +281,7 @@ struct BytecodeEmitter
|
||||
ptrdiff_t prologueOffset() const { return prologue.code.end() - prologue.code.begin(); }
|
||||
void switchToMain() { current = &main; }
|
||||
void switchToPrologue() { current = &prologue; }
|
||||
bool inPrologue() const { return current == &prologue; }
|
||||
|
||||
SrcNotesVector& notes() const { return current->notes; }
|
||||
ptrdiff_t lastNoteOffset() const { return current->lastNoteOffset; }
|
||||
|
@ -885,6 +885,39 @@ Parser<SyntaxParseHandler>::standaloneModule(HandleModuleObject module)
|
||||
return SyntaxParseHandler::NodeFailure;
|
||||
}
|
||||
|
||||
template <>
|
||||
ParseNode*
|
||||
Parser<FullParseHandler>::evalBody()
|
||||
{
|
||||
AutoPushStmtInfoPC stmtInfo(*this, StmtType::BLOCK);
|
||||
ParseNode* block = pushLexicalScope(stmtInfo);
|
||||
if (!block)
|
||||
return nullptr;
|
||||
|
||||
// For parsing declarations and directives, eval scripts must be
|
||||
// considered body level despite having a lexical scope.
|
||||
MOZ_ASSERT(pc->atBodyLevel());
|
||||
|
||||
ParseNode* body = statements(YieldIsName);
|
||||
if (!body)
|
||||
return nullptr;
|
||||
|
||||
// The statements() call above breaks on TOK_RC, so make sure we've
|
||||
// reached EOF here.
|
||||
TokenKind tt;
|
||||
if (!tokenStream.peekToken(&tt, TokenStream::Operand))
|
||||
return nullptr;
|
||||
if (tt != TOK_EOF) {
|
||||
report(ParseError, false, null(), JSMSG_UNEXPECTED_TOKEN,
|
||||
"expression", TokenKindToDesc(tt));
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
block->pn_expr = body;
|
||||
block->pn_pos = body->pn_pos;
|
||||
return block;
|
||||
}
|
||||
|
||||
template <>
|
||||
ParseNode*
|
||||
Parser<FullParseHandler>::standaloneFunctionBody(HandleFunction fun,
|
||||
@ -4296,7 +4329,7 @@ Parser<FullParseHandler>::checkAndPrepareLexical(bool isConst, const TokenPos& e
|
||||
static StaticBlockObject*
|
||||
CurrentLexicalStaticBlock(ParseContext<FullParseHandler>* pc)
|
||||
{
|
||||
return pc->atBodyLevel() ? nullptr :
|
||||
return !pc->innermostStmt() ? nullptr :
|
||||
&pc->innermostStmt()->staticScope->as<StaticBlockObject>();
|
||||
}
|
||||
|
||||
|
@ -302,6 +302,17 @@ struct MOZ_STACK_CLASS ParseContext : public GenericParseContext
|
||||
// if (cond) { function f3() { if (cond) { function f4() { } } } }
|
||||
//
|
||||
bool atBodyLevel() {
|
||||
// 'eval' scripts are always under an invisible lexical scope, but
|
||||
// since it is not syntactic, it should still be considered at body
|
||||
// level.
|
||||
if (sc->staticScope() && sc->staticScope()->is<StaticEvalObject>()) {
|
||||
bool bl = !innermostStmt()->enclosing;
|
||||
MOZ_ASSERT_IF(bl, innermostStmt()->type == StmtType::BLOCK);
|
||||
MOZ_ASSERT_IF(bl, innermostStmt()->staticScope
|
||||
->template as<StaticBlockObject>()
|
||||
.maybeEnclosingEval() == sc->staticScope());
|
||||
return bl;
|
||||
}
|
||||
return !innermostStmt();
|
||||
}
|
||||
|
||||
@ -560,6 +571,12 @@ class Parser : private JS::AutoGCRooter, public StrictModeGetter
|
||||
|
||||
bool maybeParseDirective(Node list, Node pn, bool* cont);
|
||||
|
||||
// Parse the body of an eval. It is distinguished from global scripts in
|
||||
// that in ES6, per 18.2.1.1 steps 9 and 10, all eval scripts are executed
|
||||
// under a fresh lexical scope.
|
||||
Node evalBody();
|
||||
|
||||
// Parse a module.
|
||||
Node standaloneModule(Handle<ModuleObject*> module);
|
||||
|
||||
// Parse a function, given only its body. Used for the Function and
|
||||
|
@ -6,7 +6,7 @@ var dbg = new Debugger;
|
||||
var log;
|
||||
dbg.onEnterFrame = function (frame) {
|
||||
log += 'e';
|
||||
log += frame.environment.object.label;
|
||||
log += frame.environment.parent.object.label;
|
||||
};
|
||||
|
||||
var g1 = newGlobal();
|
||||
|
@ -1,4 +1,4 @@
|
||||
// Bug 744731 - findScripts() finds active debugger evalInGlobal scripts.
|
||||
// Bug 744731 - findScripts() finds active debugger executeInGlobal scripts.
|
||||
|
||||
var g = newGlobal();
|
||||
var dbg = new Debugger;
|
||||
@ -8,5 +8,5 @@ dbg.onDebuggerStatement = function (frame) {
|
||||
hits++;
|
||||
assertEq(dbg.findScripts().indexOf(dbg.getNewestFrame().script) !== -1, true);
|
||||
};
|
||||
gw.evalInGlobal("debugger;");
|
||||
gw.executeInGlobal("debugger;");
|
||||
assertEq(hits, 1);
|
||||
|
@ -7,9 +7,9 @@ dbg.onNewGlobalObject = function (global) {
|
||||
var gw = dbg.addDebuggee(global);
|
||||
gw.defineProperty('x', { value: -1 });
|
||||
// Check that the global's magic lazy properties are working.
|
||||
assertEq(gw.evalInGlobalWithBindings('Math.atan2(y,x)', { y: 0 }).return, Math.PI);
|
||||
assertEq(gw.executeInGlobalWithBindings('Math.atan2(y,x)', { y: 0 }).return, Math.PI);
|
||||
// Check that the global's prototype is hooked up.
|
||||
assertEq(gw.evalInGlobalWithBindings('x.toString()', { x: gw }).return, "[object global]");
|
||||
assertEq(gw.executeInGlobalWithBindings('x.toString()', { x: gw }).return, "[object global]");
|
||||
};
|
||||
|
||||
newGlobal();
|
||||
|
@ -19,7 +19,7 @@ function check(code, expectedType, expectedCallee) {
|
||||
assertEq(hits, 1);
|
||||
}
|
||||
|
||||
check('debugger;', 'object', null);
|
||||
check('debugger;', 'declarative', null);
|
||||
check('with({}) { debugger; };', 'with', null);
|
||||
check('let (x=1) { debugger; };', 'declarative', null);
|
||||
|
||||
@ -30,16 +30,13 @@ g.eval('function g() { h(); }');
|
||||
g.eval('function h() { debugger; }');
|
||||
check('g()', 'declarative', gw.makeDebuggeeValue(g.h));
|
||||
|
||||
// Strict direct eval gets its own environment.
|
||||
// All evals get a lexical scope.
|
||||
check('"use strict"; eval("debugger");', 'declarative', null);
|
||||
g.eval('function j() { "use strict"; eval("debugger;"); }');
|
||||
check('j()', 'declarative', null);
|
||||
|
||||
// Lenient direct eval shares eval's caller's environment,
|
||||
// although this is a great evil.
|
||||
check('eval("debugger");', 'object', null);
|
||||
g.eval('function k() { eval("debugger;"); }');
|
||||
check('k()', 'declarative', gw.makeDebuggeeValue(g.k));
|
||||
// All evals get a lexical scope.
|
||||
check('eval("debugger");', 'declarative', null);
|
||||
|
||||
g.eval('function m() { debugger; yield true; }');
|
||||
check('m().next();', 'declarative', gw.makeDebuggeeValue(g.m));
|
||||
|
@ -4,7 +4,7 @@ var g = newGlobal();
|
||||
var dbg = Debugger(g);
|
||||
var log = '';
|
||||
dbg.onDebuggerStatement = function (frame) {
|
||||
log += frame.environment.getVariable("x") + frame.environment.getVariable("y");
|
||||
log += frame.environment.parent.getVariable("x") + frame.environment.parent.getVariable("y");
|
||||
};
|
||||
g.eval("var x = 'a'; this.y = 'b'; debugger;");
|
||||
assertEq(log, 'ab');
|
||||
|
@ -4,7 +4,7 @@ var g = newGlobal();
|
||||
var dbg = Debugger(g);
|
||||
var log = '';
|
||||
dbg.onDebuggerStatement = function (frame) {
|
||||
log += frame.environment.getVariable("x") + frame.environment.getVariable("y");
|
||||
log += frame.environment.parent.getVariable("x") + frame.environment.parent.getVariable("y");
|
||||
};
|
||||
g.eval("Object.getPrototypeOf(this).x = 'a';\n" +
|
||||
"Object.prototype.y = 'b';\n" +
|
||||
|
@ -5,7 +5,7 @@ var dbg = new Debugger;
|
||||
var gw = dbg.addDebuggee(g);
|
||||
var hits = 0;
|
||||
dbg.onDebuggerStatement = function (frame) {
|
||||
var a = frame.environment.getVariable('Math');
|
||||
var a = frame.environment.parent.getVariable('Math');
|
||||
assertEq(a instanceof Debugger.Object, true);
|
||||
var b = gw.getOwnPropertyDescriptor('Math').value;
|
||||
assertEq(a, b);
|
||||
|
@ -5,7 +5,7 @@ var gw = dbg.addDebuggee(g);
|
||||
var hits = 0;
|
||||
dbg.onDebuggerStatement = function (frame) {
|
||||
hits++;
|
||||
assertEq(frame.environment.parent.getVariable('y'), true);
|
||||
assertEq(frame.environment.parent.parent.getVariable('y'), true);
|
||||
};
|
||||
|
||||
g.eval("var g;" +
|
||||
|
@ -8,7 +8,7 @@ var dbg = Debugger(g);
|
||||
var hits = 0;
|
||||
dbg.onDebuggerStatement = function (frame) {
|
||||
assertThrowsInstanceOf(function () {
|
||||
frame.environment.getVariable("x");
|
||||
frame.environment.parent.getVariable("x");
|
||||
}, Error);
|
||||
hits++;
|
||||
};
|
||||
|
@ -51,7 +51,7 @@ function test(sharedName, expectedHits, code) {
|
||||
// the optimization or with the debugger exposing it, but that's not what we
|
||||
// want to test here.)
|
||||
|
||||
test("q", 2, "var q = function (a) { h(); }; q(1); q(2);");
|
||||
test("q", 2, "let q = function (a) { h(); }; q(1); q(2);");
|
||||
test("a", 2, "q = function (a) { (function (b) { h(); a = b; })(2); h(); }; q(1);");
|
||||
test("a", 2, "q = function (a) { h(); return function (b) { h(); a = b; }; }; q(1)(2);");
|
||||
test("n", 3, "q = function (n) { for (var i = 0; i < n; i++) { let (j = i) { h(); } } }; q(3);");
|
||||
|
@ -45,7 +45,8 @@ function debuggerHandler(frame) {
|
||||
assertEq(ke.inspectable, true);
|
||||
assertEq(ke.getVariable('xk'), 'value of xk');
|
||||
assertEq(ee.inspectable, true);
|
||||
assertEq(ee.type, 'object');
|
||||
assertEq(ee.type, 'declarative');
|
||||
assertEq(ee.parent.type, 'object');
|
||||
|
||||
dbg.removeDebuggee(g2);
|
||||
|
||||
@ -54,7 +55,8 @@ function debuggerHandler(frame) {
|
||||
assertEq(ke.inspectable, false);
|
||||
assertThrowsInstanceOf(() => ke.getVariable('xk'), Error);
|
||||
assertEq(ee.inspectable, true);
|
||||
assertEq(ee.type, 'object');
|
||||
assertEq(ee.type, 'declarative');
|
||||
assertEq(ee.parent.type, 'object');
|
||||
|
||||
dbg.removeDebuggee(g1);
|
||||
|
||||
|
@ -35,6 +35,6 @@ assertEq(log, 'd');
|
||||
dbg.addDebuggee(g);
|
||||
g.eval('function f() { }');
|
||||
let env = gw.getOwnPropertyDescriptor('f').value.environment;
|
||||
assertEq(env.type, 'object');
|
||||
assertEq(env.type, 'declarative');
|
||||
dbg.removeDebuggee(g);
|
||||
check(env);
|
||||
|
@ -28,7 +28,7 @@ dbg.onEnterFrame = function (f) {
|
||||
assertEq(funenv.callee, f.older.callee);
|
||||
assertEq(funenv.names().indexOf("x") !== -1, true);
|
||||
|
||||
globalenv = funenv.parent;
|
||||
globalenv = funenv.parent.parent;
|
||||
assertEq(globalenv.optimizedOut, false);
|
||||
assertEq(globalenv.inspectable, true);
|
||||
assertEq(globalenv.type, "object");
|
||||
|
@ -3,7 +3,7 @@
|
||||
var g = newGlobal();
|
||||
var dbg = Debugger(g);
|
||||
dbg.onDebuggerStatement = function (frame) {
|
||||
frame.environment.setVariable("x", 2);
|
||||
frame.environment.parent.setVariable("x", 2);
|
||||
};
|
||||
g.eval("var x = 1; debugger;");
|
||||
assertEq(g.x, 2);
|
||||
|
@ -4,7 +4,7 @@ var g = newGlobal();
|
||||
var dbg = new Debugger;
|
||||
var gw = dbg.addDebuggee(g);
|
||||
dbg.onDebuggerStatement = function (frame) {
|
||||
frame.environment.setVariable("x", gw);
|
||||
frame.environment.parent.setVariable("x", gw);
|
||||
};
|
||||
g.eval("var x = 1; debugger;");
|
||||
assertEq(g.x, g);
|
||||
|
@ -9,7 +9,7 @@ function test(code, expected) {
|
||||
assertEq(actual, expected);
|
||||
}
|
||||
|
||||
test("h();", 'object');
|
||||
test("h();", 'declarative');
|
||||
test("(function (s) { eval(s); })('var v = h();')", 'declarative');
|
||||
test("(function (s) { h(); })();", 'declarative');
|
||||
test("{let x = 1, y = 2; h();}", 'declarative');
|
||||
@ -17,7 +17,7 @@ test("with({x: 1, y: 2}) h();", 'with');
|
||||
test("(function (s) { with ({x: 1, y: 2}) h(); })();", 'with');
|
||||
test("let (x = 1) { h(); }", 'declarative');
|
||||
test("for (let x = 0; x < 1; x++) h();", 'declarative');
|
||||
test("for (let x in h()) ;", 'object');
|
||||
test("for (let x in h()) ;", 'declarative');
|
||||
test("for (let x in {a:1}) h();", 'declarative');
|
||||
test("try { throw new Error; } catch (x) { h(x) }", 'declarative');
|
||||
test("'use strict'; eval('var z = 1; h();');", 'declarative');
|
||||
@ -33,5 +33,5 @@ test("for (var x in (0 for (m in h()))) ;", 'declarative');
|
||||
dbg.onDebuggerStatement = function (frame) {
|
||||
assertEq(frame.eval("h(), 2 + 2;").return, 4);
|
||||
}
|
||||
test("debugger;", 'object');
|
||||
test("debugger;", 'declarative');
|
||||
test("(function f() { debugger; })();", 'declarative');
|
||||
|
@ -4,7 +4,7 @@ var g = newGlobal();
|
||||
var dbg = new Debugger;
|
||||
var gw = dbg.addDebuggee(g);
|
||||
g.h = function () {
|
||||
var env = dbg.getNewestFrame().environment;
|
||||
var env = dbg.getNewestFrame().environment.parent;
|
||||
assertEq(env instanceof Debugger.Environment, true);
|
||||
assertEq(env.object, gw);
|
||||
assertEq(env.parent, null);
|
||||
|
@ -14,7 +14,7 @@ dbg.onDebuggerStatement = function handleDebugger(frame) {
|
||||
};
|
||||
g.eval("function g() { for (var i = 0; i < 10; i++) { debugger; yield i; } }");
|
||||
g.eval("var it = g();");
|
||||
var rv = gw.evalInGlobal("it.next();");
|
||||
var rv = gw.executeInGlobal("it.next();");
|
||||
assertEq(rv.throw, "fit");
|
||||
|
||||
dbg.enabled = false;
|
||||
|
@ -13,7 +13,7 @@ dbg.onDebuggerStatement = function handleDebugger(frame) {
|
||||
};
|
||||
g.eval("function g() { for (var i = 0; i < 10; i++) { debugger; yield i; } }");
|
||||
g.eval("var it = g();");
|
||||
assertEq(gw.evalInGlobal("it.next();"), null);
|
||||
assertEq(gw.executeInGlobal("it.next();"), null);
|
||||
|
||||
dbg.enabled = false;
|
||||
assertEq(g.it.next(), 1);
|
||||
|
@ -45,7 +45,7 @@ var frames = [];
|
||||
|
||||
// We start off the test via Debugger.Frame.prototype.eval, so if we end
|
||||
// with a termination, we still catch it, instead of aborting the whole
|
||||
// test. (Debugger.Object.prototype.evalInGlobal would simplify this...)
|
||||
// test. (Debugger.Object.prototype.executeInGlobal would simplify this...)
|
||||
var dbg0 = new Debugger(g);
|
||||
dbg0.onEnterFrame = function handleOriginalEnter(frame) {
|
||||
dbg0.log += '(';
|
||||
|
@ -13,7 +13,7 @@ dbg.onDebuggerStatement = function handleDebugger(frame) {
|
||||
};
|
||||
g.eval("function* g() { for (var i = 0; i < 10; i++) { debugger; yield i; } }");
|
||||
g.eval("var it = g();");
|
||||
var rv = gw.evalInGlobal("it.next();");
|
||||
var rv = gw.executeInGlobal("it.next();");
|
||||
assertEq(rv.throw, "fit");
|
||||
|
||||
dbg.enabled = false;
|
||||
|
@ -15,7 +15,7 @@ dbg.onDebuggerStatement = function handleDebugger(frame) {
|
||||
};
|
||||
g.eval("function* g() { for (var i = 0; i < 10; i++) { debugger; yield i; } }");
|
||||
g.eval("var it = g();");
|
||||
assertEq(gw.evalInGlobal("it.next();"), null);
|
||||
assertEq(gw.executeInGlobal("it.next();"), null);
|
||||
|
||||
dbg.enabled = false;
|
||||
assertIteratorNext(g.it, 1);
|
||||
|
@ -6,7 +6,7 @@ let dbg = new Debugger(g);
|
||||
let sizeOfAM = byteSize(allocationMarker());
|
||||
|
||||
// Allocate a single allocation marker, and check that we can find it.
|
||||
g.eval('let hold = allocationMarker();');
|
||||
g.eval('var hold = allocationMarker();');
|
||||
let census = dbg.memory.takeCensus({ breakdown: { by: 'objectClass' } });
|
||||
assertEq(census.AllocationMarker.count, 1);
|
||||
assertEq(census.AllocationMarker.bytes, sizeOfAM);
|
||||
|
@ -3,13 +3,13 @@
|
||||
var g = newGlobal();
|
||||
var dbg = new Debugger;
|
||||
var gw = dbg.addDebuggee(g);
|
||||
var arrw = gw.evalInGlobal("var arr = []; arr;").return;
|
||||
var pushw = gw.evalInGlobal("var push = arr.push.bind(arr); push;").return;
|
||||
var arrw = gw.executeInGlobal("var arr = []; arr;").return;
|
||||
var pushw = gw.executeInGlobal("var push = arr.push.bind(arr); push;").return;
|
||||
assertEq(pushw.isBoundFunction, true);
|
||||
assertEq(pushw.boundThis, arrw);
|
||||
assertEq(pushw.boundArguments.length, 0);
|
||||
|
||||
var arr2 = gw.evalInGlobal("var arr2 = []; arr2").return;
|
||||
var arr2 = gw.executeInGlobal("var arr2 = []; arr2").return;
|
||||
assertEq(pushw.call(arr2, "tuesday").return, 1);
|
||||
g.eval("assertEq(arr.length, 1);");
|
||||
g.eval("assertEq(arr[0], 'tuesday');");
|
||||
|
@ -6,19 +6,19 @@
|
||||
var g = newGlobal();
|
||||
var dbg = new Debugger;
|
||||
var gw = dbg.addDebuggee(g);
|
||||
var fw = gw.evalInGlobal("function f() {}; f").return;
|
||||
var fw = gw.executeInGlobal("function f() {}; f").return;
|
||||
assertEq(fw.isBoundFunction, false);
|
||||
assertEq(fw.boundThis, undefined);
|
||||
assertEq(fw.boundArguments, undefined);
|
||||
assertEq(fw.boundTargetFunction, undefined);
|
||||
|
||||
var nw = gw.evalInGlobal("var n = Math.max; n").return;
|
||||
var nw = gw.executeInGlobal("var n = Math.max; n").return;
|
||||
assertEq(nw.isBoundFunction, false);
|
||||
assertEq(nw.boundThis, undefined);
|
||||
assertEq(nw.boundArguments, undefined);
|
||||
assertEq(nw.boundTargetFunction, undefined);
|
||||
|
||||
var ow = gw.evalInGlobal("var o = {}; o").return;
|
||||
var ow = gw.executeInGlobal("var o = {}; o").return;
|
||||
assertEq(ow.isBoundFunction, false);
|
||||
assertEq(ow.boundThis, undefined);
|
||||
assertEq(ow.boundArguments, undefined);
|
||||
|
@ -5,7 +5,7 @@ var g = newGlobal();
|
||||
var dbg = new Debugger();
|
||||
var gw = dbg.addDebuggee(g);
|
||||
var expr = "function f() { return this; }; var bf = f.bind(1, 2).bind(3, 4); bf";
|
||||
var bfw = gw.evalInGlobal(expr).return;
|
||||
var bfw = gw.executeInGlobal(expr).return;
|
||||
|
||||
assertEq(bfw.isBoundFunction, true);
|
||||
assertEq(bfw.boundThis, 3);
|
||||
|
@ -1,20 +0,0 @@
|
||||
// Debugger.Object.prototype.evalInGlobal argument validation
|
||||
|
||||
load(libdir + 'asserts.js');
|
||||
|
||||
var g = newGlobal();
|
||||
var dbg = new Debugger();
|
||||
var gw = dbg.addDebuggee(g);
|
||||
var gobj = gw.makeDebuggeeValue(g.eval("({})"));
|
||||
|
||||
assertThrowsInstanceOf(function () { gw.evalInGlobal(); }, TypeError);
|
||||
assertThrowsInstanceOf(function () { gw.evalInGlobal(10); }, TypeError);
|
||||
assertThrowsInstanceOf(function () { gobj.evalInGlobal('42'); }, TypeError);
|
||||
assertEq(gw.evalInGlobal('42').return, 42);
|
||||
|
||||
assertThrowsInstanceOf(function () { gw.evalInGlobalWithBindings(); }, TypeError);
|
||||
assertThrowsInstanceOf(function () { gw.evalInGlobalWithBindings('42'); }, TypeError);
|
||||
assertThrowsInstanceOf(function () { gw.evalInGlobalWithBindings(10, 1729); }, TypeError);
|
||||
assertThrowsInstanceOf(function () { gw.evalInGlobalWithBindings('42', 1729); }, TypeError);
|
||||
assertThrowsInstanceOf(function () { gobj.evalInGlobalWithBindings('42', {}); }, TypeError);
|
||||
assertEq(gw.evalInGlobalWithBindings('42', {}).return, 42);
|
@ -1,19 +0,0 @@
|
||||
// Debugger.Object.prototype.evalInGlobal: closures capturing the global
|
||||
|
||||
var g = newGlobal();
|
||||
var h = newGlobal();
|
||||
var dbg = new Debugger;
|
||||
var gw = dbg.addDebuggee(g);
|
||||
var hw = dbg.addDebuggee(h);
|
||||
|
||||
g.x = "W H O K I L L";
|
||||
h.x = "No Color";
|
||||
var c1 = gw.evalInGlobal('(function () { return x; })').return;
|
||||
var c2 = hw.evalInGlobal('(function () { return x; })').return;
|
||||
var c3 = gw.evalInGlobalWithBindings('(function () { return x + y; })', { y:" In Rainbows" }).return;
|
||||
var c4 = hw.evalInGlobalWithBindings('(function () { return x + y; })', { y:" In Rainbows" }).return;
|
||||
|
||||
assertEq(c1.call(null).return, "W H O K I L L");
|
||||
assertEq(c2.call(null).return, "No Color");
|
||||
assertEq(c3.call(null).return, "W H O K I L L In Rainbows");
|
||||
assertEq(c4.call(null).return, "No Color In Rainbows");
|
@ -1,55 +0,0 @@
|
||||
// Debugger.Object.prototype.evalInGlobal: nested evals
|
||||
|
||||
var g = newGlobal();
|
||||
var dbg = new Debugger;
|
||||
var gw = dbg.addDebuggee(g);
|
||||
|
||||
assertEq(gw.evalInGlobal("eval('\"Awake\"');").return, "Awake");
|
||||
|
||||
// Evaluating non-strict-mode code uses the given global as its variable
|
||||
// environment.
|
||||
g.x = "Swing Lo Magellan";
|
||||
g.y = "The Milk-Eyed Mender";
|
||||
assertEq(gw.evalInGlobal("eval('var x = \"A Brief History of Love\"');\n"
|
||||
+ "var y = 'Merriweather Post Pavilion';"
|
||||
+ "x;").return,
|
||||
"A Brief History of Love");
|
||||
assertEq(g.x, "A Brief History of Love");
|
||||
assertEq(g.y, "Merriweather Post Pavilion");
|
||||
|
||||
// As above, but notice that we still create bindings on the global, even
|
||||
// when we've interposed a new environment via 'withBindings'.
|
||||
g.x = "Swing Lo Magellan";
|
||||
g.y = "The Milk-Eyed Mender";
|
||||
assertEq(gw.evalInGlobalWithBindings("eval('var x = d1;'); var y = d2; x;",
|
||||
{ d1: "A Brief History of Love",
|
||||
d2: "Merriweather Post Pavilion" }).return,
|
||||
"A Brief History of Love");
|
||||
assertEq(g.x, "A Brief History of Love");
|
||||
assertEq(g.y, "Merriweather Post Pavilion");
|
||||
|
||||
|
||||
// Strict mode code variants of the above:
|
||||
|
||||
// Evaluating strict-mode code uses a fresh call object as its variable environment.
|
||||
// Also, calls to eval from strict-mode code run the eval code in a fresh
|
||||
// call object.
|
||||
g.x = "Swing Lo Magellan";
|
||||
g.y = "The Milk-Eyed Mender";
|
||||
assertEq(gw.evalInGlobal("\'use strict\';\n"
|
||||
+ "eval('var x = \"A Brief History of Love\"');\n"
|
||||
+ "var y = \"Merriweather Post Pavilion\";"
|
||||
+ "x;").return,
|
||||
"Swing Lo Magellan");
|
||||
assertEq(g.x, "Swing Lo Magellan");
|
||||
assertEq(g.y, "The Milk-Eyed Mender");
|
||||
|
||||
// Introducing a bindings object shouldn't change this behavior.
|
||||
g.x = "Swing Lo Magellan";
|
||||
g.y = "The Milk-Eyed Mender";
|
||||
assertEq(gw.evalInGlobalWithBindings("'use strict'; eval('var x = d1;'); var y = d2; x;",
|
||||
{ d1: "A Brief History of Love",
|
||||
d2: "Merriweather Post Pavilion" }).return,
|
||||
"Swing Lo Magellan");
|
||||
assertEq(g.x, "Swing Lo Magellan");
|
||||
assertEq(g.y, "The Milk-Eyed Mender");
|
@ -1,22 +0,0 @@
|
||||
// Debugger.Object.prototype.evalInGlobal throws when asked to evaluate in a CCW of a global.
|
||||
|
||||
load(libdir + 'asserts.js');
|
||||
|
||||
var dbg = new Debugger();
|
||||
|
||||
var g1 = newGlobal();
|
||||
var dg1 = dbg.addDebuggee(g1);
|
||||
|
||||
var g2 = newGlobal();
|
||||
var dg2 = dbg.addDebuggee(g2);
|
||||
|
||||
// Generate a Debugger.Object viewing g2 from g1's compartment.
|
||||
var dg1wg2 = dg1.makeDebuggeeValue(g2);
|
||||
assertEq(dg1wg2.global, dg1);
|
||||
assertEq(dg1wg2.unwrap(), dg2);
|
||||
assertThrowsInstanceOf(function () { dg1wg2.evalInGlobal('1'); }, TypeError);
|
||||
assertThrowsInstanceOf(function () { dg1wg2.evalInGlobalWithBindings('x', { x: 1 }); }, TypeError);
|
||||
|
||||
// These, however, should not throw.
|
||||
assertEq(dg1wg2.unwrap().evalInGlobal('1729').return, 1729);
|
||||
assertEq(dg1wg2.unwrap().evalInGlobalWithBindings('x', { x: 1729 }).return, 1729);
|
@ -1,8 +0,0 @@
|
||||
// Debugger.Object.prototype.evalInGlobal sets 'this' to the global.
|
||||
|
||||
var dbg = new Debugger;
|
||||
var g1 = newGlobal();
|
||||
var g1w = dbg.addDebuggee(g1);
|
||||
|
||||
assertEq(g1w.evalInGlobal('this').return, g1w);
|
||||
assertEq(g1w.evalInGlobalWithBindings('this', { x:42 }).return, g1w);
|
@ -1,9 +0,0 @@
|
||||
// The frame created for evalInGlobal is never marked as a 'FUNCTION' frame.
|
||||
|
||||
(function () {
|
||||
var g = newGlobal();
|
||||
var dbg = new Debugger;
|
||||
var gw = dbg.addDebuggee(g);
|
||||
gw.evalInGlobalWithBindings("eval('Math')",{}).return
|
||||
})();
|
||||
|
@ -1,4 +1,4 @@
|
||||
// Debugger.Object.prototype.evalInGlobal basics
|
||||
// Debugger.Object.prototype.executeInGlobal basics
|
||||
|
||||
var g = newGlobal();
|
||||
var h = newGlobal();
|
||||
@ -9,5 +9,5 @@ var hw = dbg.addDebuggee(h);
|
||||
g.y = "Bitte Orca";
|
||||
h.y = "Visiter";
|
||||
var y = "W H O K I L L";
|
||||
assertEq(gw.evalInGlobal('y').return, "Bitte Orca");
|
||||
assertEq(hw.evalInGlobal('y').return, "Visiter");
|
||||
assertEq(gw.executeInGlobal('y').return, "Bitte Orca");
|
||||
assertEq(hw.executeInGlobal('y').return, "Visiter");
|
20
js/src/jit-test/tests/debug/Object-executeInGlobal-02.js
Normal file
20
js/src/jit-test/tests/debug/Object-executeInGlobal-02.js
Normal file
@ -0,0 +1,20 @@
|
||||
// Debugger.Object.prototype.executeInGlobal argument validation
|
||||
|
||||
load(libdir + 'asserts.js');
|
||||
|
||||
var g = newGlobal();
|
||||
var dbg = new Debugger();
|
||||
var gw = dbg.addDebuggee(g);
|
||||
var gobj = gw.makeDebuggeeValue(g.eval("({})"));
|
||||
|
||||
assertThrowsInstanceOf(function () { gw.executeInGlobal(); }, TypeError);
|
||||
assertThrowsInstanceOf(function () { gw.executeInGlobal(10); }, TypeError);
|
||||
assertThrowsInstanceOf(function () { gobj.executeInGlobal('42'); }, TypeError);
|
||||
assertEq(gw.executeInGlobal('42').return, 42);
|
||||
|
||||
assertThrowsInstanceOf(function () { gw.executeInGlobalWithBindings(); }, TypeError);
|
||||
assertThrowsInstanceOf(function () { gw.executeInGlobalWithBindings('42'); }, TypeError);
|
||||
assertThrowsInstanceOf(function () { gw.executeInGlobalWithBindings(10, 1729); }, TypeError);
|
||||
assertThrowsInstanceOf(function () { gw.executeInGlobalWithBindings('42', 1729); }, TypeError);
|
||||
assertThrowsInstanceOf(function () { gobj.executeInGlobalWithBindings('42', {}); }, TypeError);
|
||||
assertEq(gw.executeInGlobalWithBindings('42', {}).return, 42);
|
19
js/src/jit-test/tests/debug/Object-executeInGlobal-03.js
Normal file
19
js/src/jit-test/tests/debug/Object-executeInGlobal-03.js
Normal file
@ -0,0 +1,19 @@
|
||||
// Debugger.Object.prototype.executeInGlobal: closures capturing the global
|
||||
|
||||
var g = newGlobal();
|
||||
var h = newGlobal();
|
||||
var dbg = new Debugger;
|
||||
var gw = dbg.addDebuggee(g);
|
||||
var hw = dbg.addDebuggee(h);
|
||||
|
||||
g.x = "W H O K I L L";
|
||||
h.x = "No Color";
|
||||
var c1 = gw.executeInGlobal('(function () { return x; })').return;
|
||||
var c2 = hw.executeInGlobal('(function () { return x; })').return;
|
||||
var c3 = gw.executeInGlobalWithBindings('(function () { return x + y; })', { y:" In Rainbows" }).return;
|
||||
var c4 = hw.executeInGlobalWithBindings('(function () { return x + y; })', { y:" In Rainbows" }).return;
|
||||
|
||||
assertEq(c1.call(null).return, "W H O K I L L");
|
||||
assertEq(c2.call(null).return, "No Color");
|
||||
assertEq(c3.call(null).return, "W H O K I L L In Rainbows");
|
||||
assertEq(c4.call(null).return, "No Color In Rainbows");
|
55
js/src/jit-test/tests/debug/Object-executeInGlobal-04.js
Normal file
55
js/src/jit-test/tests/debug/Object-executeInGlobal-04.js
Normal file
@ -0,0 +1,55 @@
|
||||
// Debugger.Object.prototype.executeInGlobal: nested evals
|
||||
|
||||
var g = newGlobal();
|
||||
var dbg = new Debugger;
|
||||
var gw = dbg.addDebuggee(g);
|
||||
|
||||
assertEq(gw.executeInGlobal("eval('\"Awake\"');").return, "Awake");
|
||||
|
||||
// Evaluating non-strict-mode code uses the given global as its variable
|
||||
// environment.
|
||||
g.x = "Swing Lo Magellan";
|
||||
g.y = "The Milk-Eyed Mender";
|
||||
assertEq(gw.executeInGlobal("eval('var x = \"A Brief History of Love\"');\n"
|
||||
+ "var y = 'Merriweather Post Pavilion';"
|
||||
+ "x;").return,
|
||||
"A Brief History of Love");
|
||||
assertEq(g.x, "A Brief History of Love");
|
||||
assertEq(g.y, "Merriweather Post Pavilion");
|
||||
|
||||
// As above, but notice that we still create bindings on the global, even
|
||||
// when we've interposed a new environment via 'withBindings'.
|
||||
g.x = "Swing Lo Magellan";
|
||||
g.y = "The Milk-Eyed Mender";
|
||||
assertEq(gw.executeInGlobalWithBindings("eval('var x = d1;'); var y = d2; x;",
|
||||
{ d1: "A Brief History of Love",
|
||||
d2: "Merriweather Post Pavilion" }).return,
|
||||
"A Brief History of Love");
|
||||
assertEq(g.x, "A Brief History of Love");
|
||||
assertEq(g.y, "Merriweather Post Pavilion");
|
||||
|
||||
|
||||
// Strict mode code variants of the above:
|
||||
|
||||
// Strict mode still lets us create bindings on the global as this is
|
||||
// equivalent to executing statements at the global level. But note that
|
||||
// setting strict mode means that nested evals get their own call objects.
|
||||
g.x = "Swing Lo Magellan";
|
||||
g.y = "The Milk-Eyed Mender";
|
||||
assertEq(gw.executeInGlobal("\'use strict\';\n"
|
||||
+ "eval('var x = \"A Brief History of Love\"');\n"
|
||||
+ "var y = \"Merriweather Post Pavilion\";"
|
||||
+ "x;").return,
|
||||
"Swing Lo Magellan");
|
||||
assertEq(g.x, "Swing Lo Magellan");
|
||||
assertEq(g.y, "Merriweather Post Pavilion");
|
||||
|
||||
// Introducing a bindings object shouldn't change this behavior.
|
||||
g.x = "Swing Lo Magellan";
|
||||
g.y = "The Milk-Eyed Mender";
|
||||
assertEq(gw.executeInGlobalWithBindings("'use strict'; eval('var x = d1;'); var y = d2; x;",
|
||||
{ d1: "A Brief History of Love",
|
||||
d2: "Merriweather Post Pavilion" }).return,
|
||||
"Swing Lo Magellan");
|
||||
assertEq(g.x, "Swing Lo Magellan");
|
||||
assertEq(g.y, "Merriweather Post Pavilion");
|
22
js/src/jit-test/tests/debug/Object-executeInGlobal-05.js
Normal file
22
js/src/jit-test/tests/debug/Object-executeInGlobal-05.js
Normal file
@ -0,0 +1,22 @@
|
||||
// Debugger.Object.prototype.executeInGlobal throws when asked to evaluate in a CCW of a global.
|
||||
|
||||
load(libdir + 'asserts.js');
|
||||
|
||||
var dbg = new Debugger();
|
||||
|
||||
var g1 = newGlobal();
|
||||
var dg1 = dbg.addDebuggee(g1);
|
||||
|
||||
var g2 = newGlobal();
|
||||
var dg2 = dbg.addDebuggee(g2);
|
||||
|
||||
// Generate a Debugger.Object viewing g2 from g1's compartment.
|
||||
var dg1wg2 = dg1.makeDebuggeeValue(g2);
|
||||
assertEq(dg1wg2.global, dg1);
|
||||
assertEq(dg1wg2.unwrap(), dg2);
|
||||
assertThrowsInstanceOf(function () { dg1wg2.executeInGlobal('1'); }, TypeError);
|
||||
assertThrowsInstanceOf(function () { dg1wg2.executeInGlobalWithBindings('x', { x: 1 }); }, TypeError);
|
||||
|
||||
// These, however, should not throw.
|
||||
assertEq(dg1wg2.unwrap().executeInGlobal('1729').return, 1729);
|
||||
assertEq(dg1wg2.unwrap().executeInGlobalWithBindings('x', { x: 1729 }).return, 1729);
|
8
js/src/jit-test/tests/debug/Object-executeInGlobal-06.js
Normal file
8
js/src/jit-test/tests/debug/Object-executeInGlobal-06.js
Normal file
@ -0,0 +1,8 @@
|
||||
// Debugger.Object.prototype.executeInGlobal sets 'this' to the global.
|
||||
|
||||
var dbg = new Debugger;
|
||||
var g1 = newGlobal();
|
||||
var g1w = dbg.addDebuggee(g1);
|
||||
|
||||
assertEq(g1w.executeInGlobal('this').return, g1w);
|
||||
assertEq(g1w.executeInGlobalWithBindings('this', { x:42 }).return, g1w);
|
@ -1,4 +1,4 @@
|
||||
// evalInGlobal correctly handles optional custom url option
|
||||
// executeInGlobal correctly handles optional custom url option
|
||||
var g = newGlobal();
|
||||
var dbg = new Debugger(g);
|
||||
var debuggee = dbg.getDebuggees()[0];
|
||||
@ -11,7 +11,7 @@ function testUrl (options, expected) {
|
||||
assertEq(script.url, expected);
|
||||
count--;
|
||||
};
|
||||
debuggee.evalInGlobal("", options);
|
||||
debuggee.executeInGlobal("", options);
|
||||
}
|
||||
|
||||
|
@ -1,4 +1,4 @@
|
||||
// evalInGlobal correctly handles optional lineNumber option
|
||||
// executeInGlobal correctly handles optional lineNumber option
|
||||
var g = newGlobal();
|
||||
var dbg = new Debugger(g);
|
||||
var debuggee = dbg.getDebuggees()[0];
|
||||
@ -11,7 +11,7 @@ function testLineNumber (options, expected) {
|
||||
assertEq(script.startLine, expected);
|
||||
count--;
|
||||
};
|
||||
debuggee.evalInGlobal("", options);
|
||||
debuggee.executeInGlobal("", options);
|
||||
}
|
||||
|
||||
|
9
js/src/jit-test/tests/debug/Object-executeInGlobal-09.js
Normal file
9
js/src/jit-test/tests/debug/Object-executeInGlobal-09.js
Normal file
@ -0,0 +1,9 @@
|
||||
// The frame created for executeInGlobal is never marked as a 'FUNCTION' frame.
|
||||
|
||||
(function () {
|
||||
var g = newGlobal();
|
||||
var dbg = new Debugger;
|
||||
var gw = dbg.addDebuggee(g);
|
||||
gw.executeInGlobalWithBindings("eval('Math')",{}).return
|
||||
})();
|
||||
|
13
js/src/jit-test/tests/debug/Object-executeInGlobal-10.js
Normal file
13
js/src/jit-test/tests/debug/Object-executeInGlobal-10.js
Normal file
@ -0,0 +1,13 @@
|
||||
var g = newGlobal();
|
||||
var dbg = new Debugger;
|
||||
var gw = dbg.addDebuggee(g);
|
||||
|
||||
// executeInGlobal should be able to introduce and persist lexical bindings.
|
||||
assertEq(gw.executeInGlobal(`let x = 42; x;`).return, 42);
|
||||
assertEq(gw.executeInGlobal(`x;`).return, 42);
|
||||
|
||||
// By contrast, Debugger.Frame.eval is like direct eval, and shouldn't be able
|
||||
// to introduce new lexical bindings.
|
||||
dbg.onDebuggerStatement = function (frame) { frame.eval(`let y = 84;`); };
|
||||
g.eval(`debugger;`);
|
||||
assertEq(!!gw.executeInGlobal(`y;`).throw, true);
|
@ -1,8 +1,8 @@
|
||||
// obj.getOwnPropertyDescriptor works on global objects.
|
||||
|
||||
var g = newGlobal();
|
||||
g.eval("var v; const k = 42;");
|
||||
this.eval("var v; const k = 42;");
|
||||
g.eval("var v;");
|
||||
this.eval("var v;");
|
||||
|
||||
var dbg = Debugger();
|
||||
var obj = dbg.addDebuggee(g);
|
||||
@ -20,4 +20,3 @@ function test(name) {
|
||||
|
||||
test("Infinity");
|
||||
test("v");
|
||||
test("k");
|
||||
|
@ -7,7 +7,7 @@ var hits = 0;
|
||||
|
||||
function checkIsArrow(shouldBe, expr) {
|
||||
print(expr);
|
||||
assertEq(gDO.evalInGlobal(expr).return.isArrowFunction, shouldBe);
|
||||
assertEq(gDO.executeInGlobal(expr).return.isArrowFunction, shouldBe);
|
||||
}
|
||||
|
||||
checkIsArrow(true, '() => { }');
|
||||
|
@ -87,7 +87,7 @@ dbg.onDebuggerStatement = function (frame) {
|
||||
introducer = frame.script;
|
||||
};
|
||||
log = '';
|
||||
var fDO = gDO.evalInGlobal('debugger; Function("origami;")', { lineNumber: 1685 }).return;
|
||||
var fDO = gDO.executeInGlobal('debugger; Function("origami;")', { lineNumber: 1685 }).return;
|
||||
var source = fDO.script.source;
|
||||
assertEq(log, 'F2');
|
||||
assertEq(source.introductionScript, introducer);
|
||||
|
@ -100,21 +100,21 @@ log = '';
|
||||
g.eval('debugger;');
|
||||
assertEq(log, 'oi');
|
||||
|
||||
// Debugger.Object.evalInGlobal
|
||||
// Debugger.Object.executeInGlobal
|
||||
dbg.onDebuggerStatement = function (frame) {
|
||||
log += 'd';
|
||||
assertEq(frame.script.source.introductionType, "debugger eval");
|
||||
};
|
||||
log = '';
|
||||
gDO.evalInGlobal('debugger;');
|
||||
gDO.executeInGlobal('debugger;');
|
||||
assertEq(log, 'd');
|
||||
|
||||
// Debugger.Object.evalInGlobalWithBindings
|
||||
// Debugger.Object.executeInGlobalWithBindings
|
||||
dbg.onDebuggerStatement = function (frame) {
|
||||
log += 'd';
|
||||
assertEq(frame.script.source.introductionType, "debugger eval");
|
||||
};
|
||||
log = '';
|
||||
gDO.evalInGlobalWithBindings('debugger;', { x: 42 });
|
||||
gDO.executeInGlobalWithBindings('debugger;', { x: 42 });
|
||||
assertEq(log, 'd');
|
||||
|
||||
|
@ -2,6 +2,6 @@ var g = newGlobal();
|
||||
var dbg = new Debugger();
|
||||
var gw = dbg.addDebuggee(g);
|
||||
dbg.onDebuggerStatement = function (f) {
|
||||
gw.evalInGlobal("eval('var x = \"A Brief History of Love\"');\n")
|
||||
gw.executeInGlobal("eval('var x = \"A Brief History of Love\"');\n")
|
||||
};
|
||||
g.eval('debugger');
|
||||
|
@ -361,7 +361,7 @@ jit::CanEnterBaselineMethod(JSContext* cx, RunState& state)
|
||||
} else {
|
||||
MOZ_ASSERT(state.isExecute());
|
||||
ExecuteType type = state.asExecute()->type();
|
||||
if (type == EXECUTE_DEBUG || type == EXECUTE_DEBUG_GLOBAL) {
|
||||
if (type == EXECUTE_DEBUG) {
|
||||
JitSpew(JitSpew_BaselineAbort, "debugger frame");
|
||||
return Method_CantCompile;
|
||||
}
|
||||
|
@ -3375,11 +3375,9 @@ IsFunctionCloneable(HandleFunction fun, HandleObject dynamicScope)
|
||||
|
||||
// If the script is an indirect eval that is immediately scoped under
|
||||
// the global, we can clone it.
|
||||
if (scope->is<StaticEvalObject>() &&
|
||||
!scope->as<StaticEvalObject>().isDirect() &&
|
||||
!scope->as<StaticEvalObject>().isStrict())
|
||||
{
|
||||
return true;
|
||||
if (scope->is<StaticBlockObject>()) {
|
||||
if (StaticEvalObject* staticEval = scope->as<StaticBlockObject>().maybeEnclosingEval())
|
||||
return !staticEval->isDirect();
|
||||
}
|
||||
|
||||
// Any other enclosing static scope (e.g., function, block) cannot be
|
||||
|
@ -2842,7 +2842,7 @@ JSScript::fullyInitFromEmitter(ExclusiveContext* cx, HandleScript script, Byteco
|
||||
if (bce->tryNoteList.length() != 0)
|
||||
bce->tryNoteList.finish(script->trynotes());
|
||||
if (bce->blockScopeList.length() != 0)
|
||||
bce->blockScopeList.finish(script->blockScopes());
|
||||
bce->blockScopeList.finish(script->blockScopes(), prologueLength);
|
||||
script->strict_ = bce->sc->strict();
|
||||
script->explicitUseStrict_ = bce->sc->hasExplicitUseStrict();
|
||||
script->bindingsAccessedDynamically_ = bce->sc->bindingsAccessedDynamically();
|
||||
@ -3772,10 +3772,7 @@ JSScript::getStaticBlockScope(jsbytecode* pc)
|
||||
if (!hasBlockScopes())
|
||||
return nullptr;
|
||||
|
||||
if (pc < main())
|
||||
return nullptr;
|
||||
|
||||
size_t offset = pc - main();
|
||||
size_t offset = pc - code();
|
||||
|
||||
BlockScopeArray* scopes = blockScopes();
|
||||
NestedScopeObject* blockChain = nullptr;
|
||||
|
@ -1,3 +1,8 @@
|
||||
// |reftest| skip-if(!xulRuntime.shell)
|
||||
//
|
||||
// The above skip-if is because global lexicals aren't yet implemented. Remove
|
||||
// that and the |evaluate| call below once they are.
|
||||
//
|
||||
// A class statement creates a mutable lexical outer binding.
|
||||
|
||||
var test = `
|
||||
@ -13,8 +18,6 @@ assertEq(Foo, 5);
|
||||
assertEq(foo, 4);
|
||||
}
|
||||
|
||||
var ieval = eval;
|
||||
|
||||
{
|
||||
class PermanentBinding { constructor() { } }
|
||||
delete PermanentBinding;
|
||||
@ -24,10 +27,10 @@ var ieval = eval;
|
||||
|
||||
{
|
||||
try {
|
||||
ieval(\`class x { constructor () { } }
|
||||
throw new Error("FAIL");
|
||||
class y { constructor () { } }
|
||||
\`);
|
||||
evaluate(\`class x { constructor () { } }
|
||||
throw new Error("FAIL");
|
||||
class y { constructor () { } }
|
||||
\`);
|
||||
} catch (e if e instanceof Error) { }
|
||||
assertEq(typeof x, "function");
|
||||
assertEq(y, undefined, "Congrats, you fixed top-level lexical scoping! " +
|
||||
|
@ -0,0 +1,45 @@
|
||||
/*
|
||||
* Any copyright is dedicated to the Public Domain.
|
||||
* http://creativecommons.org/licenses/publicdomain/
|
||||
*/
|
||||
|
||||
var gTestfile = "eval-has-lexical-environment.js"
|
||||
//-----------------------------------------------------------------------------
|
||||
var BUGNUMBER = 1193583;
|
||||
var summary =
|
||||
"Eval always has a lexical environment";
|
||||
|
||||
/**************
|
||||
* BEGIN TEST *
|
||||
**************/
|
||||
|
||||
eval(`
|
||||
let foo = 42;
|
||||
const kay = foo;
|
||||
var bar = 84;
|
||||
function f() {
|
||||
return foo + kay;
|
||||
}
|
||||
`);
|
||||
|
||||
(1, eval)(`
|
||||
let foo2 = 42;
|
||||
const kay2 = foo2;
|
||||
`);
|
||||
|
||||
// Lexical declarations should not have escaped eval.
|
||||
assertEq(typeof foo, "undefined");
|
||||
assertEq(typeof kay, "undefined");
|
||||
assertEq(typeof foo2, "undefined");
|
||||
assertEq(typeof kay2, "undefined");
|
||||
|
||||
// Eval'd functions can close over lexical bindings.
|
||||
assertEq(f(), 84);
|
||||
|
||||
// Var can escape direct eval.
|
||||
assertEq(bar, 84);
|
||||
|
||||
if (typeof reportCompare === "function")
|
||||
reportCompare(true, true);
|
||||
|
||||
print("Tests complete");
|
@ -1,4 +1,4 @@
|
||||
// |reftest| fails-if(Function("try{Function('let\x20x=5;');return(1,eval)('let\x20x=3;\\'x\\'\x20in\x20this');}catch(e){return(true);}")()) -- needs bug 589199 fix (top-level let not same as var); please convert AssertEq to assertEq when removing this fails-if, too
|
||||
// |reftest| fails-if(Function("try{Function('let\x20x=5;');return(evaluate)('let\x20x=3;\\'x\\'\x20in\x20this');}catch(e){return(true);}")()) -- needs bug 589199 fix (top-level let not same as var); please convert AssertEq to assertEq when removing this fails-if, too
|
||||
// Any copyright is dedicated to the Public Domain.
|
||||
// http://creativecommons.org/licenses/publicdomain/
|
||||
|
||||
|
@ -1,134 +0,0 @@
|
||||
/* -*- indent-tabs-mode: nil; js-indent-level: 2 -*- */
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
/*
|
||||
*
|
||||
* Date: 10 Jan 2002
|
||||
* SUMMARY: Reassignment to a const is NOT an error per ECMA
|
||||
* See http://bugzilla.mozilla.org/show_bug.cgi?id=103602
|
||||
*
|
||||
* ------- Additional Comment #4 From Brendan Eich 2002-01-10 15:30 -------
|
||||
*
|
||||
* That's per ECMA (don't blame me, I fought for what Netscape always did:
|
||||
* throw an error [could be a catchable exception since 1.3]).
|
||||
* Readonly properties, when set by assignment, are not changed, but no error
|
||||
* or exception is thrown. The value of the assignment expression is the value
|
||||
* of the r.h.s.
|
||||
*
|
||||
* If you want a *strict* warning, pls change the summary of this bug
|
||||
* to say so.
|
||||
*/
|
||||
//-----------------------------------------------------------------------------
|
||||
var UBound = 0;
|
||||
var BUGNUMBER = 103602;
|
||||
var summary = 'Reassignment to a const is NOT an error per ECMA';
|
||||
var status = '';
|
||||
var statusitems = [];
|
||||
var actual = '';
|
||||
var actualvalues = [];
|
||||
var expect= '';
|
||||
var expectedvalues = [];
|
||||
var cnFAIL_1 = 'Redeclaration of a const FAILED to cause an error';
|
||||
var cnFAIL_2 = 'Reassigning to a const caused an ERROR! It should not!!!';
|
||||
var sEval = '';
|
||||
|
||||
/*
|
||||
* Not every implementation supports const (a non-ECMA extension)
|
||||
* For example, Rhino does not; it would generate a complile-time error.
|
||||
* So we have to hide this so it will be detected at run-time instead.
|
||||
*/
|
||||
try
|
||||
{
|
||||
sEval = 'const one = 1';
|
||||
eval(sEval);
|
||||
}
|
||||
catch(e)
|
||||
{
|
||||
quit(); // if const is not supported, this testcase is over -
|
||||
}
|
||||
|
||||
|
||||
status = inSection(1);
|
||||
try
|
||||
{
|
||||
/*
|
||||
* Redeclaration of const should be a compile-time error.
|
||||
* Hide so it will be detected at run-time.
|
||||
*/
|
||||
sEval = 'const one = 2;';
|
||||
eval(sEval);
|
||||
|
||||
expect = ''; // we shouldn't reach this line
|
||||
actual = cnFAIL_1;
|
||||
addThis();
|
||||
}
|
||||
catch(e)
|
||||
{
|
||||
// good - we should be here.
|
||||
actual = expect;
|
||||
addThis();
|
||||
}
|
||||
|
||||
|
||||
status = inSection(2);
|
||||
try
|
||||
{
|
||||
/*
|
||||
* Reassignment to a const should be NOT be an error, per ECMA.
|
||||
*/
|
||||
one = 2;
|
||||
actual = expect; // good: no error was generated
|
||||
addThis();
|
||||
|
||||
// although no error, the assignment should have been ignored -
|
||||
status = inSection(3);
|
||||
actual = one;
|
||||
expect = 1;
|
||||
addThis();
|
||||
|
||||
// the value of the EXPRESSION, however, is the value of the r.h.s. -
|
||||
status = inSection(4);
|
||||
actual = (one = 2);
|
||||
expect = 2;
|
||||
addThis();
|
||||
}
|
||||
|
||||
catch(e)
|
||||
{
|
||||
// BAD - we shouldn't be here
|
||||
expect = '';
|
||||
actual = cnFAIL_2;
|
||||
addThis();
|
||||
}
|
||||
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
test();
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
|
||||
function addThis()
|
||||
{
|
||||
statusitems[UBound] = status;
|
||||
actualvalues[UBound] = actual;
|
||||
expectedvalues[UBound] = expect;
|
||||
UBound++;
|
||||
}
|
||||
|
||||
|
||||
function test()
|
||||
{
|
||||
enterFunc ('test');
|
||||
printBugNumber(BUGNUMBER);
|
||||
printStatus (summary);
|
||||
|
||||
for (var i = 0; i < UBound; i++)
|
||||
{
|
||||
reportCompare(expectedvalues[i], actualvalues[i], statusitems[i]);
|
||||
}
|
||||
|
||||
exitFunc ('test');
|
||||
}
|
@ -1,37 +0,0 @@
|
||||
/* -*- indent-tabs-mode: nil; js-indent-level: 2 -*- */
|
||||
/*
|
||||
* Any copyright is dedicated to the Public Domain.
|
||||
* http://creativecommons.org/licenses/publicdomain/
|
||||
* Contributor: Jason Orendorff
|
||||
*/
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
var BUGNUMBER = 452498;
|
||||
var summary = 'TM: upvar2 regression tests';
|
||||
var actual = '';
|
||||
var expect = '';
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
test();
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
function test()
|
||||
{
|
||||
enterFunc ('test');
|
||||
printBugNumber(BUGNUMBER);
|
||||
printStatus (summary);
|
||||
|
||||
|
||||
// ------- Comment #54 From Jason Orendorff
|
||||
|
||||
// Assertion failure: cg->flags & TCF_IN_FUNCTION
|
||||
// at ../jsemit.cpp:1991
|
||||
//
|
||||
function f() { var x; eval("let x, x;"); }
|
||||
f();
|
||||
|
||||
reportCompare(expect, actual, summary);
|
||||
|
||||
exitFunc ('test');
|
||||
}
|
@ -24,7 +24,7 @@ try {
|
||||
|
||||
assertEq(actual, expect);
|
||||
|
||||
s += s.slice(0, -2);
|
||||
s += s.slice(0, -4);
|
||||
|
||||
try {
|
||||
eval(s);
|
||||
|
@ -6344,9 +6344,21 @@ EvaluateInEnv(JSContext* cx, Handle<Env*> env, HandleValue thisv, AbstractFrameP
|
||||
Rooted<ScopeObject*> enclosingStaticScope(cx);
|
||||
if (!env->is<GlobalObject>())
|
||||
enclosingStaticScope = StaticNonSyntacticScopeObjects::create(cx, nullptr);
|
||||
Rooted<StaticEvalObject*> staticScope(cx, StaticEvalObject::create(cx, enclosingStaticScope));
|
||||
if (!staticScope)
|
||||
return false;
|
||||
|
||||
// Do not consider executeInGlobal{WithBindings} as an eval, but instead
|
||||
// as executing a series of statements at the global level. This is to
|
||||
// circumvent the fresh lexical scope that all eval have, so that the
|
||||
// users of executeInGlobal, like the web console, may add new bindings to
|
||||
// the global scope.
|
||||
Rooted<ScopeObject*> staticScope(cx);
|
||||
if (frame) {
|
||||
staticScope = StaticEvalObject::create(cx, enclosingStaticScope);
|
||||
if (!staticScope)
|
||||
return false;
|
||||
} else {
|
||||
staticScope = enclosingStaticScope;
|
||||
}
|
||||
|
||||
CompileOptions options(cx);
|
||||
options.setIsRunOnce(true)
|
||||
.setForEval(true)
|
||||
@ -6363,11 +6375,14 @@ EvaluateInEnv(JSContext* cx, Handle<Env*> env, HandleValue thisv, AbstractFrameP
|
||||
if (!script)
|
||||
return false;
|
||||
|
||||
if (script->strict())
|
||||
staticScope->setStrict();
|
||||
// Again, executeInGlobal is not considered eval.
|
||||
if (frame) {
|
||||
if (script->strict())
|
||||
staticScope->as<StaticEvalObject>().setStrict();
|
||||
script->setActiveEval();
|
||||
}
|
||||
|
||||
script->setActiveEval();
|
||||
ExecuteType type = !frame ? EXECUTE_DEBUG_GLOBAL : EXECUTE_DEBUG;
|
||||
ExecuteType type = !frame ? EXECUTE_GLOBAL : EXECUTE_DEBUG;
|
||||
return ExecuteKernel(cx, script, *env, thisv, NullValue(), type, frame, rval.address());
|
||||
}
|
||||
|
||||
@ -7419,29 +7434,30 @@ RequireGlobalObject(JSContext* cx, HandleValue dbgobj, HandleObject referent)
|
||||
}
|
||||
|
||||
static bool
|
||||
DebuggerObject_evalInGlobal(JSContext* cx, unsigned argc, Value* vp)
|
||||
DebuggerObject_executeInGlobal(JSContext* cx, unsigned argc, Value* vp)
|
||||
{
|
||||
THIS_DEBUGOBJECT_OWNER_REFERENT(cx, argc, vp, "evalInGlobal", args, dbg, referent);
|
||||
if (!args.requireAtLeast(cx, "Debugger.Object.prototype.evalInGlobal", 1))
|
||||
THIS_DEBUGOBJECT_OWNER_REFERENT(cx, argc, vp, "executeInGlobal", args, dbg, referent);
|
||||
if (!args.requireAtLeast(cx, "Debugger.Object.prototype.executeInGlobal", 1))
|
||||
return false;
|
||||
if (!RequireGlobalObject(cx, args.thisv(), referent))
|
||||
return false;
|
||||
|
||||
return DebuggerGenericEval(cx, "Debugger.Object.prototype.evalInGlobal",
|
||||
return DebuggerGenericEval(cx, "Debugger.Object.prototype.executeInGlobal",
|
||||
args[0], EvalWithDefaultBindings, JS::UndefinedHandleValue,
|
||||
args.get(1), args.rval(), dbg, referent, nullptr);
|
||||
}
|
||||
|
||||
static bool
|
||||
DebuggerObject_evalInGlobalWithBindings(JSContext* cx, unsigned argc, Value* vp)
|
||||
DebuggerObject_executeInGlobalWithBindings(JSContext* cx, unsigned argc, Value* vp)
|
||||
{
|
||||
THIS_DEBUGOBJECT_OWNER_REFERENT(cx, argc, vp, "evalInGlobalWithBindings", args, dbg, referent);
|
||||
if (!args.requireAtLeast(cx, "Debugger.Object.prototype.evalInGlobalWithBindings", 2))
|
||||
THIS_DEBUGOBJECT_OWNER_REFERENT(cx, argc, vp, "executeInGlobalWithBindings", args, dbg,
|
||||
referent);
|
||||
if (!args.requireAtLeast(cx, "Debugger.Object.prototype.executeInGlobalWithBindings", 2))
|
||||
return false;
|
||||
if (!RequireGlobalObject(cx, args.thisv(), referent))
|
||||
return false;
|
||||
|
||||
return DebuggerGenericEval(cx, "Debugger.Object.prototype.evalInGlobalWithBindings",
|
||||
return DebuggerGenericEval(cx, "Debugger.Object.prototype.executeInGlobalWithBindings",
|
||||
args[0], EvalHasExtraBindings, args[1], args.get(2),
|
||||
args.rval(), dbg, referent, nullptr);
|
||||
}
|
||||
@ -7521,8 +7537,8 @@ static const JSFunctionSpec DebuggerObject_methods[] = {
|
||||
JS_FN("apply", DebuggerObject_apply, 0, 0),
|
||||
JS_FN("call", DebuggerObject_call, 0, 0),
|
||||
JS_FN("makeDebuggeeValue", DebuggerObject_makeDebuggeeValue, 1, 0),
|
||||
JS_FN("evalInGlobal", DebuggerObject_evalInGlobal, 1, 0),
|
||||
JS_FN("evalInGlobalWithBindings", DebuggerObject_evalInGlobalWithBindings, 2, 0),
|
||||
JS_FN("executeInGlobal", DebuggerObject_executeInGlobal, 1, 0),
|
||||
JS_FN("executeInGlobalWithBindings", DebuggerObject_executeInGlobalWithBindings, 2, 0),
|
||||
JS_FN("unwrap", DebuggerObject_unwrap, 0, 0),
|
||||
JS_FN("unsafeDereference", DebuggerObject_unsafeDereference, 0, 0),
|
||||
JS_FS_END
|
||||
|
@ -438,6 +438,7 @@ class StaticEvalObject : public ScopeObject
|
||||
// Indirect evals terminate in the global at run time, and has no static
|
||||
// enclosing scope.
|
||||
bool isDirect() const {
|
||||
MOZ_ASSERT_IF(!getReservedSlot(SCOPE_CHAIN_SLOT).isObject(), !isStrict());
|
||||
return getReservedSlot(SCOPE_CHAIN_SLOT).isObject();
|
||||
}
|
||||
};
|
||||
@ -643,6 +644,14 @@ class StaticBlockObject : public BlockObject
|
||||
*/
|
||||
inline StaticBlockObject* enclosingBlock() const;
|
||||
|
||||
StaticEvalObject* maybeEnclosingEval() const {
|
||||
if (JSObject* enclosing = enclosingStaticScope()) {
|
||||
if (enclosing->is<StaticEvalObject>())
|
||||
return &enclosing->as<StaticEvalObject>();
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
uint32_t localOffset() {
|
||||
return getReservedSlot(LOCAL_OFFSET_SLOT).toPrivateUint32();
|
||||
}
|
||||
|
@ -253,20 +253,6 @@ InterpreterFrame::epilogue(JSContext* cx)
|
||||
DebugScopes::onPopStrictEvalScope(this);
|
||||
} else if (isDirectEvalFrame()) {
|
||||
MOZ_ASSERT_IF(isDebuggerEvalFrame(), !IsSyntacticScope(scopeChain()));
|
||||
} else {
|
||||
/*
|
||||
* Debugger.Object.prototype.evalInGlobal creates indirect eval
|
||||
* frames scoped to the given global;
|
||||
* Debugger.Object.prototype.evalInGlobalWithBindings creates
|
||||
* indirect eval frames scoped to an object carrying the introduced
|
||||
* bindings.
|
||||
*/
|
||||
if (isDebuggerEvalFrame()) {
|
||||
MOZ_ASSERT(scopeChain()->is<GlobalObject>() ||
|
||||
scopeChain()->enclosingScope()->is<GlobalObject>());
|
||||
} else {
|
||||
MOZ_ASSERT(scopeChain()->is<GlobalObject>());
|
||||
}
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
@ -283,8 +283,7 @@ enum ExecuteType {
|
||||
EXECUTE_MODULE = 0x4, /* == InterpreterFrame::GLOBAL */
|
||||
EXECUTE_DIRECT_EVAL = 0x8, /* == InterpreterFrame::EVAL */
|
||||
EXECUTE_INDIRECT_EVAL = 0x9, /* == InterpreterFrame::GLOBAL | EVAL */
|
||||
EXECUTE_DEBUG = 0x18, /* == InterpreterFrame::EVAL | DEBUGGER */
|
||||
EXECUTE_DEBUG_GLOBAL = 0x19 /* == InterpreterFrame::EVAL | DEBUGGER | GLOBAL */
|
||||
EXECUTE_DEBUG = 0x18, /* == InterpreterFrame::EVAL | DEBUGGER_EVAL */
|
||||
};
|
||||
|
||||
/*****************************************************************************/
|
||||
|
@ -85,7 +85,7 @@ https://bugzilla.mozilla.org/show_bug.cgi?id=937317
|
||||
// The incumbent script override doesn't take effect if the callback is scripted.
|
||||
let d = Promise.defer();
|
||||
iwin.wrappedJSObject.timeoutFun2 = Cu.getIncumbentGlobal.bind(Cu, makeCallback(iwin, d, "cross-global setTimeout of scripted function"));
|
||||
iwin.eval('let timeoutFun2Wrapper = function() { timeoutFun2(); }');
|
||||
iwin.eval('var timeoutFun2Wrapper = function() { timeoutFun2(); }');
|
||||
setTimeout(iwin.wrappedJSObject.timeoutFun2Wrapper, 0);
|
||||
return d.promise;
|
||||
}).then(function() {
|
||||
|
@ -31,8 +31,8 @@ function run_test() {
|
||||
|
||||
debuggeree.eval(
|
||||
`
|
||||
const dbg = new Debugger(this.debuggee);
|
||||
let fired = 0;
|
||||
var dbg = new Debugger(this.debuggee);
|
||||
var fired = 0;
|
||||
dbg.memory.onGarbageCollection = _ => {
|
||||
fired++;
|
||||
gc(this);
|
||||
|
@ -166,8 +166,7 @@ public:
|
||||
|
||||
nsDocViewerSelectionListener()
|
||||
: mDocViewer(nullptr)
|
||||
, mGotSelectionState(false)
|
||||
, mSelectionWasCollapsed(false)
|
||||
, mSelectionWasCollapsed(true)
|
||||
{
|
||||
}
|
||||
|
||||
@ -177,8 +176,7 @@ protected:
|
||||
|
||||
virtual ~nsDocViewerSelectionListener() {}
|
||||
|
||||
nsDocumentViewer* mDocViewer;
|
||||
bool mGotSelectionState;
|
||||
nsDocumentViewer* mDocViewer;
|
||||
bool mSelectionWasCollapsed;
|
||||
|
||||
};
|
||||
@ -3572,13 +3570,13 @@ NS_IMETHODIMP nsDocViewerSelectionListener::NotifySelectionChanged(nsIDOMDocumen
|
||||
|
||||
bool selectionCollapsed;
|
||||
selection->GetIsCollapsed(&selectionCollapsed);
|
||||
// we only call UpdateCommands when the selection changes from collapsed
|
||||
// to non-collapsed or vice versa. We might need another update string
|
||||
// for simple selection changes, but that would be expenseive.
|
||||
if (!mGotSelectionState || mSelectionWasCollapsed != selectionCollapsed)
|
||||
// We only call UpdateCommands when the selection changes from collapsed to
|
||||
// non-collapsed or vice versa, however we skip the initializing collapse. We
|
||||
// might need another update string for simple selection changes, but that
|
||||
// would be expenseive.
|
||||
if (mSelectionWasCollapsed != selectionCollapsed)
|
||||
{
|
||||
domWindow->UpdateCommands(NS_LITERAL_STRING("select"), selection, aReason);
|
||||
mGotSelectionState = true;
|
||||
mSelectionWasCollapsed = selectionCollapsed;
|
||||
}
|
||||
|
||||
|
@ -147,6 +147,6 @@ fuzzy-if(d2d,47,400) == linear-onestopposition-1.html linear-onestopposition-1-r
|
||||
== repeating-radial-onestopposition-1c.html orange-square.html
|
||||
== bug-916535-background-repeat-linear.html bug-916535-background-repeat-linear-ref.html
|
||||
fuzzy(1,800000) == large-gradient-1.html large-gradient-1-ref.html
|
||||
== large-gradient-2.html large-gradient-2-ref.html
|
||||
fuzzy-if(Android,4,1) == large-gradient-2.html large-gradient-2-ref.html # Bug 1182082
|
||||
fails-if(browserIsRemote&&!B2G) fuzzy-if(!browserIsRemote||B2G,1,800000) == large-gradient-3.html large-gradient-3-ref.html
|
||||
== large-gradient-4.html large-gradient-4-ref.html
|
||||
|
@ -1,4 +1,4 @@
|
||||
skip-if(B2G||Mulet) == mq_print_height.xhtml mq_print-ref.xhtml # bug 773482 # Initial mulet triage: parity with B2G/B2G Desktop
|
||||
fuzzy-if(Android,8,454) skip-if(B2G||Mulet) == mq_print_height.xhtml mq_print-ref.xhtml # bug 773482 # Initial mulet triage: parity with B2G/B2G Desktop, bug 1178697
|
||||
skip-if(B2G||Mulet) == mq_print_deviceheight.xhtml mq_print-ref.xhtml # bug 773482 # Initial mulet triage: parity with B2G/B2G Desktop
|
||||
skip-if(B2G||Mulet) == mq_print_width.xhtml mq_print-ref.xhtml # bug 773482 # Initial mulet triage: parity with B2G/B2G Desktop
|
||||
skip-if(B2G||Mulet) == mq_print_minwidth.xhtml mq_print-ref.xhtml # bug 773482 # Initial mulet triage: parity with B2G/B2G Desktop
|
||||
|
@ -7,4 +7,4 @@
|
||||
== box-sizing-content-box-003.xht box-sizing-content-box-003-ref.xht
|
||||
random-if(Android) skip-if((B2G&&browserIsRemote)||Mulet) == box-sizing-replaced-001.xht box-sizing-replaced-001-ref.xht #bug 982547 # Initial mulet triage: parity with B2G/B2G Desktop
|
||||
fuzzy-if(Android,27,874) random-if((B2G&&browserIsRemote)||Mulet) == box-sizing-replaced-002.xht box-sizing-replaced-002-ref.xht # Bug 1128229 # Initial mulet triage: parity with B2G/B2G Desktop
|
||||
fuzzy-if(Android,27,869) random-if((B2G&&browserIsRemote)||Mulet) == box-sizing-replaced-003.xht box-sizing-replaced-003-ref.xht # Bug 1128229 # Initial mulet triage: parity with B2G/B2G Desktop
|
||||
fuzzy-if(Android,27,925) random-if((B2G&&browserIsRemote)||Mulet) == box-sizing-replaced-003.xht box-sizing-replaced-003-ref.xht # Bug 1128229 # Initial mulet triage: parity with B2G/B2G Desktop
|
||||
|
@ -1,5 +0,0 @@
|
||||
[WorkerGlobalScope_importScripts_NetworkErr.htm]
|
||||
type: testharness
|
||||
[ importScripts() with non-existent script file ]
|
||||
expected: FAIL
|
||||
|
@ -1,5 +0,0 @@
|
||||
[uncontrolled-page.https.html]
|
||||
type: testharness
|
||||
[Fetch events should not go through uncontrolled page.]
|
||||
expected: FAIL
|
||||
|
@ -26,7 +26,7 @@ async_test(function(t) {
|
||||
return wait_for_state(t, reg.installing, 'activated');
|
||||
})
|
||||
.then(function() {
|
||||
return fetch_url('/service-worker/resources/simple.txt');
|
||||
return fetch_url('resources/simple.txt');
|
||||
})
|
||||
.then(function(text) {
|
||||
assert_equals(text, 'a simple text file\n');
|
||||
|
@ -975,7 +975,7 @@ function run_float_tests(library, t, name, size) {
|
||||
function test_roundtrip(t, val)
|
||||
{
|
||||
let f1 = t(val);
|
||||
eval("let f2 = " + f1.toSource());
|
||||
eval("var f2 = " + f1.toSource());
|
||||
do_check_eq(f1.value, f2.value);
|
||||
}
|
||||
vals = [Infinity, -Infinity, -0, 0, 1, -1, 1/3, -1/3, 1/4, -1/4,
|
||||
@ -1582,7 +1582,7 @@ function run_StructType_tests() {
|
||||
|
||||
do_check_eq(s.toSource(), "s_t(4, {\"a\": 7, \"b\": 2}, 10)");
|
||||
do_check_eq(s.toSource(), s.toString());
|
||||
eval("let s2 = " + s.toSource());
|
||||
eval("var s2 = " + s.toSource());
|
||||
do_check_true(s2.constructor === s_t);
|
||||
do_check_eq(s.b.b, s2.b.b);
|
||||
|
||||
@ -2060,7 +2060,7 @@ function run_ArrayType_tests() {
|
||||
c.value = [1, 2, 3, 4, 5, 6];
|
||||
do_check_eq(c.toSource(), "ctypes.int32_t.array(6)([1, 2, 3, 4, 5, 6])");
|
||||
do_check_eq(c.toSource(), c.toString());
|
||||
eval("let c2 = " + c.toSource());
|
||||
eval("var c2 = " + c.toSource());
|
||||
do_check_eq(c2.constructor.name, "int32_t[6]");
|
||||
do_check_eq(c2.length, 6);
|
||||
do_check_eq(c2[3], c[3]);
|
||||
|
@ -1060,7 +1060,7 @@ WebConsoleActor.prototype =
|
||||
* provide the "bindObjectActor" mechanism: the Web Console tells the
|
||||
* ObjectActor ID for which it desires to evaluate an expression. The
|
||||
* Debugger.Object pointed at by the actor ID is bound such that it is
|
||||
* available during expression evaluation (evalInGlobalWithBindings()).
|
||||
* available during expression evaluation (executeInGlobalWithBindings()).
|
||||
*
|
||||
* Example:
|
||||
* _self['foobar'] = 'test'
|
||||
@ -1218,7 +1218,7 @@ WebConsoleActor.prototype =
|
||||
result = frame.evalWithBindings(aString, bindings, evalOptions);
|
||||
}
|
||||
else {
|
||||
result = dbgWindow.evalInGlobalWithBindings(aString, bindings, evalOptions);
|
||||
result = dbgWindow.executeInGlobalWithBindings(aString, bindings, evalOptions);
|
||||
}
|
||||
|
||||
let helperResult = helpers.helperResult;
|
||||
|
@ -37,7 +37,7 @@ skip-if = buildapp == 'mulet'
|
||||
[test_director.html]
|
||||
[test_director_connectToChild.html]
|
||||
skip-if = buildapp == 'mulet'
|
||||
[test_evalInGlobal-outerized_this.html]
|
||||
[test_executeInGlobal-outerized_this.html]
|
||||
[test_framerate_01.html]
|
||||
skip-if = buildapp == 'mulet'
|
||||
[test_framerate_02.html]
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user